镜像构造

  我们可以通过公共仓库拉取镜像使用,但是有些时候公共仓库拉取的镜像并不符合我们的需求。尽管已经从繁琐的部署中解放出来,但是实际开发时,我们可能希望镜像包含整个项目的完整环境,在其他机器上拉取 📦 打包完成的镜像,直接运行即可。
Docker 支持自己构建镜像,还支持自己构建的镜像上传至公共仓库,镜像构建可以通过以下两种方式来实现:

  • docker commit:从容器创建一个新的镜像
  • docker build:配合Dockerfile文件创建镜像

Docker commit 镜像构造

  本小节中我们通过基础镜像 centos:7,在该镜像中安装 python 和 Scapy 的环境再将其制作为一个新的镜像 myscapy:7

  • 步骤一:创建容器
1
2
3
$ docker pull centos:7
$ docker run -id --name mycentos centos:7
565227db06fd95a05e544235a58b765f226b0510a48fa5541c4502ceae3094ba
  • 步骤二:下载资源
1
2
3
4
5
6
7
8
9
10
$ docker exec -it mycentos /bin/bash
[root@565227db06fd /]# yum install python3
[root@565227db06fd /]# pip3 install scapy
# 如果资源是需要从本地拷贝的话,使用cp的命令即可
[root@565227db06fd /]# python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>>
  • 步骤三:构建镜像
1
2
3
4
5
6
7
8
9
10
11
12
# docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
$ docker commit -a="DeepMountains" -m="PYTHON:Scapy" mycentos mycentos:7
sha256:71924f38dd6296c22e406cdf6b82515865b08240c82578c28e7c92cfc19d7da3
# -a:提交镜像的作者
# -c:使用Dockerfile命令指令来创建镜像
# -m:提交镜像的描述信息
# -p:在commit时,将容器暂停

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 7 71924f38dd62 6 seconds ago 364MB
tomcat latest 040bdb29ab37 3 weeks ago 649MB

Dockerfile 构建镜像

  在 Docker 中构建镜像最常用的方式,就是使用 Dockerfile。Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需要的指令和说明。

  • Dockerfile常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# From
# 指明构建的新镜像时来自于哪个基础镜像,如果没有选择tag,那么默认值为latest.
# 如果不以任何镜像为基础,那么写法为:FROM scratch。
# scratch镜像是一个空镜像,可以用于构建busbox等超小镜像,可以说是真正的从零开始构建属于自己的镜像
FROM centos:7

# LABEL
# 为镜像指明标签,也可以使用LABEL来制定镜像作者
# LABEL <key>=<value> <key>=<value> ......
LABEL maintainer="DeepMountains"

# RUN
# 构建镜像运行时的shell命令,比如构建的新镜像中我们想在/usr/local目录下创建一个新的目录
RUN mkdir -p /usr/local/java

# ADD
# 拷贝文件或目录到镜像中。src可以是一个本地文件或者一个本地压缩文件,压缩文件会自动解压。还可以是一个URL,
# 把src写成一个url,那么ADD就类似于wget命令,然后自动下载和解压
# ADD <src>...<dest>
ADD jdk-11.0.6_Linux-x64_bin.tar.gz /usr/local/java

# COPY
# 拷贝文件或目录到镜像中。用法同ADD,但是不支持自动下载和解压
COPY jdk-11.0.6_Linux-x64_bin.tar.gz /usr/local/java

# EXPOSE
# 暴露容器运行监听的端口给外部,可以指端口是监听TCP还是UDP,如果为指定协议,则默认为TCP。
# 如果想使用容器与宿主机的端口有映射关系,必须在容器启动的时候加上-P参数
# EXPOSE <port> [<port>/<protocol>...]
EXPOSE 80 443 8080/tcp

# ENV
# 设置容器环境变量
# ENV <key> <value>添加单个;ENV <key>=<value> ...添加多个
ENV JAVA_HOME /usr/local/java/jdk-11.0.6/

# CMD
# 启动容器时执行的shell命令。在Dockerfile中只能有一条CMD指令。如果设置了多条CMD指令,只有最后一条生效
# CMD ["executable","param1","param2"];例如CMD ["python3","run"]
# CMD ["param1","param2"];例如 CMD ["echo","$JAVA_HOME"]
# CMD command param1 param2;例如 CMD echo $JAVA_HOME
# 如果容器在docker run的时候指定了命令则cmd命令会被替代,不生效。在run的命令后面可以添加一个命令。
CMD echo $JAVA_HOME

# ENTERYPOINT
# 启动容器时执行的shell命令。同CMD类似,不会被docker run命令行指定的参数所覆盖。在Dockerfile中只能有一条ENTRYPOINT指令。
# 如果设置了多条ENTRYPOINT,只有最后一条指令生效。
# ENTRYPOINT ["executable","param1","param2"];例如ENTRYPOINT ["python3","run"]
# ENTRYPOINT command param1 param2;例如 ENTRYPOINT echo $JAVA_HOME
# 如果在Dockerfile中同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将被作为ENTRYPOIT的参数
# 如果在Dockerfile中同时写了ENTRYPOINT和CMD,并且CMD是一个完整指令,那么它们会相互覆盖,谁在最后谁生效
ENTRYPOINT echo $JAVA_HOME

# WORKDIR
# 为RUN、CMD、ENTRYPOINT以及COPY和AND设置工作目录。说白了通过docker exec -it进入容器时所在的目录
WORKDIR /usr/local

# VOLUME
# 指定容器挂载点到宿主机自动生成的目录或其他容器。一般的使用场景为需要持久化存储数据时。
# 一般不会在Dockerfile中用到,更常见的还是在docker run的时候通过-v的方式灵活挂载
VOLUME ["/var/lib/mysql"]
# 容器的/var/lib/mysql目录会在运行时自动挂载为匿名卷,匿名卷在宿主机的/var/lib/docker/volumes目录下
  • 构建Dockerfile
1
2
3
4
5
6
7
FROM centos:7
LABEL maintainer="DeepMountains"
RUN mkdir -p /etc/docker_test
RUN yum install python3 -y
RUN pip3 install scapy
WORKDIR /etc/docker_test
CMD ["python3"]
  • 运行Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# 使用build命令来构建镜像,-f指定dockerfile文件的位置,-t设置输出镜像的名字,最后为若dockerfile文件中含有需要拷贝的的资源则需要指定资源的位置
$ docker build -f ./dockerfile -t mypython3 /root/

Sending build context to Docker daemon 12.29kB
Step 1/7 : FROM centos:7
---> 8652b9f0cb4c
Step 2/7 : LABEL maintainer="DeepMountains"
---> Using cache
---> 83f8205ce7e0
Step 3/7 : RUN mkdir -p /etc/docker_test
---> Using cache
---> eabf7253e75c
Step 4/7 : RUN yum install python3 -y
---> Running in 881d1ed87f7e
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
* updates: mirrors.aliyun.com
Resolving Dependencies
--> Running transaction check
---> Package python3.x86_64 0:3.6.8-18.el7 will be installed
--> Processing Dependency: python3-libs(x86-64) = 3.6.8-18.el7 for package: python3-3.6.8-18.el7.x86_64
--> Processing Dependency: python3-setuptools for package: python3-3.6.8-18.el7.x86_64
--> Processing Dependency: python3-pip for package: python3-3.6.8-18.el7.x86_64
--> Processing Dependency: libpython3.6m.so.1.0()(64bit) for package: python3-3.6.8-18.el7.x86_64
--> Running transaction check
---> Package python3-libs.x86_64 0:3.6.8-18.el7 will be installed
--> Processing Dependency: libtirpc.so.1()(64bit) for package: python3-libs-3.6.8-18.el7.x86_64
---> Package python3-pip.noarch 0:9.0.3-8.el7 will be installed
---> Package python3-setuptools.noarch 0:39.2.0-10.el7 will be installed
--> Running transaction check
---> Package libtirpc.x86_64 0:0.2.4-0.16.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
python3 x86_64 3.6.8-18.el7 updates 70 k
Installing for dependencies:
libtirpc x86_64 0.2.4-0.16.el7 base 89 k
python3-libs x86_64 3.6.8-18.el7 updates 6.9 M
python3-pip noarch 9.0.3-8.el7 base 1.6 M
python3-setuptools noarch 39.2.0-10.el7 base 629 k

Transaction Summary
================================================================================
Install 1 Package (+4 Dependent packages)

Total download size: 9.3 M
Installed size: 48 M
Downloading packages:
warning: /var/cache/yum/x86_64/7/base/packages/libtirpc-0.2.4-0.16.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Public key for libtirpc-0.2.4-0.16.el7.x86_64.rpm is not installed
Public key for python3-3.6.8-18.el7.x86_64.rpm is not installed
--------------------------------------------------------------------------------
Total 5.8 MB/s | 9.3 MB 00:01
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Importing GPG key 0xF4A80EB5:
Userid : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
Package : centos-release-7-9.2009.0.el7.centos.x86_64 (@CentOS)
From : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : libtirpc-0.2.4-0.16.el7.x86_64 1/5
Installing : python3-setuptools-39.2.0-10.el7.noarch 2/5
Installing : python3-pip-9.0.3-8.el7.noarch 3/5
Installing : python3-3.6.8-18.el7.x86_64 4/5
Installing : python3-libs-3.6.8-18.el7.x86_64 5/5
Verifying : libtirpc-0.2.4-0.16.el7.x86_64 1/5
Verifying : python3-setuptools-39.2.0-10.el7.noarch 2/5
Verifying : python3-libs-3.6.8-18.el7.x86_64 3/5
Verifying : python3-3.6.8-18.el7.x86_64 4/5
Verifying : python3-pip-9.0.3-8.el7.noarch 5/5

Installed:
python3.x86_64 0:3.6.8-18.el7

Dependency Installed:
libtirpc.x86_64 0:0.2.4-0.16.el7 python3-libs.x86_64 0:3.6.8-18.el7
python3-pip.noarch 0:9.0.3-8.el7 python3-setuptools.noarch 0:39.2.0-10.el7

Complete!
Removing intermediate container 881d1ed87f7e
---> 9bb5fc96382f
Step 5/7 : RUN pip3 install scapy
---> Running in a729ab36718f
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting scapy
Downloading https://files.pythonhosted.org/packages/c6/8f/438d4d0bab4c8e22906a7401dd082b4c0f914daf2bbdc7e7e8390d81a5c3/scapy-2.4.4.tar.gz (1.0MB)
Installing collected packages: scapy
Running setup.py install for scapy: started
Running setup.py install for scapy: finished with status 'done'
Successfully installed scapy-2.4.4
Removing intermediate container a729ab36718f
---> f2092b9e06cf
Step 6/7 : WORKDIR /etc/docker_test
---> Running in f7e4a5d7849b
Removing intermediate container f7e4a5d7849b
---> b9b2f9241b2e
Step 7/7 : CMD ["python3"]
---> Running in 0d72e02d4b73
Removing intermediate container 0d72e02d4b73
---> b05b660f7714
Successfully built b05b660f7714
Successfully tagged mypython3:latest

$ docker run -id --name python01 mypython3
7f7241be4f19167e8f8e4f0c931d80f0817eccc95a50805b0a7c9adfa1846635
$ docker exec -it python01 bash
[root@7f7241be4f19 docker_test]# ps -ef | grep python
root 1 0 0 04:41 ? 00:00:00 python3

镜像容灾

  备份镜像,我们有以下几个方式可以选择:

  • 将指定的镜像保存tar归档文件,需要使用时将tar包恢复为镜像即可;
  • 登陆DockerHub注册中心,将镜像推送至DockerHub仓库方便使用;
  • 搭建私有镜像仓库,将镜像推送至私有镜像仓库方便使用

镜像备份和恢复

1
2
3
4
5
6
7
8
9
10
# 使用docker save将指定镜像保存为tar归档文件
# docker save [OPTIONS] IMAGE [IMAGE...]
# -o:镜像打包后的归档文件输出目录
docker save -o /root/mycentos7.tar mycentos:7

# 使用docker load导入docker save命令到处的归档文件
# docker load [OPTIONS]
# --input,-i:指定导入的文件
# --quiet,-q:精简输出信息
$ docker load -i mycentos7.tar

Docker Hub 注册中心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 第一步登陆docker,在hub.docker.com上可以注册用户。推出登陆使用logout命令
# 登陆了之后所有的pull操作都会在个人仓库中查找
$ docker login
Login with your Docker ID to push and pull images from Docker Hub.
Username: deepmountains
Password:
Login Succeeded

# 第二步给docker镜像打上tag
$ docker tag mypython3:latest deepmountains/mypython3:lmb1.0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
deepmountains/mypython3 lmb1.0 3b704de398aa 4 hours ago 364MB

# 第三步上传镜像
$ docker push deepmountains/mypython3:lmb1.0

Docker 私有仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 安装私有仓库
$ docker pull registry

# 修改配置文件,追加以下行8的内容
$ vi /etc/docker/daemon.json
{
"registry-mirrors": ["http://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn"],
"insecure-registries":["192.168.222.200:5000"]
}
$ systemctl daemon-reload
$ systemctl restart docker

# 创建私有仓库容器
$ docker run -id --name lmbregistry -p 5000:5000 -v /root/docker/registry/:/var/lib/registry registry
15af55c3134ef6ffab7794ce83a7558247e8e059893ff27bcdf8e6108f5bfe50
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
15af55c3134e registry "/entrypoint.sh /etc…" About a minute ago Up About a minute 0.0.0.0:5000->5000/tcp lmbregistry

# push镜像至私有仓库
$ docker tag mypython3 192.168.222.200:5000/mypython3:lmb1.0
$ docker push 192.168.222.200:5000/mypython3:lmb1.0
The push refers to repository [192.168.222.200:5000/mypython3]
713a84d3be51: Pushed
a33aed951d88: Pushed
9dfcd2f3e89a: Pushed
174f56854903: Pushed
lmb1.0: digest: sha256:0159cd84f32f7a56f014b2935f8b9a30249af499af5624d8c8e594f45cd15f38 size: 1159
$ cd docker/registry/docker/registry/v2/repositories/
$ ls
mypython3