Dockerfile 是一个文本文件,其中包含了构建 Docker 镜像需要执行的命令序列。使用 docker build
命令从 Dockerfile 中读取指令来构建镜像。
构建镜像时,该过程的第一件事是将 Dockerfile
文件所在目录下的所有内容发送给 Docker 守护进程。所以大多数情况下,最好创建一个新的目录,在其中保存 Dockerfile
,以及构建镜像所需的其它文件。Dockerfile 文件所在目录也被称为构建上下文(context)。
使用 FROM 指令指定一个基础镜像,后续指令将在此镜像基础上运行:
FROM ubuntu:14.04
在 Dockerfile 中可以指定一个用户,后续的 RUN
, CMD
以及 ENTRYPOINT
指令都会使用该用户身份去执行,该用户必须已存在。
USER soundhearer
除了指定用户之外,还可以使用 WORKDIR
指定当前工作目录(CWD), RUN
, CMD
, COPY
, ADD
指令将在指定的工作目录中执行。
WORKDIR /
RUN 指令用于执行命令,该指令有两种形式:
RUN
,在 shell 中执行命令 command
,一般默认的 shell
为 /bin/sh
。RUN["executable","param1","param2",...]
,运行可执行程序 executable
,可以指定程序需要的命令行参数。例如我们执行更新命令:
RUN apt-get update
CMD 的使用方式跟 RUN 类似,不过在一个 Dockerfile 文件中只能有一个 CMD 指令,如果有多个,则只有最后一个会生效。该指令指定了启动容器时要执行的命令,例如:
CMD echo "hello soundhearer"
可以在 docker run
时指定命令来覆盖默认的 CMD 命令,比如 docker run image echo"hello shiyanlou"
。
CMD 指令还有一种特殊用法。在 Dockerfile 中,如果使用 ENTRYPOINT 指令指定了入口命令,则 CMD 指令的内容会作为 ENTRYPOINT 指令的参数:
CMD ["param1", "param2"]
ENTRYPOINT 指令会覆盖 CMD 指令作为容器运行时的默认指令,并且该指令不会被 docker run
时指定的指令覆盖,如下示例:
FROM ubuntu:latest
ENTRYPOINT ["ls", "-a"]
CMD ["-l"]
上述文件构建出来的镜像,使用 docker run image
等同于 docker run image ls-a-l
。使用 docker run image-i-s
等同于 docker run image ls-a-i-s
。即 CMD 指令的值会被当作 ENTRYPOINT 指令的参数附加到 ENTRYPOINT 指令的后面,只有 CMD 指令可以被覆盖。
COPY 和 ADD 都用于将构建上下文中的文件,目录等复制到镜像中。使用方式如下:
ADD <src>... <dest>
ADD ["<SRC>",... "<dest>"]
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
`` 可以指定多个,但是其路径不能超出构建上下文范围,即必须在 Dockerfile 同级或子目录中。
不需要预先存在,不存在时会自动创建,如果使用相对路径,则
为相对于工作目录的路径。
COPY 和 ADD 的不同之处在于,ADD 可以添加远程文件,并且 `` 可以是 gzip 或 tar 等格式的压缩文件,添加时会自动进行解压。
ENV 指令用于设置环境变量:
ENV <key> <value>
ENV <key>=<value> <key>=<value>...
VOLUME 指令指定要创建的挂载路径,在容器运行时,将为每个挂载路径创建一个匿名卷并挂载上去:
VOLUME /data1 /data2
上述指令将会在容器运行时,创建两个匿名卷,并分别挂载到容器中的 /data1 和 /data2 路径。
EXPOSE 用来暴露容器运行时会监听的端口,它只是一种声明,让外部能够知道容器内部的服务端口。可以在运行容器时通过 -p
选项来绑定容器监听端口到宿主机端口,这些监听端口不一定需要通过 EXPOSE 暴露。当使用 -P
(大写)选项时会自动绑定所有暴露出来的端口。
EXPOSE port
学习了上面这些常见的 Dockerfile 指令之后,可以使用这些指令来构建一个镜像。如下所示,构建一个提供 ssh 服务的镜像:
#cd /Docker-Ser/Dockerfile/centos-ssh
#vi Dockerfile
#生成的新镜像以centos镜像为基础
FROM centos
#指定作者信息
MAINTAINER soundhearer
# 安装openssh-server
RUN yum -y install openssh-server
RUN mkdir /var/run/sshd
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
#指定root密码
RUN /bin/echo 'root:123456'|chpasswd
RUN /bin/sed -i 's/.*session.*required.*pam_loginuid.so.*/session optional pam_loginuid.so/g' /etc/pam.d/sshd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" > /etc/default/local
EXPOSE 22
CMD /usr/sbin/sshd -D
构建镜像
[root@VM_0_17_centos dockerfile]# docker build -t 5588/centos-ssh:v1.0.0 .
Sending build context to Docker daemon 14.85kB
Step 1/11 : FROM centos
---> 470671670cac
Step 2/11 : MAINTAINER soundhearer
---> Running in d5705e869a7e
Removing intermediate container d5705e869a7e
---> 76f3b6fa1597
Step 3/11 : RUN yum -y install openssh-server
---> Running in dcd4af79f6c1
查看镜像
[root@VM_0_17_centos dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
5588/centos-ssh v1.0.0 c16cedf7052c 2 minutes ago 278MB
启动容器
[root@VM_0_17_centos dockerfile]# docker run -itd -p 10022:22 --name test_centos_1 5588/centos-ssh:v1.0.0
ae638dff422529144e0066a98611a96ea51cd1469aa8007a503ed8b53ab62d22
[root@VM_0_17_centos dockerfile]#
查看已经启动的容器
[root@VM_0_17_centos dockerfile]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ae638dff4225 5588/centos-ssh:v1.0.0 "/bin/sh -c '/usr/sb…" 51 seconds ago Up 50 seconds 0.0.0.0:10022->22/tcp test_centos_1
测试远程登录
[root@VM_0_17_centos dockerfile]# ssh -p10022 127.0.0.1
root@127.0.0.1's password:
[root@ae638dff4225 ~]#
Compose 是运行由多个容器组成的 Docker
应用的工具,使用 Compose 可以一次启动一组有关联的服务,每个服务由来自同一镜像的单个或多个容器组成。
在复杂应用中,应用一般由多个服务(service)组成,例如一个网站后台通常包含 Web 服务、数据库服务、缓存服务、消息队列服务等。
使用 Compose 的步骤如下:
Dockerfile
文件docker-compose.yml
文件关于 docker-compose.yml 文件的详细格式可以参考 官方文档。
目前有三种版本的 Compose 文件格式:
下载 docker-compose-Linux-x86_64
下载成功后,为了方便使用,可以将其添加到 PATH 路径下
sudo mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compos
sudo chmod +x /usr/local/bin/docker-compose
执行完成后,就能够在终端下直接使用 docker-compose
命令了:
[root@VM_0_17_centos dockerfile]# docker-compose --help
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
接下来我们将创建一个 Web 应用,该应用包含两个容器:
项目目录结构如下:
app
|----web
| |----web.py
| |----requirements.txt
| |----Dockerfile
|
|----docker-compose.yml
首先编辑 app/web/web.py
文件,写入下面的内容:
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
redis.incr('number')
return 'Hello Docker! # %s' % redis.get('number')
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80, debug=True)
上述代码创建了一个简单的 Web 应用。该应用会连接 redis
服务,在访问 /
页面时,自动将变量 number
加 1。
编辑 app/web/requirements.txt
文件,输入如下内容:
flask==0.10
redis==2.10.3
requirements.txt
文件存放了 Web 应用依赖的第三方库包的名称和版本信息。
编辑 app/web/Dockerfile
文件,添加如下内容
FROM python:2.7
COPY ./ /web/
WORKDIR /web
RUN pip install -r requirements.txt
CMD python web.py
上述 Dockerfile
定义了 Web 应用镜像,该镜像基于 python:2.7
基础镜像,在其基础上安装了应用依赖的库包,并通过 CMD
指令指定了应用的启动命令。
编辑 app/docker-compose.yml
文件:
services:
redis:
image: redis:3.2
web:
build:
context: /home/shiyanlou/app/web
depends_on:
- redis
ports:
- 8001:80/tcp
volumes:
- /home/shiyanlou/app/web:/web:rw
version: '3.0'
该 docker-compose.yml
文件定义了两个服务,分别为 web
和 redis
服务,并且配置了 web
服务的端口映射和挂载目录。depends_on
定义了依赖关系,被依赖的服会先启动。
进入 app
目录,执行 docker-compose up
命令来启动应用:
[root@VM_0_17_centos app]# docker-compose up
Building web
Step 1/5 : FROM python:2.7
---> fbc983cb5352
Step 2/5 : COPY ./ /web/
---> 10bdacc94674
Step 3/5 : WORKDIR /web
---> Running in 7ff982241c92
Removing intermediate container 7ff982241c92
---> 0a37af3e9713
Step 4/5 : RUN pip install -r requirements.txt
---> Running in 9832ab0165d1
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting flask==0.10
Downloading Flask-0.10.tar.gz (544 kB)
Collecting redis==2.10.3
Downloading redis-2.10.3.tar.gz (86 kB)
Collecting Werkzeug>=0.7
Downloading Werkzeug-1.0.0-py2.py3-none-any.whl (298 kB)
Collecting Jinja2>=2.4
Downloading Jinja2-2.11.1-py2.py3-none-any.whl (126 kB)
Collecting itsdangerous>=0.21
Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting MarkupSafe>=0.23
Downloading MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl (24 kB)
Building wheels for collected packages: flask, redis
Building wheel for flask (setup.py): started
Building wheel for flask (setup.py): finished with status 'done'
Created wheel for flask: filename=Flask-0.10-py2-none-any.whl size=115528 sha256=967ce1269d455054b3713a87985eeceda84b437ff0c2d0ba8855bb813daf9c10
Stored in directory: /root/.cache/pip/wheels/75/15/2c/b14930624e0a52fdd754537b216da52d96b79dd5d14966abb7
Building wheel for redis (setup.py): started
Building wheel for redis (setup.py): finished with status 'done'
Created wheel for redis: filename=redis-2.10.3-py2-none-any.whl size=50695 sha256=9741ffb0196e0dc9d1818811a48f206aff9c53699dfe822e1b0f9591f72db9e8
Stored in directory: /root/.cache/pip/wheels/12/ce/01/1aba4866d936f9a08aeb59a573b188c17daea0da2537c68dea
Successfully built flask redis
Installing collected packages: Werkzeug, MarkupSafe, Jinja2, itsdangerous, flask, redis
Successfully installed Jinja2-2.11.1 MarkupSafe-1.1.1 Werkzeug-1.0.0 flask-0.10 itsdangerous-1.1.0 redis-2.10.3
Removing intermediate container 9832ab0165d1
---> f12bc5dc1aac
Step 5/5 : CMD python web.py
---> Running in aec73ed63ab6
Removing intermediate container aec73ed63ab6
---> 228792f96283
Successfully built 228792f96283
Successfully tagged app_web:latest
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build`
Creating app_redis_1 ... done
Creating app_redis_1 ...
Creating app_web_1 ... done
Attaching to app_redis_1, app_web_1
redis_1 | 1:C 14 Mar 13:54:22.030 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1 | _._
redis_1 | _.-``__ ''-._
redis_1 | _.-`` `. `_. ''-._ Redis 3.2.12 (00000000/0) 64 bit
redis_1 | .-`` .-```. ```\/ _.,_ ''-._
redis_1 | ( ' , .-` | `, ) Running in standalone mode
redis_1 | |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
redis_1 | | `-._ `._ / _.-' | PID: 1
redis_1 | `-._ `-._ `-./ _.-' _.-'
redis_1 | |`-._`-._ `-.__.-' _.-'_.-'|
redis_1 | | `-._`-._ _.-'_.-' | http://redis.io
redis_1 | `-._ `-._`-.__.-'_.-' _.-'
redis_1 | |`-._`-._ `-.__.-' _.-'_.-'|
redis_1 | | `-._`-._ _.-'_.-' |
redis_1 | `-._ `-._`-.__.-'_.-' _.-'
redis_1 | `-._ `-.__.-' _.-'
redis_1 | `-._ _.-'
redis_1 | `-.__.-'
redis_1 |
redis_1 | 1:M 14 Mar 13:54:22.033 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | 1:M 14 Mar 13:54:22.033 # Server started, Redis version 3.2.12
redis_1 | 1:M 14 Mar 13:54:22.033 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1 | 1:M 14 Mar 13:54:22.033 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1 | 1:M 14 Mar 13:54:22.033 * The server is now ready to accept connections on port 6379
web_1 | * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger PIN: 764-159-950
web_1 | 116.30.196.114 - - [14/Mar/2020 13:58:04] "GET / HTTP/1.1" 200 -
web_1 | 116.30.196.114 - - [14/Mar/2020 13:58:05] "GET /favicon.ico HTTP/1.1" 404 -
web_1 | * Detected change in '/web/web.py', reloading
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger PIN: 764-159-950
启动成功后,就可以打开网址 127.0.0.1:8001
来访问 Web 应用了。
另外一些命令:
# 后台运行应用:
docker-compose up -d
# 查看容器
docker-compose ps
# 查看镜像
docker-compose images
# 停止并删除应用,相关容器也会一并删除
docker-compose down