Docker学习笔记(高阶篇)一
一、Docker Dockerfile
Docker Dockerfile是一个文本文件,包含了一系列的指令和参数,用于自动化构建Docker镜像。每条指令都构建镜像的一层,每一层都代表了镜像构建过程中的一个步骤。该层包含了该指令执行后的所有更改,这些层最终会叠加起来形成最终的镜像。
镜像层的工作原理
假设我们有一个非常基础的Dockerfile:
FROM ubuntu:18.04
RUN apt-get update && apt-get install -y nginx
COPY . /var/www/html
这个Dockerfile包含了三条指令,每条指令对应镜像的一层:
- FROM ubuntu:18.04:这是基础镜像层,所有后续的操作都基于这个Ubuntu 18.04的镜像。
- RUN apt-get update && apt-get install -y nginx:这一条指令创建了第二层。这层在Ubuntu 18.04的基础上,更新了软件包列表并安装了nginx。这一层只包含了由于安装nginx而产生的改变。
- COPY . /var/www/html:这一条指令创建了第三层。它把宿主机当前目录下的文件复制到了镜像的/var/www/html目录中。这层包含了由于复制文件操作产生的所有改变。
层的重用和缓存
当Dockerfile被重新构建时,如果FROM指令指定的基础镜像没有变化,且RUN指令执行的安装命令没有变化,那么Docker会使用缓存的镜像层,而不是重新创建。这大大加快了构建过程。
但是如果你修改了COPY指令复制的文件内容(哪怕是一个小小的改变),Docker需要重新执行这条指令以及所有后续的指令,因为这会影响到/var/www/html目录的内容,从而影响到这一层以及所有基于这一层的后续层。
层的效率
Docker镜像的这种分层结构,使得镜像的分发非常高效。如果多个镜像都是基于相同的Ubuntu 18.04基础镜像,那么这个基础镜像只需要在一个节点上存储和缓存一次,不同的镜像只需存储它们自己特有的层。
二、Dockerfile常用指令
截止到发文当天,Dockerfile支持18个常用字的保留指令:
1.FROM:指定基础镜像。所有Dockerfile都必须以FROM指令开始,指定一个已存在的镜像作为构建新镜像的基础:
FROM ubuntu:18.04
2.RUN:在镜像中运行命令。用于安装软件包或执行其它配置任务:
RUN apt-get update && apt-get install -y python3
3.CMD:提供容器默认执行的命令。Dockerfile中只能有一个CMD指令。如果定义了多个,只有最后一个会被执行:
CMD ["python3", "./app.py"]
4.COPY:将主机的文件或目录复制到镜像中。常用于复制源代码到镜像内:
COPY . /app
5.ADD:与COPY类似,但是它还支持远程URL和自动解压压缩文件的功能:
ADD https://example.com/big.tar.gz /var/www/html/
6.EXPOSE:声明容器运行时监听的端口:
EXPOSE 80
7.ENV:设置环境变量:
ENV MYSQL_ROOT_PASSWORD password
ENV MYSQL_DATABASE my_database
ENV MYSQL_USER my_user
ENV MYSQL_PASSWORD my_password
8.ENTRYPOINT:配置容器启动时运行的命令,与CMD配合使用,可以让容器以应用程序或服务的形式运行:
ENTRYPOINT ["python3"]
CMD ["app.py"]
当你的dockerfile文件编辑好后,切换到dockerfile文件所在目录下构建镜像:
docker build -t your-image-name:tag .
使用docker run -d
命令来运行该镜像即可。
二、Docker Compose
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
使用Compose的步骤
- 编写Dockerfile:这是创建自定义Docker镜像的步骤,你会在这个文件中定义基础镜像、安装必要的软件包、配置环境、复制应用程序文件等步骤。这个步骤是为了创建一个能够满足你特定需求的镜像。
- 编写
docker-compose.yml
文件:在这个文件中,定义你的应用所需的服务、网络和卷。这包括使用哪些镜像(无论是自定义镜像还是直接从Docker Hub拉取的镜像)、如何配置容器之间的网络、容器需要挂载哪些卷等。 - 运行
docker-compose up -d
命令:这一步会根据你在docker-compose.yml
文件中定义的配置启动和运行你的应用。-d
参数表示在后台运行容器。 - 通过
docker-compose down
进行清理:用于停止并删除根据docker-compose.yml
文件创建的所有容器,网络和默认创建的卷。
在Docker中,使用docker-compose up -d
命令时并不一定需要有一个自己创建的Dockerfile
文件。例如下面是一个基于nginx
官方镜像启动一个简单web服务器的docker-compose.yml
示例,这里并不需要Dockerfile
:
version: '3'
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
在这个示例中,image: nginx:latest
指示Docker使用已有的最新的nginx
官方镜像。因此只要你有这个docker-compose.yml
文件,就可以使用docker-compose up -d
命令来启动服务,无需自己编写Dockerfile
。
但是如果你想要构建一个自定义的镜像(例如,你有特定的环境配置或者应用程序需要包含在镜像中),那么你就需要自行创建一个Dockerfile
来指定如何构建这个镜像,并在docker-compose.yml
文件中使用build:
指令指向包含Dockerfile
的目录。
Docker Compose文件格式(docker-compose.yml
)
Compose 文件是一个YAML文件,其中定义了所有相关的服务设置。一个服务通常表示运行一个容器。服务可以包括应用的数据库、web服务、前端服务等。
Compose文件的结构大致如下:
version: '3'
services:
db:
image: postgres
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: exampledb
POSTGRES_USER: exampleuser
POSTGRES_PASSWORD: examplepass
web:
build: .
command: python app.py
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
volumes:
db-data:
在这个例子中:
db
服务使用了postgres
镜像,并定义了一个卷db-data
来持久化数据库数据。web
服务通过build: .
指令构建当前目录下的Dockerfile,并且映射了端口8000到容器的端口8000。depends_on
指令确保在启动web
服务之前数据库db
服务已经在运行。
这样定义了服务后,使用docker-compose up -d
命令就可以一起启动这两个服务。它们会在同一个网络中创建,web
服务能够通过数据库服务名称db
来访问数据库服务。
三、总结
- Dockerfile:它的作用是定义如何从一个基础镜像开始,通过一系列步骤构建出一个新的镜像。这些步骤可能包括安装软件包、设置环境变量、复制应用程序代码到镜像中等。Dockerfile关注的是镜像的创建,是构建过程的一张清单说明。
- docker-compose.yml:这个文件则用于定义和运行基于Docker的应用。它允许你用YAML格式配置应用的服务、网络和卷,这些服务可以基于你通过Dockerfile构建的镜像,也可以是直接从Docker Hub或其他Docker镜像仓库拉取的现成镜像。docker-compose.yml关注的是如何将一个或多个镜像组织成完整的应用,处理服务之间的关系、网络连接和数据存储。
所以Dockerfile
是关于构建镜像的,“怎样做”这个镜像;而 docker-compose.yml
是关于部署和管理这些镜像作为服务的,即如何把这些镜像“运作起来”,使它们共同作为一个整体服务运行。
docker Compose 虽然是官方提供的容器编排工具,但是实际生产环境是不用的,因为其局限性很大,这只适合单机多容器部署进行本地开发环境、测试环境以及小型的生产部署。但并不直接支持跨多个主机或管理一个容器集群。对于生产环境中的容器编排和集群管理,更倾向于使用像Kubernetes这样的系统。因为Kubernetes提供了更强大的功能,能够处理跨主机的容器编排、自动扩展、服务发现、负载均衡、自我修复等复杂功能,这些是Docker Compose所不具备的。