Docker踩坑指南2:Dockerfile和Docker Co
一、Dockerfile
Dockerfile 用途
Dockerfile是用来干嘛的?之前我们介绍了Docker的主要用途,用来节省配置运行环境的开销,接着讲了一大堆docker命令,但还没讲到具体该如何生成一个镜像文件。
上次我们是讲过一条命令,docker container commit
,它可以将正在运行的容器保存成镜像。然后官方提供了很多已经配置好运行环境的镜像诸如Tomcat、NodeJs、MySQL等等都有,所以只需要运行这些镜像,再把把自己的项目文件放进去,然后用commit命令生成镜像文件,接着在服务器上下载这个镜像文件并运行就可以了。
这个方法理论上虽然可行,但每修改一次项目文件,就需要手动运行镜像然后再复制文件,这实在很不方便;再加上很多时候官方提供的镜像并不一定完全满足我们的要求,我们需要做很多自定义的配置,每次都要手动进行配置,然后再coomit保存,费时间不说还容易出错。而Dockerfile就是这样产生的,它将手动的配置运行环境转换成了一条条的特殊指令,每次修改完工程之后,只需要输入docker built
命令便可以自动执行这些指令并生成镜像文件,方便又快捷。除此之外,Dockerfile 在生成镜像文件的过程中会生成很多层的缓存,重新执行docker built
时如果中间某些指令执行的时候文件系统没有发生变化,这些指令就不会重复运行,从而节省了很多时间。
Dockerfile 指令举例
在明白了它的用途之后我们就来学习最关键的部分,它有哪些指令。
首先就用我个人的一个Django(Python的一个web后端框架)项目来作为范例展示:
FROM nginx
WORKDIR /usr/src/app
COPY resources/sources.list /etc/apt/sources.list
COPY resources/pip.conf /root/.pip/pip.conf
RUN apt update && apt -y install python3 python3-pip
RUN pip3 install uwsgi
COPY resources/requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
RUN mkdir -p /var/www/
COPY static /var/www/static
COPY code .
COPY resources/start.sh .
RUN chmod +x ./start.sh
ENTRYPOINT ["./start.sh"]
-
首先开头的
FROM nginx
表示根据哪个镜像进行修改制作,虽然官方也有Django的镜像,但无法满足我的要求,于是直接根据官方nginx镜像进行制作。 -
接下来的WORKDIR /usr/src/app,是设置工作目录,就和命令行的cd差不多,后面运行的所有命令都会基于这个工作目录进行,不过如果运行这条指令的时候右边的目录不存在则会自动创建这个目录。
-
后面是配置运行环境的主要过程,主要是 COPY 和 RUN 命令。COPY xxx yyy:就是将文件从本地复制到镜像内部,xxx 是源文件在本机上的目录;yyy 是目的文件在镜像内部的路径,由于之前设置了工作目录,所以实际的目的文件路径就是 /usr/src/app/requirements.txt,例如我这里复制了 Django的Python依赖(requirements.txt)、debian 的国内下载源(sources.list)、pip 的配置文件以及整个项目工程到镜像里。
RUN 命令也很简单,就是在生成镜像文件过程中需要运行的命令,例如我这里运行的命令有安装Python依赖、创建文件夹、设置文件权限等等。
-
最后就是 ENTRYPOINT 命令,设置了运行镜像时要执行的命令,我这里因为要同时运行多个命令,所以把它写成了shell脚本文件。
还有其他很多诸如设置环境变量、标签、暴露端口号什么的还有很多,我觉得没必要详细介绍了,直接看官网的文档或CSDN博客就都可以理解了,这里就只重点介绍一下 ENTRYPOINT 和 CMD 的异同。
ENTRYPOINT 和 CMD 的区别
刚刚我们的示例中用的是ENTRYPOINT,而CMD的作用也差不多,都是设置在容器运行以后执行的命令,在没有设置ENTRYPOINT的情况下,才会使用CMD后面的指令。
两者的基本语法如下:
ENTRYPOINT <command> 或
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
第二种是官方推荐的使用方法,将命令分成几段,写成数组的形式;也可以像RUN一样写成shell的形式。
CMD <command> 或
CMD ["<executeable>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...]
这里的第二种也是官方推荐的写法,而第三种用法则是和 ENTRYPOINT 一起使用的,可以实现在 ENTRYPOINT 中设置执行的程序,而在 CMD 中设置对应的参数,例如下面的示例则会执行top -b -c
。
ENTRYPOINT ["top"]
CMD ["-b","-c"]
还有一点重要的就是,docker run命令后面可以接一个默认运行的命令,它会替换掉 CMD 后面的命令,而 ENTRYPOINT 后面的命令则不会被替换掉。
二、Docker Compose
Docker Compose 是官方用 Python 写的一个小工具,因为有时候需要同时运行多个Docker服务,例如一个简单的网站就需要用到至少两个服务——网页前后端、MySQL服务,而采用手工管理多个服务(包括创建镜像,开始、停止、删除容器等等)并不是很方便,于是 Docker Compose 应运而生,它可以方便的管理多个Docker服务,同时它将 docker run 的运行参数改成了文本文件的配置方式,方便临时修改参数。
Compose file 简述
Docker Compose 主要就是一个docker-compose.yml
文件,里面设置的每个service就相当于一条docker run命令,下面我也用同一个项目的文件范例来介绍:
version: '3'
services:
database:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=XXXXXXXXX
- MYSQL_DATABASE=bxnb_db
web:
image: registry.cn-hangzhou.aliyuncs.com/tommy0607/bxnb-website:v1.5
ports:
- "80:80"
- "443:443"
environment:
- ENV=production
- 开头第一行是Compose file的版本,现在基本上用版本3就可以了
- 后面的services里面是不同的服务,我这里定义了数据库和网页前后端这两个服务,database和web是自定义的服务名
- image指定了服务所使用的镜像名
- environment设置了容器所用的环境变量,与
-e xxxx=yyy
的作用一致 - ports设置了向外部映射的端口,与
-p 80:80
的作用一致
总之就是docker run后面的每一个参数都可以对应一个相关属性,除此之外还可以设置不同服务间的依赖关系等等,这些属性就直接看官方文档就好了,这里不再详述。
Docker Compose 命令介绍
Docker Compose里的命令都和docker里的命令相对应,实现一条命令来开始、停止、删除容器等等的操作
Commands:
build Build or rebuild services
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
ps List containers
restart Restart services
rm Remove stopped containers
run Run a one-off command
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
主要有上面一些命令,其他的我就不介绍了,就介绍两个up和down:
- up命令就是一键创建镜像、运行容器,要记得加上
-d
参数表示在后台运行。 - down命令就是一键停止容器、删除容器、删除镜像。
这些命令后面都可以加上针对的服务名列表,如果不加服务名的话表示对所有服务执行这些命令。
举个例子:docker-compose up -d database
就是创建并后台运行数据库服务。