1 Docker容器管理
1.1 语法格式
docker run [选项] [镜像名] [shell命令] [参数]
docker run [参数选项] [镜像名称,必须在所有选项的后面] [/bin/echo 'hellowold'] #单次执行,没有自定义容器名称
docker run centos /bin/echo 'hello wold' #启动的容器在执行完shel命令就退出了
1.2 启动一个容器
[root@test01 ~]# docker run -it alpine:latest /bin/sh # -i:交互式操作。-t: 分配一个tty终端
/ # exit # 在容器中退出的话,像这种没有守护进程的镜像,容器也会退出运行
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
78af0f97e239 alpine:latest "/bin/sh" 11 seconds ago Exited (0) 3 seconds ago cool_diffie
# 退出容器命令行,容器继续运行
[root@test01 ~]# docker run -it alpine:latest /bin/sh # 在容器命令行按 ctrl+p+q,就可以退出容器命令行,容器继续运行
/ # [root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 16 seconds ago Up 15 seconds friendly_lumiere
1.3 查看容器
1.3.1 查看正在运行的容器
[root@test01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 2 minutes ago Up 2 minutes friendly_lumiere
e6e1ca6883dc 605c77e624dd "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp kind_meninsky
1.3.2 查看最近启动的一个容器
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 7 minutes ago Up 7 minutes friendly_lumiere
1.3.3 查看所有容器
[root@test01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 8 minutes ago Up 8 minutes friendly_lumiere
db2d702c166d alpine:latest "/bin/bash" 10 minutes ago Created stupefied_elgamal
5dd07a6914cd alpine:latest "bash" 10 minutes ago Created admiring_ishizaka
e6e1ca6883dc 605c77e624dd "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp kind_meninsky
1.4 删除容器
1.4.1 删除未运行的容器
[root@test01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 9 minutes ago Up 9 minutes friendly_lumiere
db2d702c166d alpine:latest "/bin/bash" 11 minutes ago Created stupefied_elgamal
5dd07a6914cd alpine:latest "bash" 12 minutes ago Created admiring_ishizaka
e6e1ca6883dc 605c77e624dd "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp kind_meninsky
[root@test01 ~]# docker rm db2d702c166d # 可以指定id或容器名进行删除。且可以一次性删除多个,容器ID或容器名之间用空格分
db2d702c166d
[root@test01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 10 minutes ago Up 10 minutes friendly_lumiere
5dd07a6914cd alpine:latest "bash" 12 minutes ago Created admiring_ishizaka
e6e1ca6883dc 605c77e624dd "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp kind_meninsky
1.4.2 删除正在运行的容器
[root@test01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d1217afbf527 alpine:latest "/bin/sh" 10 minutes ago Up 10 minutes friendly_lumiere
e6e1ca6883dc 605c77e624dd "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp kind_meninsky
[root@test01 ~]# docker rm -f d1217afbf527 # 可以指定id或容器名进行删除。且可以一次性删除多个,容器ID或容器名之间用空格分隔
d1217afbf527
[root@test01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e6e1ca6883dc 605c77e624dd "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:81->80/tcp kind_meninsky
1.5 容器端口映射
1.5.1 随机端口映射
-P:分配随机端口(宿主机上的)映射到容器端口
Docker随机端口范围的默认值是32768到60999。
可以通过修改/etc/sysctl.conf文件中的net.ipv4.ip_local_port_range参数来调整随机端口范围。
[root@test01 ~]# docker run -it -d -P nginx:latest
04dfa3d4a8d91d566bab247ab972e4f9905cb6e8d6f1266dd4e9365258309be1
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
04dfa3d4a8d9 nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:32769->80/tcp stupefied_diffie
[root@test01 ~]# curl -I 10.31.200.3:32769
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Thu, 16 Mar 2023 14:05:24 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
# 查看iptables规则
[root@test01 ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 2 packets, 104 bytes)
pkts bytes target prot opt in out source destination
22 1144 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 2 packets, 104 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 277 bytes)
pkts bytes target prot opt in out source destination
1 60 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 5 packets, 337 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.3 172.17.0.3 tcp dpt:80
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:81 to:172.17.0.3:80
1 60 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32769 to:172.17.0.2:80 # 这里可以看到,所有请求到32769端口的,都会转到172.17.0.2:80
1.5.2 指定端口映射
1.5.2.1 方法1:本地端口映射到容器端口
[root@test01 ~]# docker run -it -d -p 999:80 nginx:latest # 999宿主机端口,80容器端口
985bd9bc30fbfaea4822fc426518b0e528970770216c2fba6174cc8b579b9bb6
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
985bd9bc30fb nginx:latest "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 0.0.0.0:999->80/tcp elegant_khayyam
[root@test01 ~]# curl -I 10.31.200.3:999
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Thu, 16 Mar 2023 14:17:45 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
[root@test01 ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
22 1144 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
2 120 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 1 packets, 60 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.3 172.17.0.3 tcp dpt:80
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
0 0 MASQUERADE tcp -- * * 172.17.0.4 172.17.0.4 tcp dpt:80
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:81 to:172.17.0.3:80
1 60 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32769 to:172.17.0.2:80
1 60 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:999 to:172.17.0.4:80
1.5.2.2 方法2:指定宿主机ip和端口
当服务器多个IP时,可以指定某端口的请求从指定IP进来时,才被转发到容器
# 不指定地址映射,外部所有请求都可以请求到容器
[root@test01 ~]# ss -lntup|grep 999
tcp LISTEN 0 128 [::]:999 [::]:* users:(("docker-proxy",pid=19422,fd=4))
# 指定地址映射
[root@test01 ~]# docker run -d -it -p 10.31.200.3:1001:80/tcp nginx:latest # 只有请求10.31.200.3:1001,才能访问到容器的80
ce4e9f636cd1c59f8c6c60be1e968f46bde228849257ac4853d686a395c164d9
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4e9f636cd1 nginx:latest "/docker-entrypoint.…" 8 seconds ago Up 7 seconds 10.31.200.3:1001->80/tcp upbeat_mendel
[root@test01 ~]# ss -lnt|grep 1001
LISTEN 0 128 10.31.200.3:1001 *:*
1.5.2.3 方法3:指定宿主机ip和随机端口
[root@test01 ~]# docker run -d -it -p 10.31.200.3::80 nginx:latest # 不写宿主机端口就是随机分配
83e34150ce61156da1acf1ea14f3afb1ed1700f4e8166c9306d0f6d886119e19
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
83e34150ce61 nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 10.31.200.3:32770->80/tcp nervous_boot # 这里随机分配的32770
1.5.2.4 方法4:指定宿主机IP、端口、协议
默认协议为:tcp
docker run -d -it -p 10.31.200.3:93:80/tcp -p 530:53/udp nginx:latest
1.5.2.5 方法5:一次性映射多个端口和协议
[root@test01 ~]# docker run -d -it -p 80:80 -p 443:443 nginx:latest
1.5.3 直接使用宿主机端口
容器是什么端口,宿主机上就是什么端口
–network=host:host,使用宿主机的IP和端口
[root@test01 ~]# docker run -d -it --network=host nginx:latest
11fcc30bc5c4569b7a6f3c1fc7667e8f7b22fa0f543f5d0bf15c7f653e0bb3a2
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11fcc30bc5c4 nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 2 seconds epic_mcclintock
[root@test01 ~]# ss -lntup|grep 80
tcp LISTEN 0 128 *:80 *:* users:(("nginx",pid=22864,fd=7),("nginx",pid=22863,fd=7),("nginx",pid=22825,fd=7))
tcp LISTEN 0 128 [::]:80 [::]:* users:(("nginx",pid=22864,fd=8),("nginx",pid=22863,fd=8),("nginx",pid=22825,fd=8))
[root@test01 ~]# curl -I 10.31.200.3
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Fri, 17 Mar 2023 05:42:49 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
1.5.4 查看容器已经映射的端口
[root@test01 ~]# docker ps -a # docker ps也可以看(比较常用)
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b5d6b01a7930 nginx:latest "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 0.0.0.0:1000->80/tcp elastic_goodall
11fcc30bc5c4 nginx:latest "/docker-entrypoint.…" 32 minutes ago Up 32 minutes epic_mcclintock
[root@test01 ~]# docker port b5d6b01a7930 # docker port也可以看
80/tcp -> 0.0.0.0:1000
1.6 查看容器日志
docker logs 容器名或容器ID
#参数
-f : 跟踪日志输出(实时查看)
--since :显示某个开始时间的所有日志
-t : 显示时间戳
--tail :仅列出最新N条容器日志
1.6.1 方式1:全量查看
方式1太过简单粗暴,一次查看所有日志,一般生产日志都非常多,这样会导致终端直接卡死
[root@test01 ~]# docker logs 11fcc30bc5c4
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/03/17 05:42:21 [notice] 1#1: using the "epoll" event method
2023/03/17 05:42:21 [notice] 1#1: nginx/1.21.5
2023/03/17 05:42:21 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/03/17 05:42:21 [notice] 1#1: OS: Linux 3.10.0-1062.el7.x86_64
2023/03/17 05:42:21 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/03/17 05:42:21 [notice] 1#1: start worker processes
2023/03/17 05:42:21 [notice] 1#1: start worker process 31
2023/03/17 05:42:21 [notice] 1#1: start worker process 32
10.31.200.3 - - [17/Mar/2023:05:42:49 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"
[root@test01 ~]# docker logs 11fcc30bc5c4|less # 这样可以防止日志全量输出,卡死终端
1.6.2 方式2:实时查看
这种方式也会一次加载所有日志内容出来,日志内容少还行,多了不推荐
[root@test01 ~]# docker logs -f 11fcc30bc5c4
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/03/17 05:42:21 [notice] 1#1: using the "epoll" event method
2023/03/17 05:42:21 [notice] 1#1: nginx/1.21.5
2023/03/17 05:42:21 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/03/17 05:42:21 [notice] 1#1: OS: Linux 3.10.0-1062.el7.x86_64
2023/03/17 05:42:21 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/03/17 05:42:21 [notice] 1#1: start worker processes
2023/03/17 05:42:21 [notice] 1#1: start worker process 31
2023/03/17 05:42:21 [notice] 1#1: start worker process 32
10.31.200.3 - - [17/Mar/2023:05:42:49 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"
1.6.3 方式3:查看最后几行
工作中比较推荐这种方式。
但更加合理的还是做日志收集
[root@test01 ~]# docker logs -f --tail 5 11fcc30bc5c4
2023/03/17 05:42:21 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/03/17 05:42:21 [notice] 1#1: start worker processes
2023/03/17 05:42:21 [notice] 1#1: start worker process 31
2023/03/17 05:42:21 [notice] 1#1: start worker process 32
10.31.200.3 - - [17/Mar/2023:05:42:49 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.29.0" "-"
1.7 自定义容器名称
容器启动时可以用–name来指定容器名,不指定的话会随机分配一个名称
[root@test01 ~]# docker run -d -it -p :80 --name nginx-v1 nginx:latest
12104a624f6b3cd165b3f1fbcab83acd2d91fe4bcb579cbb0c4a5064134adaf1
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
12104a624f6b nginx:latest "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 0.0.0.0:32770->80/tcp nginx-v1
1.8 后台运行容器
-d:让容器后台运行
[root@test01 ~]# docker run -d -it nginx:latest
5a292ecb3cfad9264e7c3443e2505e21bee447a26524455b46111b9b675959c0
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a292ecb3cfa nginx:latest "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 80/tcp goofy_gagarin
1.8.1 为什么要后台运行
# 这里用nginx举例说明。
## nginx容器,默认是有deamon守护进程的,不加-d是这样的
[root@test01 ~]# docker run -it -p :80 nginx:latest # 因为nginx有守护进程的原因,默认会前台运行,所以我们必须加-d让他后台运行,这样关闭终端才不会影响服务正常运行,否则容器会退出
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/03/17 06:22:20 [notice] 1#1: using the "epoll" event method
2023/03/17 06:22:20 [notice] 1#1: nginx/1.21.5
2023/03/17 06:22:20 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/03/17 06:22:20 [notice] 1#1: OS: Linux 3.10.0-1062.el7.x86_64
2023/03/17 06:22:20 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/03/17 06:22:20 [notice] 1#1: start worker processes
2023/03/17 06:22:20 [notice] 1#1: start worker process 30
2023/03/17 06:22:20 [notice] 1#1: start worker process 31
# 按ctrl+c 前台运行的容器就会退出
2023/03/17 06:23:35 [notice] 1#1: signal 2 (SIGINT) received, exiting
2023/03/17 06:23:35 [notice] 1#1: signal 17 (SIGCHLD) received from 30
2023/03/17 06:23:35 [notice] 1#1: worker process 30 exited with code 0
2023/03/17 06:23:35 [notice] 1#1: signal 29 (SIGIO) received
2023/03/17 06:23:35 [notice] 1#1: signal 17 (SIGCHLD) received from 31
2023/03/17 06:23:35 [notice] 1#1: worker process 31 exited with code 0
2023/03/17 06:23:35 [notice] 1#1: exit
1.9 创建并进入容器
参数:
-i:表示在容器中保持标准输入流(STDIN)开放,使得用户可以将输入发送到容器中的命令或应用程序。
-t:表示在容器中分配一个终端操作器,以便用户可以使用交互式(TTY)模式与容器进行通信。
[root@test01 ~]# docker run -it nginx:latest bash # bash是传递的命令,这样可以直接进入命令行,可以使用sh。
root@7a33a99724f5:/#
root@7a33a99724f5:/#
root@7a33a99724f5:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@7a33a99724f5:/# exit
exit
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7a33a99724f5 nginx:latest "/docker-entrypoint.…" 10 seconds ago Exited (0) 3 seconds ago laughing_satoshi
1.10 单次运行容器
–rm:容器退出后就自动删除
[root@localhost ~]# docker run -it --rm --name nginx-delete-test nginx # 这里运行一个容器,然后ctrl+c退出
[root@localhost ~]# docker ps -a # ps -a也找不到这个容器,就说明被删除了
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1.10 启动容器时传递命令
容器需要有一个前台运行的进程才能保持容器的运行,通过传递运行参数是一种方式,另外也可以在构建镜像的时候指定容器启动时运行的前台命令。
[root@localhost ~]# docker run -it --name nginx-delete-test nginx cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 54d159aeed88
1.11 容器的启动和关闭
关闭:stop
启动:start
重启:restart
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3960437b729f nginx "/docker-entrypoint.…" 8 seconds ago Up 7 seconds 80/tcp nginx-delete-test
[root@localhost ~]# docker stop 3960437b729f
3960437b729f
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3960437b729f nginx "/docker-entrypoint.…" 19 seconds ago Exited (0) 1 second ago nginx-delete-test
[root@localhost ~]# docker start 3960437b729f
3960437b729f
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3960437b729f nginx "/docker-entrypoint.…" 25 seconds ago Up 1 second 80/tcp nginx-delete-test
1.12 进入容器
1.12.1 使用attach命令
**
不推荐使用该方式进入容器。
因为attach类似于vnc,就算多个人同时进入容器,但是命令行只有一个人能操作。并且一个终端关闭,其他终端也会关闭。
**
不推荐使用该方式
1.12.2 使用exec命令
该方式工作中常用,可以多用户同时使用。
exec: 在运行的容器中执行命令
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3960437b729f nginx "/docker-entrypoint.…" 9 minutes ago Up 9 minutes 80/tcp nginx-delete-test
[root@localhost ~]# docker exec -it 3960437b729f bash
root@3960437b729f:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@3960437b729f:/# exit
exit
1.12.3 nsenter
nsenter:单纯的进入容器
该命令需要通过PID进入到容器内部,不过可以使用docker inspect获取到容器的PID
[root@localhost ~]# yum install util-linux # nsenter命令在util-linux包中
[root@localhost ~]# docker inspect 3960437b729f|grep State -A 10 # 先找到包含容器PID的字段
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 2296,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-03-18T13:25:16.607306011Z",
[root@localhost ~]# docker inspect -f "{{.State.Pid}}" 3960437b729f # 通过这种方式就可以取出想要的值
2296
[root@localhost ~]# nsenter -t 2296 -m -u -i -n -p # 进入容器
root@3960437b729f:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@3960437b729f:/# exit
logout
1.12.3.1 脚本方式
由于单纯使用nsenter太麻烦,所以可以使用脚本
[root@localhost ~]# cat docker-in.sh
#!/bin/bash
docker_in(){
NAME_ID=$1
PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID})
nsenter -t ${PID} -m -u -i -n -p
}
docker_in $1
[root@localhost ~]# sh docker-in.sh 3960437b729f
root@3960437b729f:/# exit
logout
1.13 容器的hosts文件
[root@localhost ~]# docker exec -it 3708963039f6 bash
[root@3708963039f6 /]# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 3708963039f6 # 容器默认会将实例ID添加到自己的hosts文件中
[root@3708963039f6 /]# ping 3708963039f6
PING 3708963039f6 (172.17.0.3) 56(84) bytes of data.
64 bytes from 3708963039f6 (172.17.0.3): icmp_seq=1 ttl=64 time=0.031 ms
1.14 容器的批量操作
1.14.1 批量停止正在运行的容器
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3708963039f6 eeb6ee3f44bd "bash" 4 minutes ago Up 4 minutes C7
3960437b729f nginx "/docker-entrypoint.…" About an hour ago Up About an hour 80/tcp nginx-delete-test
[root@localhost ~]# docker ps -q # -q:只显示容器ID
3708963039f6
3960437b729f
[root@localhost ~]# docker stop `docker ps -q`
3708963039f6
3960437b729f
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3708963039f6 eeb6ee3f44bd "bash" 4 minutes ago Exited (137) 5 seconds ago C7
3960437b729f nginx "/docker-entrypoint.…" About an hour ago Exited (0) 15 seconds ago nginx-delete-test
1.14.2 批量强制停止正在运行的容器
docker kill。
不推荐该方式,可能会丢数据或者造成服务异常,除非容器真的关不掉。
[root@localhost ~]# docker start `docker ps -qa`
3708963039f6
3960437b729f
[root@localhost ~]# docker kill `docker ps -q`
3708963039f6
3960437b729f
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3708963039f6 eeb6ee3f44bd "bash" 7 minutes ago Exited (137) 4 seconds ago C7
3960437b729f nginx "/docker-entrypoint.…" About an hour ago Exited (137) 4 seconds ago nginx-delete-test
[root@localhost ~]#
1.14.3 批量删除已经退出运行的容器
[root@localhost ~]# docker rm `docker ps -aq -f status=exited`
3708963039f6
3960437b729f
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1.14.4 批量删除所有容器
危险,会删除正在运行和退出运行的容器
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0c3690a93a54 eeb6ee3f44bd "bash" 18 seconds ago Up 17 seconds unruffled_thompson
0708d3234dd8 nginx "/docker-entrypoint.…" 34 seconds ago Up 33 seconds 80/tcp laughing_euclid
[root@localhost ~]# docker rm -f `docker ps -qa`
0c3690a93a54
0708d3234dd8
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1.15 指定容器DNS
容器默认情况下是使用宿主机的DNS的,当我们需要容器访问内部DNS时,可以手动修改这个DNS地址。
[root@localhost ~]# cat /etc/resolv.conf # 查看宿主机DNS
# Generated by NetworkManager
nameserver 114.114.114.114
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
70d121296729 eeb6ee3f44bd "bash" 7 seconds ago Up 7 seconds bold_hopper
[root@localhost ~]# docker exec -it 70d121296729 cat /etc/resolv.conf # 查看容器DNS
# Generated by NetworkManager
nameserver 114.114.114.114
1.15.1 方法1:修改宿主机DNS
[root@localhost ~]# vim /etc/resolv.conf # 给宿主机添加DNS
# Generated by NetworkManager
nameserver 114.114.114.114
nameserver 8.8.8.8
[root@localhost ~]# docker run -it eeb6ee3f44bd bash
[root@24eb3ea96a63 /]# cat /etc/resolv.conf # 查看容器dns
# Generated by NetworkManager
nameserver 114.114.114.114
nameserver 8.8.8.8
1.15.2 方法2:使用–dns参数指定dns地址
[root@localhost ~]# docker run -it --dns 1.1.1.1 eeb6ee3f44bd bash
[root@2b6bf420b08d /]# cat /etc/resolv.conf
nameserver 1.1.1.1
[root@2b6bf420b08d /]# exit
exit
1.16 文件复制
# 复制容器中的文件到宿主机
docker cp 容器ID或容器名:/绝对路径/文件名 宿主机绝对路径
# 复制宿主机中的文件到容器
docker cp 宿主机绝对路径/文件名 容器ID或容器名:/绝对路径/文件名 # 会直接覆盖容器中的源文件
1.17 容器环境变量
有些容器的启动,是需要传递相关的环境变量,才能正常启动的,如下
[root@test01 ~]# docker run -itd --name mysql-5.6 -p 3307:3306 dd3b2a5dcb48
b454e438b22b29342f7a034b9f181cf9e31fd8c7f3ab5b375d696cdaed9c19bd
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b454e438b22b dd3b2a5dcb48 "docker-entrypoint.s…" 3 seconds ago Exited (1) 1 second ago mysql-5.6
[root@test01 ~]# docker logs b454e438b22b # 上面启动一个mysql容器,但是起来就退出了,查看日志发现需要传递变量才可以
2023-03-20 02:24:37+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.6.51-1debian9 started.
2023-03-20 02:24:37+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2023-03-20 02:24:37+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.6.51-1debian9 started.
2023-03-20 02:24:37+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of the following:
- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD
[root@test01 ~]# docker run -itd --name mysql-5.6 -p 3307:3306 -e MYSQL_ROOT_PASSWORD='123456' dd3b2a5dcb48
3ebe2131b0217e960c1a4d678dc62f54162dd8a5657ea93e1aba316fb52a5538
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3ebe2131b021 dd3b2a5dcb48 "docker-entrypoint.s…" 2 seconds ago Up 2 seconds 0.0.0.0:3307->3306/tcp mysql-5.6
1.18 其他命令
1.18.1 更新容器资源配置信息
docker update 容器--cpus 2 # 更新容器的cpu资源配置
1.18.2 获取dockerd的实时事件
docker events # 容器的增删改查都会记录下来
1.18.3 显示容器的退出状态码
docker wait f8ae0c8dcaf8 #显示容器的退出状态码
2. Docekr镜像与制作
Docker镜像有没有内核吗?
从镜像大小上面来说,一个比较小的镜像只有十几MB,而内核文件需要一百多兆,因此镜像里面是没有内核的,镜像在被启动为容器后将直接使用宿主机的内核,而镜像本身则只提供相应的rootfs,即系统正常运行所必须的用户空间的文件系统,比如/devl,/proc,/bin,/etc等目录,所以容器中/boot是空的,而/boot当中保存的就是与内核相关的文件和目录。
为什么没有内核?
由于容器启动和运行过程中是直接使用了宿主机的内核,所以没有直接调用过物理硬件,所以也不会涉及到硬件驱动,因此也用不上内核和驱动,另外有内核的那是虚拟机。
2.1 制作镜像的方式
(1)docker commit # 基于运行中的容器制作一个新的镜像
(2)dockerfile
2.2 基于docker commit方式制作镜像
相关参数
-a :提交的镜像作者;
-c :使用Dockerfile指令来创建镜像;
-m :提交时的说明文字;
-p :在commit时,将容器暂停(默认参数,不加也会暂停,防止新数据写入)。
2.2.1 下载基础镜像并初始化环境
[root@test01 ~]# docker images |grep centos
centos centos7.9.2009 eeb6ee3f44bd 18 months ago 204MB
[root@test01 ~]# docker run -it eeb6ee3f44bd bash
[root@97d32845846e /]# yum -y install wget
[root@97d32845846e /]# cd /etc/yum.repos.d/
[root@97d32845846e yum.repos.d]# ls
CentOS-Base.repo CentOS-Debuginfo.repo CentOS-Sources.repo CentOS-fasttrack.repo
CentOS-CR.repo CentOS-Media.repo CentOS-Vault.repo CentOS-x86_64-kernel.repo
[root@97d32845846e yum.repos.d]# rm -f *
[root@97d32845846e yum.repos.d]# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@97d32845846e yum.repos.d]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@97d32845846e yum.repos.d]# ll
total 8
-rw-r--r-- 1 root root 2523 Aug 4 2022 CentOS-Base.repo
-rw-r--r-- 1 root root 664 Aug 4 2022 epel.repo
2.2.2 yum安装并配置nginx
[root@97d32845846e ~]# yum -y install nginx
[root@97d32845846e ~]# yum -y install vim pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop # 安装常用命令
2.2.3 关闭nginx后台运行
注意Nginx默认是后台运行的,但Docker需要其在前台运行,否则直接退出容器。配置文件中添加daemon off;关闭后台运行。另外可以通过Dockerfile配置CMD命令实现。
[root@97d32845846e ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
daemon off; # 添加这一行
……省略 部分内容
2.2.4 自定义web页面
[root@97d32845846e ~]# cd /usr/share/nginx/
[root@97d32845846e nginx]# echo 'Docker Yum Nginx' > /usr/share/nginx/index.html
[root@97d32845846e nginx]# mv index.html html/
[root@97d32845846e nginx]# cd html/
[root@97d32845846e html]# cat index.html
Docker Yum Nginx
2.2.5 提交为镜像
[root@test01 ~]# docker commit 97d32845846e centos-nginx:v1
sha256:dc087527a3af62d4e1f0fe7db3200753cc1181c5ffb083476666cef99c95f371
[root@test01 ~]# docker images |grep centos-nginx
centos-nginx v1 dc087527a3af 10 seconds ago 546MB
2.2.6 基于刚打的镜像启动一个容器
[root@test01 ~]# docker images |grep centos-nginx
centos-nginx v1 dc087527a3af 10 seconds ago 546MB
[root@test01 ~]# docker run -d -p 88:80 --name my-centos-nginx dc087527a3af /usr/sbin/nginx
1193b5c9e5ed217687589b83b0be17da4cb697a3f22cc0ee9017cf23143e9e1a
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1193b5c9e5ed dc087527a3af "/usr/sbin/nginx" 3 seconds ago Up 2 seconds 0.0.0.0:88->80/tcp my-centos-nginx
2.2.7 访问测试
2.3 基于dockerfile制作编译版nginx 1.16.1镜像
Dockerfile官方文档:https://docs.docker.com/engine/reference/builder/
DockerFile可以说是一种可以被Docker程序解释的脚本,DockerFile是由一条条的命令组成的,每条命令对应linux下面的一条命令,Docker程序将这些DockerFile指令再翻译成真正的linux命令,其有自己的书写方式和支持的命令,Docker程序读取DockerFile 并根据指令生成Docker镜像,相比手动制作镜像的方式,DockerFile更能直观的展示镜像是怎么产生的,有了写好的各种各样DockerFile文件,当后期某个镜像有额外的需求时,只要在之前的DockerFile添加或者修改相应的操作即可重新生成新的Docke镜像,避免了重复手动制作镜像的麻烦,具体如下:
官方文档:https://docs.docker.com/engine/reference/builder/
FROM #在整个dockfile文件中,除了注释之外的第一行,要是from,用于指定父镜像
ADD #用于添加宿主机本地的文件、目录、压缩等资源到镜像里面去,会自动解压tar.gz格式的压缩包,但是无法自动解压zip包(因为tar命令自带的,zip需要额外安装)。
COPY #用于添加宿主机本地的文件、目录、压缩等资源到镜像里面去。
ENV # 设置整个容器的环境变量
EXPOSE # “声明” 映射哪些端口到宿主机上(只是声明,我当它为一个注释说明)
RUN # 执行shell命令,但是一定得是非交互式的方式来执行shell命令
LABEL # 设置镜像的属性标签(如作者信息)
MAINTAINER # 设置镜像的属性标签(该方式可能废弃,推荐使用LABEL)
USER # 指定容器运行中使用的用户(不指定的话就会使用父镜像的默认用户)
VOLUME # 声明一个具有指定名称的挂载点(容器中不存在会自动创建),run的时候没有-v的话,会自动在宿主机的目录下生成一个匿名数据卷。注意,如果任何构建步骤在声明卷后更改了卷中的数据,那么这些更改将被丢弃。(就是被VOLUME声明的目录,后续就不能修改了,就算有修改的步骤,在dockerfile中也不会被执行)
WORKDIR # 定义进入容器时的工作目录
CMD # 启动容器时使用的默认命令或脚本(可以被传参覆盖)
ENTRYPOINT # 启动容器时使用的默认命令或脚本,结合CMD使用时,CMD设置的值会变成ENTRYPOINT的参数
2.3.1 下载镜像并初始化系统
[root@test01 ~]# docker pull centos:centos7.9.2009
[root@test01 ~]# docker run -itd --name my-centos centos:centos7.9.2009 bash
ea363d152b2dcc6d1755b4c1d28f79bf740e7959bf3043404dd6632210129141
[root@test01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea363d152b2d centos:centos7.9.2009 "bash" 4 seconds ago Up 3 seconds my-centos
[root@test01 ~]# cd /opt/
[root@test01 opt]# mkdir -p dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}} #目录结构按照业务类型或系统类型等方式划分,方便后期镜像比较多的时候进行分类。
[root@test01 opt]# cd dockerfile/
[root@test01 dockerfile]# tree
.
├── system
│ ├── centos
│ ├── redhat
│ └── ubuntu
└── web
├── apache
├── jdk
├── nginx
└── tomcat
[root@test01 ~]# cd /opt/dockerfile/web/nginx/
[root@test01 nginx]# mkdir all-in-one
[root@test01 nginx]# cd all-in-one
[root@test01 all-in-one]#
2.3.2 编写Dockerfile
docker build的过程中,会启动一个临时容器,来根据dockerfile中的内容执行操作,执行完后,把该容器提交成为一个镜像。
[root@test01 all-in-one]# cat Dockerfile
#base image
FROM centos:centos7.9.2009
LABEL maintainer="xts 1184964356@qq.com" # 作者信息,可写可不写
RUN yum -y install epel-release && yum -y install vim wget tree lrzsz gcc gcC-C++ automake pcrepcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
# 测试
[root@test01 all-in-one]# docker build -t nginx-web-v1:1.16.1 . # -t:设置镜像的名称和标签
[root@test01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx-web-v1 1.16.1 3f8b5422b301 3 minutes ago 595MB
[root@test01 ~]# docker history nginx-web-v1:1.16.1
IMAGE CREATED CREATED BY SIZE COMMENT
3f8b5422b301 9 minutes ago /bin/sh -c yum -y install epel-release && yu… 391MB
4e2685c70d97 12 minutes ago /bin/sh -c #(nop) LABEL maintainer=xts 1184… 0B
eeb6ee3f44bd 18 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 18 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 18 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
# 下载nginx源码包
[root@test01 all-in-one]# wget http://nginx.org/download/nginx-1.16.1.tar.gz
# 继续编写dockerfile
[root@test01 all-in-one]# tail -1 Dockerfile
ADD nginx-1.16.1.tar.gz /usr/local/src/ # 再次构建的时候,docker会检测到上面是已经执行过的,就直接从add开始执行了
# 再测试构建
[root@test01 all-in-one]# docker build -t nginx-web-v2:1.16.1 .
Sending build context to Docker daemon 1.077MB
……省略部分输出
Successfully built cba4b82c48bf
Successfully tagged nginx-web-v2:1.16.1
[root@test01 ~]# docker run -it --rm nginx-web-v2:1.16.1 bash
[root@58823fe3b73f /]# ll /usr/local/src/
total 1012
-rw-r--r-- 1 root root 1032630 Aug 13 2019 nginx-1.16.1 # 这里可以看到tar包已经被ADD解压了
[root@58823fe3b73f /]# exit
exit
# 继续编写dockerfile
[root@test01 all-in-one]# tail -1 Dockerfile
RUN cd /usr/local/src/nginx-1.16.1 && ./configure --prefix=/apps/nginx --with-http_sub_module && make && make install
# 再次构建
[root@test01 all-in-one]# docker build -t nginx-web-v3:1.16.1 .
# 测试
[root@test01 all-in-one]# docker run -it --rm nginx-web-v3:1.16.1 bash
[root@d0acc899d983 /]# cd apps/
[root@d0acc899d983 apps]# ls
nginx
[root@d0acc899d983 apps]# cd nginx/
[root@d0acc899d983 nginx]# ls
conf html logs sbin
[root@d0acc899d983 nginx]# ./sbin/nginx
[root@d0acc899d983 nginx]# ss -lntup |grep 80
tcp LISTEN 0 128 *:80 *:* users:(("nginx",pid=19,fd=6
# 新开一个窗口
[root@test01 ~]# curl -I localhost:8088
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Tue, 21 Mar 2023 07:04:16 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 21 Mar 2023 03:25:25 GMT
Connection: keep-alive
ETag: "641923a5-264"
Accept-Ranges: bytes
# 自定义nginx配置文件
[root@test01 all-in-one]# docker run -itd nginx-web-v3:1.16.1 bash
7ced74ca645095596958f71dfaceb06e23922c9ded6ce112c54657cfbbf91c85
[root@test01 all-in-one]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ced74ca6450 nginx-web-v3:1.16.1 "bash" 2 seconds ago Up 2 seconds quizzical_hopper
[root@test01 all-in-one]# docker cp 7ced74ca6450:/apps/nginx/conf/nginx.conf ./nginx.conf
[root@test01 all-in-one]# docker cp 7ced74ca6450:/apps/nginx/html/index.html ./index.html
[root@test01 all-in-one]# ll -rt
total 1064
-rw-r--r-- 1 root root 1032630 Aug 14 2019 nginx-1.16.1.tar.gz
-rw------- 1 root root 40920 Mar 20 17:57 nohup.out
-rw-r--r-- 1 root root 411 Mar 21 16:24 Dockerfile
-rw-r--r-- 1 root root 2656 Mar 21 16:25 nginx.conf
-rw-r--r-- 1 root root 612 Mar 21 16:25 index.html
# 自定义配置文件和html文件
[root@test01 all-in-one]# cat nginx.conf
user nginx; # 修改
worker_processes auto; # 修改
location / {
root /data/nginx/html; # 修改
index index.html index.htm;
}
# 生成测试页面
[root@test01 all-in-one]# echo 'Docker Nginx Test' > index.html
# 编辑dockerfile
[root@test01 all-in-one]# tail -4 Dockerfile
RUN useradd nginx # 创建nginx所需用户
ADD nginx.conf /apps/nginx/conf/nginx.conf # 复制宿主机上修改过的nginx配置文件到容器中,文件名可以不指定,会直接覆盖源文件
ADD index.html /data/nginx/html/ # 复制宿主机上的html文件到容器中,注意html/ 这里一定要写/,不然add index.html会把html目录替换成一个文件
# 构建镜像
[root@test01 all-in-one]# docker build -t nginx-web-v4:1.16.1 .
[root@test01 ~]# docker images |grep v4
nginx-web-v4 1.16.1 67ce34721588 56 seconds ago 618M
# 启动容器
[root@test01 all-in-one]# docker run -it --rm -p 8088:80 nginx-web-v4:1.16.1
[root@ab57914facd8 /]# id nginx
uid=1000(nginx) gid=1000(nginx) groups=1000(nginx)
[root@ab57914facd8 /]# tree /data
/data
`-- nginx
`-- html
`-- index.html
2 directories, 1 file
[root@ab57914facd8 /]# /apps/nginx/sbin/nginx
# 再开一个窗口访问测试
[root@test01 all-in-one]# curl localhost:8088
Docker Nginx Test
# 再次编辑dockerfile
[root@test01 all-in-one]# tail -5 Dockerfile
EXPOSE 80 443 # 声明端口
CMD /apps/nginx/sbin/nginx;tail -f /etc/hosts # 先让nginx启动,然后使用tail命令,使得有进程是前台运行的,这样容器就不会退出
# 构建镜像
[root@test01 all-in-one]# docker build -t nginx-web-v4:1.16.1 .
# 启动测试
[root@test01 all-in-one]# docker run -d -p 8088:80 nginx-web-v4:1.16.1
a59034b756aa2a307732f7f177ad4b15fe6263e1d21d9d3ca72ffda447affc9c
[root@test01 all-in-one]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a59034b756aa nginx-web-v4:1.16.1 "tail -f /etc/hosts" 5 seconds ago Up 4 seconds 443/tcp, 0.0.0.0:8088->80/tcp recursing_aryabhata
[root@test01 all-in-one]# docker exec -it 8409b9b27a64 bash
[root@8409b9b27a64 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:01 pts/0 00:00:00 /bin/sh -c /apps/nginx/sbin/nginx;tail -f /etc/hosts # 初始化的进程
root 7 1 0 10:01 ? 00:00:00 nginx: master process /apps/nginx/sbin/nginx
nginx 8 7 0 10:01 ? 00:00:00 nginx: worker process
root 9 1 0 10:01 pts/0 00:00:00 tail -f /etc/hosts
nginx 10 7 0 10:01 ? 00:00:00 nginx: worker process
root 11 0 1 10:02 pts/1 00:00:00 bash
root 26 11 0 10:02 pts/1 00:00:00 ps -ef
[root@test01 ~]# curl localhost:8088
Docker Nginx Test
# 编辑dockerfile,使用nginx进程命令前台运行
[root@test01 all-in-one]# tail -1 Dockerfile
CMD ["/apps/nginx/sbin/nginx","-g","daemon off;"]
# 构建
[root@test01 all-in-one]# docker build -t nginx-web-v4:1.16.1 .
# 运行
[root@test01 all-in-one]# docker run -d -p 8088:80 nginx-web-v4:1.16.1
752d327d2e2dc9bdcc634aeeb40c588368ccb8e484de6ac0aaf716c00bbe9718
[root@test01 all-in-one]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
752d327d2e2d nginx-web-v4:1.16.1 "/apps/nginx/sbin/ng…" 2 seconds ago Up 2 seconds 443/tcp, 0.0.0.0:8088->80/tcp cranky_mccarthy
[root@test01 all-in-one]# docker exec -it 752d327d2e2d bash
[root@752d327d2e2d /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:08 ? 00:00:00 nginx: master process /apps/nginx/sbin/nginx -g daemon off; # 初始化进程
nginx 6 1 0 10:08 ? 00:00:00 nginx: worker process
nginx 7 1 0 10:08 ? 00:00:00 nginx: worker process
root 8 0 1 10:10 pts/0 00:00:00 bash
root 23 8 0 10:10 pts/0 00:00:00 ps -ef
# 测试
[root@test01 all-in-one]# curl localhost:8088
Docker Nginx Test
# 最终dockerfile
[root@test01 all-in-one]# cat Dockerfile
#base image
FROM centos:centos7.9.2009
LABEL maintainer="xts 1184964356@qq.com"
RUN yum -y install epel-release && yum -y install vim wget tree lrzsz gcc gcC-C++ automake pcrepcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
ADD nginx-1.16.1.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.16.1 && ./configure --prefix=/apps/nginx --with-http_sub_module && make && make install
RUN useradd nginx
ADD nginx.conf /apps/nginx/conf/nginx.conf
ADD index.html /data/nginx/html/
EXPOSE 80 443
#CMD /apps/nginx/sbin/nginx;tail -f /etc/hosts
CMD ["/apps/nginx/sbin/nginx","-g","daemon off;"] # 注意:这里的daemon off可以直接加到nginx.conf中,CMD这就变成CMD ["/apps/nginx/sbin/nginx"]
# 使用脚本的方式来启动
## 使用脚本 很多地方可以自己控制
[root@test01 all-in-one]# cat run_nginx.sh
#!/bin/bash
/apps/nginx/sbin/nginx -g "daemon off;" # 在启动之前 可以定义很多其他需要的操作
# 编辑dockerfile
[root@test01 all-in-one]# cat Dockerfile
#base image
FROM centos:centos7.9.2009
LABEL maintainer="xts 1184964356@qq.com"
RUN yum -y install epel-release && yum -y install vim wget tree lrzsz gcc gcC-C++ automake pcrepcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
ADD nginx-1.16.1.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.16.1 && ./configure --prefix=/apps/nginx --with-http_sub_module && make && make install
RUN useradd nginx
ADD nginx.conf /apps/nginx/conf/nginx.conf
ADD index.html /data/nginx/html/
ADD run_nginx.sh /apps/nginx/sbin/run_nginx.sh # 修改部分
RUN chmod +x /apps/nginx/sbin/run_nginx.sh # 修改部分
EXPOSE 80 443
CMD ["run_nginx.sh"] # 修改部分
# 构建并运行
[root@test01 all-in-one]# docker build -t nginx-web-v4:1.16.1 .
[root@test01 all-in-one]# docker run -d -p 8088:80 nginx-web-v4:1.16.1
[root@test01 all-in-one]# curl localhost:8088
Docker Nginx Test
2.4 容器运行注意事项
2.4.1 关于容器运行的
运行容器的时候,一定是要有一个进程在容器tty终端前台运行的。
方式:
(1)命令方式
tail -f /etc/hosts # 这种方式可以一直在前台运行
(2)服务进程
如nginx配置中,关闭默认的后台运行,使其前台运行,daemon off;
(3)脚本
通过编写脚本,让进程前台运行
2.4.2 关于CMD的
CMD有两种用法:
用法1:CMD 命令1;命令2;命令N # 这种不加[ ],适合多条命令在一个CMD中执行
用法2:CMD [“命令”, “参数1”, “参数2”] # 这种用法会将 command 和其后面的参数视为一个数组,它不会使用 shell 命令解析器,而是直接执行,更加安全和高效。
3. 镜像分层构建
3.1 自定义Tomcat业务镜像
基于官方提供的 centos、debain、ubuntu、alpine等基础镜像构建JDK(Java环境),然后再基于自定义的JDK 镜像构建出业务需要的 tomcat 镜像。
3.1.1 使用CentOS基础镜像
3.1.1.1 配置基础镜像与基本环境
[root@test01 ~]# cd /opt/dockerfile/system/centos/
[root@test01 centos]# docker images |grep centos
centos-nginx v1 dc087527a3af 45 hours ago 546MB
centos centos7.9.2009 eeb6ee3f44bd 18 months ago 204MB
[root@test01 centos]# cat Dockerfile
# 第一层
FROM centos:centos7.9.2009
LABEL maintainer="xts 1184964356@qq.com"
# 第二层
RUN rm -fr /etc/yum.repos.d/* && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum clean all && yum makecache && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && yum clean all && yum makecache && \
yum -y install vim wget tree lrzsz gcc gcC-C++ automake pcrepcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop && groupadd www -g 2023 && useradd www -u 2023 -g www
# 准备构建镜像相关的脚本
[root@test01 centos]# cat build-command.sh
#!/bin/bash
docker build -t centos-base:7.9.2009 .
# 执行脚本 构建镜像
[root@test01 centos]# sh build-command.sh
[root@test01 centos]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-base 7.9.2009 dd4f9e4b93a0 26 minutes ago 949MB
3.1.1.2 构建jdk镜像
[root@test01 dockerfile]# cd web/jdk/
[root@test01 jdk]# ls
[root@test01 jdk]# mkdir jdk-8u361
[root@test01 jdk]# cd jdk-8u361
[root@test01 jdk-8u361]# pwd
/opt/dockerfile/web/jdk/jdk-8u361
# 上传jdk文件
[root@test01 jdk-8u361]# ll -h
total 133M
-rw-r--r-- 1 root root 133M Mar 22 20:26 jdk-8u361-linux-x64.tar.gz
# 复制基础镜像中的profile文件,添加对应环境变量
[root@test01 jdk-8u361]# docker run -dit centos-base:7.9.2009 bash
7ea2cb225a0b791e95881721c9a4bd5d3aeba1ddf74d6075f1f717cf023653ac
[root@test01 jdk-8u361]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ea2cb225a0b centos-base:7.9.2009 "bash" 3 seconds ago Up 2 seconds optimistic_tesl
[root@test01 jdk-8u361]# docker cp 7ea2cb225a0b:/etc/profile ./
[root@test01 jdk-8u361]# ll -rt
total 135520
-rw-r--r-- 1 root root 1819 Apr 1 2020 profile
[root@test01 jdk-8u361]# tail -4 profile
export JAVA_HOME=/usr/local/jdk
export TOMCAT_HOME=/apps/tomcat
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$TOMCAT_HOME/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
# 编辑dockerfile
[root@test01 jdk-8u361]# tail -1 Dockerfile
ADD profile /etc/profile
# 编辑构建脚本进行构建
[root@test01 jdk-8u361]# cat build-command.sh
#!/bin/bash
docker build -t centos-jdk-base:8u361 .
[root@test01 jdk-8u361]# sh build-command.sh
[root@test01 jdk-8u361]# docker images |grep centos-jdk-base
centos-jdk-base 8u361 c6acb95cad1f 30 seconds ago 1.29GB
# 运行容器检查配置
[root@test01 jdk-8u361]# docker run -it --rm centos-jdk-base:8u361 bash
[root@80e83a6cdf48 /]# tail -4 /etc/profile
export JAVA_HOME=/usr/local/jdk
export TOMCAT_HOME=/apps/tomcat
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$TOMCAT_HOME/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
# 注意点
[root@56b659c7d483 /]# java
bash: java: command not found
[root@56b659c7d483 /]# su - www
[www@56b659c7d483 ~]$ java -version
java version "1.8.0_361"
Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)
# 为什么上面java命令root没法使用,www用户确能使用,是因为容器在启动时,root用户不会去读profile文件,除非手动source一下。
# 编辑dockerfile,为root用户添加java环境变量
[root@test01 jdk-8u361]# tail -4 Dockerfile
ENV JAVA_HOME /usr/local/jdk
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin
# 构建镜像
[root@test01 jdk-8u361]# sh build-command.sh
[root@test01 jdk-8u361]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-jdk-base 8u361 765d45445897 13 seconds ago 1.29GB
# 启动容器检查配置
[root@test01 jdk-8u361]# docker run -it --rm centos-jdk-base:8u361 bash
[root@f93ada792cc8 /]# java -version
java version "1.8.0_361"
Java(TM) SE Runtime Environment (build 1.8.0_361-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)
# 修改容器时间,同步宿主机时间(这一步可以在构建基础镜像的时候做也行)
[root@0cbdbb93c628 /]# date #这是修改前的容器时间,需要加8小时才能对应现在的北京时间
Thu Mar 23 03:30:54 UTC 2023
[root@test01 jdk-8u361]# tail -1 Dockerfile
RUN rm -fr /etc/localtime && ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 构建镜像 查看时区
[root@test01 jdk-8u361]# !sh
sh build-command.sh
[root@test01 jdk-8u361]# docker run -it --rm centos-jdk-base:8u361 bash
[root@5552b9c8825d /]# date
Thu Mar 23 11:37:51 CST 2023
[root@5552b9c8825d /]# exit
exit
3.1.2 从jdk镜像构建tomcat 8镜像
基于自定义的JDK基础镜像,构建出通用的自定义Tomcat基础镜像,此镜像后期会被多个业务的多个服务共同引用(相同的JDK版本和Tomcat版本)。
3.1.2.1 下载tomcat包
[root@test01 tomcat]# wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.87/bin/apache-tomcat-8.5.87.tar.gz
[root@test01 tomcat]# ll -h
total 11M
-rw------- 1 root root 11M Mar 23 13:42 apache-tomcat-8.5.87.tar.gz
3.1.2.2 编辑dockerfile
[root@test01 tomcat]# cat Dockerfile
# tomcat base image
FROM centos-jdk-base:8u361
LABEL maintainer="xts 1184964356@qq.com"
ADD apache-tomcat-8.5.87.tar.gz /apps
RUN ln -sv /apps/apache-tomcat-8.5.87 /apps/tomcat
3.1.2.3 编写构建脚本
[root@test01 tomcat]# cat build-command.sh
#!/bin/bash
docker build -t tomcat-centos-base:v8.5.87 .
3.1.2.4 构建镜像,检查配置
[root@test01 tomcat]# sh build-command.sh
[root@test01 tomcat]# docker run -it --rm tomcat-centos-base:v8.5.87 bash
[root@44d9e0653658 /]# ll /apps/
total 0
drwxr-xr-x 9 root root 220 Mar 23 14:39 apache-tomcat-8.5.87
lrwxrwxrwx 1 root root 26 Mar 23 14:37 tomcat -> /apps/apache-tomcat-8.5.87
[root@44d9e0653658 /]# ll /apps/tomcat/
total 128
-rw-r----- 1 root root 19992 Feb 28 03:32 BUILDING.txt
-rw-r----- 1 root root 6210 Feb 28 03:32 CONTRIBUTING.md
-rw-r----- 1 root root 57011 Feb 28 03:32 LICENSE
-rw-r----- 1 root root 1726 Feb 28 03:32 NOTICE
-rw-r----- 1 root root 3398 Feb 28 03:32 README.md
-rw-r----- 1 root root 7139 Feb 28 03:32 RELEASE-NOTES
-rw-r----- 1 root root 16505 Feb 28 03:32 RUNNING.txt
drwxr-x--- 2 root root 4096 Mar 23 14:39 bin
drwx------ 2 root root 238 Mar 23 14:39 conf
drwxr-x--- 2 root root 4096 Mar 23 14:39 lib
drwxr-x--- 2 root root 6 Feb 28 03:32 logs
drwxr-x--- 2 root root 30 Mar 23 14:39 temp
drwxr-x--- 7 root root 81 Mar 23 14:39 webapps
drwxr-x--- 2 root root 6 Feb 28 03:32 work
3.1.3 构建业务镜像一
到业务镜像这一步,就可以把开发给的代码编译后,放到基础镜像中运行了。
[root@test01 tomcat]# mkdir tomcat-base-8.5.87
[root@test01 tomcat]# mv * tomcat-base-8.5.87
mv: cannot move ‘tomcat-base-8.5.87’ to a subdirectory of itself, ‘tomcat-base-8.5.87/tomcat-base-8.5.87’
[root@test01 tomcat]# ll tomcat-base-8.5.87/
total 10408
-rw------- 1 root root 10645961 Feb 28 03:55 apache-tomcat-8.5.87.tar.gz
-rw-r--r-- 1 root root 57 Mar 23 14:02 build-command.sh
-rw-r--r-- 1 root root 200 Mar 23 14:37 Dockerfile
3.1.3.1 按服务名创建目录
[root@test01 tomcat]# mkdir tomcat-app1 tomcat-app2
[root@test01 tomcat]# ll
total 0
drwxr-xr-x 2 root root 6 Mar 23 15:53 tomcat-app1
drwxr-xr-x 2 root root 6 Mar 23 15:53 tomcat-app2
drwxr-xr-x 2 root root 83 Mar 23 15:51 tomcat-base-8.5.87
[root@test01 tomcat]# cd tomcat-app1
[root@test01 tomcat-app1]#
3.1.3.2 编辑tomcat配置文件
[root@test01 tomcat-app1]# docker run -itd tomcat-centos-base:v8.5.87 bash
080b5669e5e76f519d350a65ec6f52ca71e673b4c63cd2ccb0ef0a385a892091
[root@test01 tomcat-app1]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
080b5669e5e7 tomcat-centos-base:v8.5.87 "bash" 3 seconds ago Up 1 second serene_lalande
[root@test01 tomcat-app1]# docker exec -it 080b5669e5e7 bash
[root@080b5669e5e7 /]# ll /apps/tomcat/conf/server.xml
-rw------- 1 root root 7580 Feb 28 03:32 /apps/tomcat/conf/server.xml
[root@080b5669e5e7 /]# exit
exit
[root@test01 tomcat-app1]# docker cp 080b5669e5e7:/apps/tomcat/conf/server.xml ./
[root@test01 tomcat-app1]# ll -rt
total 16
-rw------- 1 root root 7580 Feb 28 03:32 server.xml
[root@test01 tomcat-app1]# grep "Host name" server.xml
<Host name="localhost" appBase="/data/tomcat/webapps" # 修改appBase为自定义的目录
3.1.3.3 编辑dokerfile
[root@test01 tomcat-app1]# cat Dockerfile
# tomcat app 1 image
FROM tomcat-centos-base:v8.5.87
LABEL maintainer="xts 1184964356@qq.com"
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
ADD server.xml /apps/tomcat/conf/server.xml
ADD memtest.war /data/tomcat/webapps
RUN chown -R www.www /data /apps
EXPOSE 8080 8443
CMD ["/apps/tomcat/bin/run_tomcat.sh"]
3.1.3.4 编辑启动脚本
[root@test01 tomcat-app1]# cat run_tomcat.sh
#!/bin/bash
# 下面启动方式二选一
## 启动方式1
su - www -c "/apps/tomcat/bin/catalina.sh run" # 该方式前台运行(普通用户)
## 启动方式2
#su - www -c "/apps/tomcat/bin/catalina.sh start" # 普通用户
#su - www -c "tail -f /etc/hosts"
3.1.3.5 构建镜像并运行
[root@test01 tomcat-app1]# cat build-command.sh
#!/bin/bash
docker build -t tomcat-app1:v1 .
[root@test01 tomcat-app1]# sh build-command.sh
[root@test01 tomcat-app1]# docker images |grep tomcat-app1
tomcat-app1 v1 417f14852f9a 14 seconds ago 1.31GB
[root@test01 tomcat-app1]# docker run -d -p 8080:8080 tomcat-app1:v1
3.1.3.6 访问测试
3.1.4 构建业务镜像二
3.1.4.1 准备首页文件
[root@test01 tomcat]# cd tomcat-app2/
[root@test01 tomcat-app2]# ls
[root@test01 tomcat-app2]# mkdir myapp
[root@test01 tomcat-app2]# cd myapp
[root@test01 myapp]# echo '<h1>Docker Test App2</h1>' > index.jsp
[root@test01 myapp]# cat index.jsp
<h1>Docker Test App2</h1>
[root@test01 tomcat-app2]# tar zcvf myapp.tar.gz myapp
myapp/
myapp/index.jsp
3.1.4.2 准备构建脚本
[root@test01 tomcat-app2]# cp ../tomcat-app1/build-command.sh ./
[root@test01 tomcat-app2]# vim build-command.sh
[root@test01 tomcat-app2]# cat build-command.sh
#!/bin/bash
docker build -t tomcat-app2:v1 .
3.1.4.3 准备dockerfile
[root@test01 tomcat-app2]# cp ../tomcat-app1/Dockerfile ./
[root@test01 tomcat-app2]# vim Dockerfile
[root@test01 tomcat-app2]# cat Dockerfile
# tomcat app 1 image
FROM tomcat-centos-base:v8.5.87
LABEL maintainer="xts 1184964356@qq.com"
ADD myapp.tar.gz /data/tomcat/webapps/ # 修改的部分
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
ADD server.xml /apps/tomcat/conf/server.xml
RUN chown -R www.www /data /apps
EXPOSE 8080 8443
CMD ["/apps/tomcat/bin/run_tomcat.sh"]
3.1.4.4 准备tocmat配置文件和启动脚本
[root@test01 tomcat-app2]# cp ../tomcat-app1/run_tomcat.sh ./
[root@test01 tomcat-app2]# cp ../tomcat-app1/server.xml ./
3.1.4.5 构建镜像并运行
[root@test01 tomcat-app2]# sh build-command.sh
[root@test01 tomcat-app2]# docker run -d -p 8081:8080 tomcat-app2:v1
3.1.4.6 访问测试
3.2 构建haporxy镜像
下载地址:https://www.haproxy.org/#down
3.2.1 准备dockerfile
[root@test01 ~]# cd /opt/dockerfile/web/
[root@test01 web]# mkdir haporxy
[root@test01 web]# cd haporxy
[root@test01 haporxy]# cat Dockerfile
# haproxy image
FROM centos-base:7.9.2009
RUN yum install -y libtermcap-devel ncurses-devel libevent-devel readline-devel gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdmp wget ntpdate
3.2.3 准备构建脚本
[root@test01 haporxy]# cat build-command.sh
#!/bin/bash
docker build -t haproxy:v2.2.11 .
3.2.4 构建测试
[root@test01 haporxy]# sh build-command.sh
……省略部分输出
Successfully built 1524cc97aa69
Successfully tagged haproxy:v2.2.11
3.2.5 编辑dockerfile
[root@test01 haporxy]# tail -3 Dockerfile
ADD haproxy-2.2.11.tar.gz /usr/local/src/
RUN cd /usr/local/src/haproxy-2.2.11 && make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/apps/haproxy && make install PREFIX=/apps/haproxy && cp haproxy /usr/sbin/ && mkdir /apps/haproxy/run
3.2.6 构建测试
[root@test01 haporxy]# sh build-command.sh
……省略部分输出
Successfully built 421003565e9f
Successfully tagged haproxy:v2.2.11
3.2.7 运行容器检查配置
[root@test01 haporxy]# docker run -it --rm haproxy:v2.2.11 bash
[root@1bc902da71aa /]# ll /apps/
total 0
drwxr-xr-x 5 root root 42 Mar 24 06:14 haproxy
[root@1bc902da71aa /]# ll /apps/haproxy/
total 0
drwxr-xr-x 3 root root 21 Mar 24 06:14 doc
drwxr-xr-x 2 root root 21 Mar 24 06:14 sbin
drwxr-xr-x 3 root root 17 Mar 24 06:14 share
[root@1bc902da71aa /]# /apps/haproxy/sbin/haproxy -v
HA-Proxy version 2.2.11-c58c4e4 2021/03/18 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2025.
Known bugs: http://www.haproxy.org/bugs/bugs-2.2.11.html
Running on: Linux 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64
[root@1bc902da71aa /]# exit
exit
3.2.8 编辑服务启动脚本
[root@test01 haporxy]# cat run_haproxy.sh
#!/bin/bash
/apps/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
3.2.9 准备haproxy配置文件
[root@test01 haporxy]# cat haproxy.cfg
[root@test01 haporxy]# cat haproxy.cfg
global
chroot /apps/haproxy
uid 99
gid 99
daemon
nbproc 1
pidfile /apps/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info
defaults
option http-keep-alive
option forwardfor
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:123456
listen web_port
bind 0.0.0.0:80
mode http
log global
balance roundrobin
server app1 172.17.0.2:8080 check inter 3000 fall 2 rise 5 # 业务容器1(因为默认情况下,容器之间是可以通讯的,所以可以直接写容器IP和端口)
server app2 172.17.0.3:8080 check inter 3000 fall 2 rise 5 # 业务容器2(因为默认情况下,容器之间是可以通讯的,所以可以直接写容器IP和端口)
3.2.10 编辑dockerfile
[root@test01 haporxy]# chmod +x run_haproxy.sh
[root@test01 haporxy]# tail -4 Dockerfile
ADD run_haproxy.sh /apps/haproxy/bin/run_haproxy.sh
ADD haproxy.cfg /etc/haproxy/haproxy.cfg
CMD ["/apps/haproxy/bin/run_haproxy.sh"]
3.2.11 构建镜像
[root@test01 haporxy]# sh build-command.sh
…………省略部分输出
Successfully built cb9bcb3e5858
Successfully tagged haproxy:v2.2.11
3.2.12 启动检查
[root@test01 haporxy]# docker run -d -p 80:80 -p 9999:9999 haproxy:v2.2.11
d70fd3b35e4271fc0d56e960fa7d2a8d6bc065732c07164be03b59c694ba0052
[root@test01 haporxy]# docker exec -it d70fd3b35e4271fc0d56e960fa7d2a8d6bc065732c07164be03b59c694ba0052 bash
[root@d70fd3b35e42 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 17:59 ? 00:00:00 /bin/bash /apps/haproxy/bin/run_haproxy.sh
nobody 8 1 0 17:59 ? 00:00:00 /apps/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg # haproxy启动进程
root 9 1 0 17:59 ? 00:00:00 tail -f /etc/hosts
root 11 0 0 17:59 pts/0 00:00:00 bash
root 26 11 0 17:59 pts/0 00:00:00 ps -ef
[root@d70fd3b35e42 /]# netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN - # 监听端口
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN - # 监听端口
udp 0 0 0.0.0.0:52349 0.0.0.0:* -
udp 0 0 0.0.0.0:60988 0.0.0.0:* -
3.2.13 访问测试
访问status页面
随机访问一个页面
3.3 镜像分层原理之共享镜像层(Dockerfile缓存)
如上图,所有镜像大小加起来已经好几G了,为什么overlay2目录才2.5G,这就是我们要说的共享镜像层。
我们在拉取镜像的时候,经常会看到 Already exists,这是说明拉取的这个镜像中,该层在宿主机上已经存在了。
比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像(因为镜像的ID唯一);同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
如上图,两个容器镜像大小加起来1000M,但是宿主机上实际只会占用700M的存储空间。
因为两个镜像的相同部分是可以共享使用的,也就是dockerfile缓存。
3.4 本章重点总结
3.4.1 必须掌握
(1)熟练掌握dockerfile的指令使用
(2)熟练通过dockerfile制作镜像的各种方式(yum安装、编译安装)
(3)镜像的分层构建
(4)CMD和ENTRYPOINT的区别及使用
3.4.2 扩展
构建haproxy+nginx+tomcat的小型站点的全部镜像,实现动静分离。