上期我们讲解了Docker的一些基础知识以及一些基础用法,接下来我将带领大家继续深入学习Docker。这篇主要讲解Docker的网络模式、Docker的数据管理以及DockerFile的使用。
1.Docker网络模式
1.1 容器之间的互联
1.1.1 通过容器名称互联
即在同一个宿主机上的容器之间可以通过自定义的容器名称相互访问,比如一个业务前端静态页面是使用nginx,动态页面使用的是tomcat,由于容器在启动的时候其内部IP地址是DHCP随机分配的,所以如果通过内部访问的话,自定义名称是相对比较固定的,因此比较适用于此场景。
#1、先创建第一个容器,后续会使用到这个容器的名称]# docker run -it -d --name web01 -p 80:80 nginx#2、查看当前hosts文件内容]# docker exec -it 1502c0a6d361 bashroot@1502c0a6d361:/# cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.2 1502c0a6d361#3、创建第二个容器]# docker run -it -d -p 81:80 --name mynginx-web01 --link web01 nginx#4、查看第二个容器的hosts文件内容]# docker exec -it 1e6f6cc462ed bashroot@1e6f6cc462ed:/# cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.2 web01 1502c0a6d361 #连接的对方容器的ID和容器名称172.17.0.3 1e6f6cc462ed#5、检测通信root@1e6f6cc462ed:/# ping web01PING web01 (172.17.0.2): 56 data bytes64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.311 ms64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.072 ms
1.1.2 通过自定义容器别名互联
上一步骤中,自定义的容器名称可能后期会发生变化,那么一旦名称发生变化,程序之间也要随之发生变化,比如程序通过容器名称进行服务调用,但是容器名称发生变化之后再使用之前的名称肯定是无法成功调用,每次都进行更改的话又比较麻烦,因此可以使用自定义别名的方式来解决,即容器名称可以随意更,只要不更改别名即可,具体操作如下:
#1、通过别名的方式]# docker run -it -d -p 81:80 --name mynginx-web01 --link web01:nginx_server nginx#2、查看当前容器的hosts文件root@67d9c26be254:/# cat /etc/hosts127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.2 nginx_server 1502c0a6d361 web01172.17.0.3 67d9c26be254#3、检查自定义别名通信root@67d9c26be254:/# ping nginx_serverPING nginx_server (172.17.0.2): 56 data bytes64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.064 ms64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.128 ms
1.2 docker网络类型
我们之前通过Docker run创建Docker容器时,可以使用—net选项指定Docker容器的网络模式,Docker默认有四种网络模式:
- Host模式:
通常来说,启动新的Docker容器,都会分配独立的Network Namespace隔离子系统,如果在运行是指定为host模式,那么Docker容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace子系统。 新创建的Docker容器不会创建自己的网卡,不会再虚拟出自己的网卡、IP、网管、路由等信息,而是和宿主机共享IP和端口等信息,其他的软件、目录还是相互独立的,两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是相互隔离的。 - Container模式:
Docker容器网络,Container模式是指定新创建的容器和已存在的某个容器共享一个Network Namespace子系统,而不是和宿主机共享Namespace子系统。
新创建的Docker容器不会创建自己的网卡,不会再虚拟出自己的网卡、IP、网关、路由等信息,而是和指定的Docker容器共享IP和端口等信息,其他的软件、目录还是相互独立的。两个容器除了网络方面相同之外,其他的都是相互之间隔离的。如果依附的Docker容器关闭,新的Docker容器网络也会丢失。 - None模式
None模式和其他模式不同,如果Docker容器使用None模式,Docker容器会拥有自己的Network Namespace子系统,但是Docker引擎并不会为新启动的Docker容器配置任何的网络信息。即新创建的这个容器不会虚拟出自己的网卡、IP、网关、路由等信息。相当于没有任何网络,无法上网。 - Bridge桥接模式
Docker容器的Bridge模式也是Docker默认的网络模式,该模式会为每个容器分配一个Network Namespace子系统,会自动给每个容器虚拟出自己的网卡、IP、网关、路由等信息,无需手工添加,默认创建的Docker容器会统一通过一对veth虚拟网卡,连接到一个虚拟网桥交换机Docker0上,所有的容器的网络加入到一个二层交换机网络里面,即同一宿主机的所有容器之间都是可以相互联通和访问的。
1.3 Docker网络模式端口实战
#1、随机端口[root@docker-100 ~]# docker run -it -d -P nginx3af778185f6bbe4afc9841c99c741e8ac6242b9ea98cfba0444b293d39945d00[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES3af778185f6b nginx "/docker-entrypoint.…" 2 seconds ago Up 1 second 0.0.0.0:32768->80/tcp jolly_archimedes#2、指定端口映射,将宿主机80端口映射到容器的80端口,这个用的最多[root@docker-100 ~]# docker run -it -d -p 80:80 nginx8a1aea370a015106852240af72f8210075bc00615f9886477e560328fb79d608[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES8a1aea370a01 nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp kind_hodgkin说明:docker run -it -d --name nginx-v1 -p 10.0.0.100:80:80:udp nginx #可以以tcp还是以udp起端口,默认是tcp
1.4 docker跨主机互联
跨主机互联是说A宿主机的容器可以访问B主机上的容器,但是前提是保证各宿主机之间的网络是可以相互通信的,然后各容器才可以通过宿主机访问到对方的容器,实现原理是在宿主机做一个网络路由就可以实现A宿主机的容器访问B主机的容器的目的,复杂的网络或者大型的网络可以使用google开源的k8s进行互联。
#1、修改各宿主机网段:docker的默认网段是172.17.0.x/24,而且每个宿主机都是一样的,因此要做路由的前提就是各个主机的网络不能一致,具体如下:# 服务器A更改网段[root@docker-100 ~]# vim /usr/lib/systemd/system/docker.serviceExecStart=/usr/bin/dockerd --insecure-registry 10.0.0.101 --insecure-registry 10.0.0.102 --bip=10.10.0.1/24[root@docker-100 ~]# systemctl daemon-reload[root@docker-100 ~]# systemctl restart docker# 验证网卡[root@docker-100 ~]# ifconfigdocker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500inet 10.10.0.1 netmask 255.255.255.0 broadcast 10.10.0.255inet6 fe80::42:d1ff:fe43:1822 prefixlen 64 scopeid 0x20<link>ether 02:42:d1:43:18:22 txqueuelen 0 (Ethernet)RX packets 138117 bytes 5848474 (5.5 MiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 197357 bytes 582769608 (555.7 MiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# 服务器B更改网段[root@git-110 ~]# vim /usr/lib/systemd/system/docker.serviceExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.20.0.1/24[root@git-110 ~]# systemctl daemon-reload[root@git-110 ~]# systemctl restart docker#验证网卡[root@git-110 ~]# ip ad3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWNlink/ether 02:42:ca:3f:41:12 brd ff:ff:ff:ff:ff:ffinet 10.20.0.1/24 brd 10.20.0.255 scope global docker0valid_lft forever preferred_lft forever#2、在两个宿主机分别启动一个容器# server1:[root@docker-100 ~]# docker run -it -d -p 80:80 nginx bash[root@docker-100 ~]# docker exec -it 5e8e434674e8fb4babe8 bashroot@5e8e434674e8:/# ifconfigeth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 10.10.0.2 netmask 255.255.255.0 broadcast 10.10.0.255ether 02:42:0a:0a:00:02 txqueuelen 0 (Ethernet)RX packets 3888 bytes 9306247 (8.8 MiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 3184 bytes 174239 (170.1 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# server2:[root@git-110 ~]# docker run -it -p 80:80 nginx bashroot@d46c81216eab:/# ifconfigeth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500inet 10.20.0.2 netmask 255.255.255.0 broadcast 10.20.0.255ether 02:42:0a:14:00:02 txqueuelen 0 (Ethernet)RX packets 3993 bytes 9256352 (8.8 MiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 2786 bytes 152416 (148.8 KiB)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0#3、添加静态路由在各宿主机添加静态路由,网关指向对方的IP# server1添加静态路由:[root@docker-100 ~]# route add -net 10.20.0.0/24 gw 10.0.0.2[root@docker-100 ~]# iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPT# ping对方容器IP是否通信:root@5e8e434674e8:/# ping 10.20.0.2PING 10.20.0.2 (10.20.0.2): 56 data bytes64 bytes from 10.20.0.2: icmp_seq=0 ttl=62 time=0.344 ms64 bytes from 10.20.0.2: icmp_seq=1 ttl=62 time=0.279 ms# server2添加静态路由[root@git-110 ~]# route add -net 10.10.0.0/24 gw 10.0.0.100[root@git-110 ~]# iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPT# ping对方容器IP是否通信:root@d46c81216eab:/# ping 10.10.0.2PING 10.10.0.2 (10.10.0.2): 56 data bytes64 bytes from 10.10.0.2: icmp_seq=0 ttl=62 time=2.745 ms64 bytes from 10.10.0.2: icmp_seq=1 ttl=62 time=0.265 ms
2.Docker数据管理
Docker被关闭或者重启,其数据不受影响。但是要删除Docker容器,则其更改将会全部丢失。
存在的问题:
- 存储于联合文件系统中,不易于宿主机访问。
- 容器间数据共享不便。
- 删除容器其数据会丢失。
解决方案:
- 通过挂载数据卷,让容器上的一个或多个目录,和宿主机上的某目录进行关联,实现持久化存储。

2.1 Docker数据管理实战
[root@docker-100 ~]# mkdir -p /data #创建一个data目录[root@docker-100 ~]# cd /data/[root@docker-100 data]# echo "123" >> xujun.txt #创建一个普通文件[root@docker-100 data]# cat xujun.txt123[root@docker-100 ~]# docker run -it -d -v /data/:/data centos bash #运行容器,并挂载宿主机的/data目录至容器中的/data目录a3d28861c65a776042ed276334bcb036c10ac7ed44d766c43b06c3ccf568f2ae[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa3d28861c65a centos "bash" 2 seconds ago Up 2 seconds vibrant_lewin[root@docker-100 ~]# docker exec -it a3d28861c65a bash[root@a3d28861c65a /]# cd /data/[root@a3d28861c65a data]# lsxujun.txt[root@a3d28861c65a data]# cat xujun.txt #我们可以看到有一个xujun.txt这个文件123#这是生产环境中经常用到的方法,宿主机上生成一个目录,然后挂载到对应的容器中。
2.2 Docker数据卷容器
1、如果需要在容器之间共享一些数据,可以使用数据卷容器。
第一种方法:[root@docker-100 ~]# mkdir -p /data #创建一个data目录[root@docker-100 ~]# cd /data/[root@docker-100 data]# echo "123" >> xujun.txt #创建一个普通文件[root@docker-100 data]# cat xujun.txt123[root@docker-100 ~]# docker run -it -d -v /data/:/data centos bash #运行容器,并挂载宿主机的/data目录至容器中的/data目录a3d28861c65a776042ed276334bcb036c10ac7ed44d766c43b06c3ccf568f2ae[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa3d28861c65a centos "bash" 2 seconds ago Up 2 seconds vibrant_lewin[root@docker-100 ~]# docker exec -it a3d28861c65a bash[root@a3d28861c65a /]# cd /data/[root@a3d28861c65a data]# lsxujun.txt[root@a3d28861c65a data]# cat xujun.txt #我们可以看到有一个xujun.txt这个文件123[root@a3d28861c65a data]# exit #退出这个容器exit#在创建一个新的容器[root@docker-100 ~]# docker run -it -d -v /data/:/data centos bash46603d5827801ec9ddb4ccac5f0594e941cac1bb1329bb7563f87ee58875cdf2[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES46603d582780 centos "bash" 12 seconds ago Up 11 seconds distracted_khoranaa3d28861c65a centos "bash" 2 minutes ago Up 2 minutes vibrant_lewin[root@docker-100 ~]# docker exec -it 46603d582780 bash[root@46603d582780 /]# cd /data/[root@46603d582780 data]# lsxujun.txt[root@46603d582780 data]# cat xujun.txt #我们可以看到在新的容器中,也有一个xujun.txt的文件123第二种方法:[root@docker-100 ~]# docker run -it -d -v /data:/data --name centos_v1 centos bash #运行第一个容器,并取名为centos_v19af382c19dec0cc5ad7b5d85e4d7c27f018949d334d170483f8160ff05f9dc0b[root@docker-100 ~]# docker run -it -d --name centos_v2 --volumes-from centos_v1 centos bash #运行第二个容器,并把centos_v1挂载至被共享的容器中dd95713fbbd50f558199d804832be2309e1334932b7891c18afcd5916dda361e[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESdd95713fbbd5 centos "bash" 8 seconds ago Up 8 seconds centos_v29af382c19dec centos "bash" About a minute ago Up About a minute centos_v1[root@docker-100 ~]# docker exec -it 9af382c19dec bash #进入第一个容器查看[root@9af382c19dec /]# cd /data/[root@9af382c19dec data]# lsxujun.txt[root@9af382c19dec data]# cat xujun.txt123[root@9af382c19dec data]# exitexit[root@docker-100 ~]# docker exec -it dd95713fbbd5 bash #进入第二个容器查看[root@dd95713fbbd5 /]# cd /data/[root@dd95713fbbd5 data]# lsxujun.txt[root@dd95713fbbd5 data]# cat xujun.txt #可以看到数据和第一个容器中的数据一模一样123#注释:--name:指定新的容器名字# --volumes-from:创建共享容器# sick_ramanujan:要共享的容器# Centos:被共享的容器
3 Docker传递环境变量
[root@docker-200 ~]# docker run --rm -p 81:80 -e NAME=xujun 313ec0a602bc printenvPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=f652de4d43a9NAME=xujunNGINX_VERSION=1.12.0-1~stretchNJS_VERSION=1.12.0.0.1.10-1~stretchHOME=/root
4 Docker镜像构建和Dockerfile
4.1 Dockerfile、镜像以及容器之间的关系
Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。
简单来讲,Dockerfile构建出Docker镜像,通过Docker镜像运行Docker容器。下图就是三者之间的关系:

4.2 Dockerfile与Docker镜像
首先,我们结合上图来看看Dockerfile与Docker镜像之间的关系。
FROM ubuntu:14.04:设置基础镜像,此时会使用基础镜像 ubuntu:14.04 的所有镜像层,为简单起见,图中将其作为一个整体展示。
ADD run.sh /:将 Dockerfile 所在目录的文件 run.sh 加至镜像的根目录,此时新一层的镜像只有一项内容,即根目录下的 run.sh。
VOLUME /data:设定镜像的 VOLUME,此 VOLUME 在容器内部的路径为 /data。需要注意的是,此时并未在新一层的镜像中添加任何文件,即构建出的磁层镜像中文件为空,但更新了镜像的 json 文件,以便通过此镜像启动容器时获取这方面的信息。
CMD [“./run.sh”]:设置镜像的默认执行入口,此命令同样不会在新建镜像中添加任何文件,仅仅在上一层镜像 json 文件的基础上更新新建镜像的 json 文件。
因此,通过以上分析,以上的Dockerfile可以构建出一个新的镜像,包含4个镜像层,每一条命令会和一个镜像层对应,镜像之间会存在父子关系。图中很清楚的表明了这些关系。
4.3 Docker镜像构建
[root@docker-100 ~]# docker run -it -d --name mycentos centos bash #运行我们pull下来的容器a24788624db4659afca1539c22895e3ab7eecb273406e8b7911d07312f89a94d[root@docker-100 ~]# docker ps #查看已经运行的容器CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa24788624db4 centos "bash" 1 second ago Up 1 second mycentos[root@docker-100 ~]# docker exec -it mycentos bash #进入容器[root@a24788624db4 /]# yum install epel-* -y #安装epel源[root@a24788624db4 /]# yum install nginx -y #在容器里安装nginx[root@a24788624db4 /]# cat /etc/nginx/nginx.conf #编辑nginx配置文件# For more information on configuration, see:# * Official English Documentation: http://nginx.org/en/docs/# * Official Russian Documentation: http://nginx.org/ru/docs/daemon off; #添加这一行,表示不已守护进程的方式运行nginxuser nginx;worker_processes auto;error_log /var/log/nginx/error.log;pid /run/nginx.pid;# Load dynamic modules. See /usr/share/nginx/README.dynamic.include /usr/share/nginx/modules/*.conf;events {worker_connections 1024;}http {log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;tcp_nopush on;tcp_nodelay on;keepalive_timeout 65;types_hash_max_size 2048;...............#编辑好之后,退出当前容器,接下来就是制作镜像[root@docker-100 ~]# docker ps -a #查看mycentos的IDCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa24788624db4 centos "bash" 7 minutes ago Up 7 minutes mycentos[root@docker-100 ~]# docker commit -m "My Nginx" a24788624db4 xgg/mynginx:v1sha256:4e1581e20d4509935bc7e293788bb4f474084ec2945b53b9fc668350578e3ec0# commit:提交当前容器为新的镜像#-m:注释#a24788624db4:当前容器ID#xgg/mynginx:v1:要生成的镜像名称[root@docker-100 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZExgg/mynginx v1 4e1581e20d45 About a minute ago 338MBnginx latest f6d0b4767a6c 3 days ago 133MBcentos latest 300e315adb2f 5 weeks ago 209MB[root@docker-100 ~]# docker run -it -d -p 80:80 xgg/mynginx:v1 nginx #运行nginx容器7658501d862e45660022459fcbe7588d26d7d518ea3185fb2156e7058653dded[root@docker-100 ~]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES7658501d862e xgg/mynginx:v1 "nginx" 1 second ago Up 1 second 0.0.0.0:80->80/tcp ecstatic_meitnera24788624db4 centos "bash" 10 minutes ago Up 10 minutes mycentos

4.4 Dockerfile构建
Dockerfile指令说明:

1、FROM指令
- 指定所创建的镜像为基础镜像,如果本地不存在,则默认会去Docker Hub下载指定的镜像。
- 格式为:FROM,或者为FROM:,或者为FROM @
- 列子:
FROM centos7FROM centos7:0.1
注意:tag标签如果省略,默认为latest
2、MAINTANIER指令
- 用于让Dockerfile制作者提供本人的详细信息
- Dockerfile并不限制MAINTAINER指定可在出现的位置,但推荐将其放置于FROM指令之后
- 列子:
MAINTAINER xujun1270@qq.com
3、COPY指令
- 用于从Docker主机复制文件至创建的新映像文件
- 复制本地主机的(为Dockerfile所在目录的一个相对路径、文件或目录)下的内容到镜像中的下。目标路径不存在时,会自动创建。
- 列子:
#Description:test imageFROM centos7:1611MAINTAINER xujun1270@qq.comCOPY index.html /data/web/html/
4、ADD指令
- 该指令将复制指定的路径下的内容到容器中的路径下
- 其中可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL,也可以是一个tar文件,但如果是tar文件,会自动解压至路径下
- 列子:
ADD index.html /data/web/html
5、VOLUME指令
- 创建一个数据卷挂载点
- 可以从本地主机或者其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等
- 列子:
VOLUME /data
6、EXPOSE指令
- 用于为容器打开指定要监听的端口以实现与外部通信,默认为TCP协议
- 列子:
EXPOSE 80/tcp
7、ENV指令
- 指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在
- 列子:
ENV DIR /data/web/htmlCOPY index.html $DIR
8、RUN指令
- 用于指定Docker build过程中运行的程序,其可以是任何命令
- 列子:
Run echo "/application/php-5.6.32/sbin/php-fpm" >> /etc/rc.local && \"/application/nginx-1.8.1/sbin/nginx" >> /etc/rc.local && \"systemctl start nslcd" >> /etc/rc.local && chmod +x /etc/rc.local
9、CMD指令
- 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
1.RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时
2.CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止。不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
3.在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效。 - 列子:
CMD ["/sbin/init"]CMD ["/bin/bash","/init.sh"]
10、USER指令
- 用于指定运行images时的或运行Dockerfile中任何RUN,CMD指令指定的程序时的用户名或UID
- 默认情况下,容器的运行身份为root用户
- 列子:
USER nginx
注意:USER指定的用户,必须存在/etc/passwd中,否则会报错
11、HEALTHCHECK指令
- 配置启动的容器是否进行健康检查
主要选项:--inerval=DURATION (默认为:30s)多久检查一次--timeout=DURATION (默认为:30s)每次检查等待结果的超时时间--retries=N (默认为:30s)如果失败了,重试几次才最终确定失败--start-period=DURATION (默认为:0s)延迟健康检测检测状态响应值:0:成功1:失败2:未设定
列子:
HEALTHCHECK --interval=5m --timeout=3s
12、WORKDIR指令
- 为后续的RUN、CMD和ENTRYPOINT指令配置工作目录
- 列子:
WORKDIR /path/to/workdir/
13、ENTRYPOINT指令
- 容器启动时要执行的命令,它和CMD很像,也是只有一条生效,如果写多个只有最后一条有效,和CMD不同是:
- CMD是可以被docker run指令覆盖的,而ENTRYPOINT不能覆盖。
- 我们在Dockerfile中指定如下CMD:
- CMD [“/bin/echo”,”test”]
- 启动容器的命令是docker run centos7这样会输出test
- 假如启动容器的命令是docker run -it centos7 /bin/bash 什么都不会输出
- ENTRYPOINT不会被覆盖,而且会比CMD或者docker run指定的命令要靠前执行
- ENTRYPOINT [“echo”,”test”]
- docker run -it centos7 123
- 则会输出test 123,这就相当于要执行命令echo test 123
[root@wiki-10 docker]# cat /data/dockerfile/DockerfileFROM centos:7ADD entrypoint.sh /entrypoint.shRUN yum install epel-release -q -y && yum install nginx -yENTRYPOINT /entrypoint.sh[root@wiki-10 docker]# cat /data/dockerfile/entrypoint.sh#!/bin/bash/sbin/nginx -g "daemon off;"[root@wiki-10 docker]# docker build . -t iflytek/mynginx:V1[root@wiki-10 docker]# docker run -d --name mynginx -p 84:80 iflytek/mynginx:V1
4.5 Dockerfile构建Nginx(yum安装的方式)
[root@docker-100 nginx]# mkdir -p /scripts/docker/nginx #先创建dockerfile目录[root@docker-100 nginx]# lsDockerfile nginx.conf[root@docker-100 nginx]# cat DockerfileFROM centosADD ./nginx.conf /etc/nginx/RUN yum install epel-* -y && \yum install nginx -yEXPOSE 80 443CMD ["nginx -g daemon off"][root@docker-100 nginx]# docker build -t "xxg/mynginx:v2" . #构建镜像Sending build context to Docker daemon 5.12kBStep 1/5 : FROM centos---> 300e315adb2fStep 2/5 : ADD ./nginx.conf /etc/nginx/---> f762d3d859a4Step 3/5 : RUN yum install epel-* -y && yum install nginx -y。。。。。[root@docker-100 nginx]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZExxg/mynginx v2 1b51ed27c661 About a minute ago 312MBxgg/mynginx v1 4e1581e20d45 21 minutes ago 338MBnginx latest f6d0b4767a6c 3 days ago 133MBcentos latest 300e315adb2f 5 weeks ago 209MB[root@docker-100 nginx]# docker run -it -d -p 81:80 --name mynginx-v1 xxg/mynginx:v2 nginxb179638f0e3311cae1ca1d749f6a85f0df41fef5bcef3bf297a9bed0615cd269[root@docker-100 nginx]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESb179638f0e33 xxg/mynginx:v2 "nginx" 1 second ago Up 1 second 443/tcp, 0.0.0.0:81->80/tcp mynginx-v17658501d862e xgg/mynginx:v1 "nginx" 22 minutes ago Up 22 minutes 0.0.0.0:80->80/tcp ecstatic_meitnera24788624db4 centos "bash" 33 minutes ago Up 33 minutes mycentos
4.6 制作JDK镜像
#1、定义dockerfile文件[root@docker-100 jdk]# cat /scripts/docker/jdk/DockerfileFROM centosADD ./jdk-8u241-linux-x64.tar.gz /usr/local/src/ADD ./profile /etc/profileRUN yum install vim wget net-tools -y && \ln -s /usr/local/src/jdk1.8.0_241 /usr/local/jdk && \rm -rf /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtimeENV JAVA_HOME /usr/local/jdkENV PATH $JAVA_HOME/bin:$PATHENV CLASSPATH .:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib#2、上传JDK压缩文件和profile文件[root@docker-100 jdk]# lsDockerfile jdk-8u241-linux-x64.tar.gz profile#3、开始构建JDK镜像[root@docker-100 jdk]# docker build -t "xxg/jdk:v1" .[root@docker-100 jdk]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZExxg/jdk v1 4b84418c0477 10 minutes ago 673MB#4、开启容器,并进入容器中,验证java环境[root@docker-100 jdk]# docker run --rm -it xxg/jdk:v1 bash[root@8688ce0d283f /]# java -versionjava version "1.8.0_241"Java(TM) SE Runtime Environment (build 1.8.0_241-b07)Java HotSpot(TM) 64-Bit Server VM (build 25.241-b07, mixed mode)
4.7 基于官方alpine基础镜像制作自定义镜像
#1、定义dockerfile文件[root@docker-100 nginx-alpine]# cat DockerfileFROM alpineRUN apk update && apk add iotop gcc libgcc libc-dev libcurl libc-utils pcre-dev zlib-dev libnfs make pcre pcre2 zip unzip net-tools pstree wget libevent libevent-dev iproute2 && \mkdir -p /application/ && \cd /usr/local/ && wget http://nginx.org/download/nginx-1.18.0.tar.gz && tar xf nginx-1.18.0.tar.gz && cd nginx-1.18.0 && ./configure --prefix=/application/nginx-1.18.0 && make && make install && \ln -s /application/nginx-1.18.0/ /application/nginx && \cd /application/nginx/sbin/ && cp -a nginx /usr/bin/ && \addgroup -g 2019 -S nginx && adduser -s /sbin/nologin -S -D -u 2019 -G nginx nginx && \chown nginx.nginx /application/nginx -R && \rm -rf /usr/local/nginx-1.18.0.tar.gz /usr/local/nginx-1.18.0ADD ./nginx.conf /application/nginx/conf/EXPOSE 80 443CMD ["nginx"]#2、上传nginx.conf文件[root@docker-100 nginx-alpine]# lsDockerfile nginx.conf#3、构建alpine镜像[root@docker-100 nginx-alpine]# docker build -t "xxg/alpine-nginx:v1" .[root@docker-100 nginx-alpine]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZExxg/alpine-nginx v1 7205d7afd77d 16 seconds ago 199MB#4、运行alpine容器[root@docker-100 nginx-alpine]# docker run --rm -it -p84:80 xxg/alpine-nginx:v1 nginx
4.8 制作nginx+php+wiki镜像构建
[root@wiki-10 ~]# mkdir -p /docker #创建dockerfile所在的目录[root@wiki-10 ~]# cd /docker[root@wiki-10 docker]# touch Dockerfile #创建一个dockerfile,首字母必须大写[root@wiki-10 docker]# mkdir -p wiki #创建用于放置dockerfile所需要的文件[root@wiki-10 docker]# lsDockerfile wiki[root@wiki-10 docker]# cat DockerfileFROM daocloud.io/library/centos:centos7.3.1611COPY wiki /wikiRUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup && \curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \yum makecache && \yum install epel-release -y && \yum install nginx -y && \yum install php-fpm php php-mysql -y && \yum install python-setuptools -y && \easy_install supervisor && \cd /wiki/ && tar xf hdwiki.tar.gz && \mv /wiki/nginx.conf /etc/nginx/nginx.conf && \mv /wiki/hdwiki /usr/share/nginx/html/ && \mv /wiki/supervisor.conf /etc/supervisord.conf && \rm -rf /wiki && \yum remove epel-release -y && \yum clean allEXPOSE 80CMD ["/usr/bin/supervisord"]注意:在Dockerfile里写入一个指令,就会使得docker在构建的时候,多加一层,这样容器就会显得很笨重。所以写Dockerfile的时候,最好还是以一条命令的方式写入。[root@wiki-10 docker]# cd wiki/[root@wiki-10 wiki]# lshdwiki.tar.gz nginx.conf supervisor.conf这边我要解释一下CMD ["/usr/bin/supervisord"]是什么意思。Docker奉行的是一个容器跑一个进程的思想,所以启动容器的时候一般也只能启动一个进程或者一个脚本。所以为了实现nginx+php两个进程一起启动,我用了supervisor,一个可以管理进程的工具。接下去开始构建Dockerfile:[root@wiki-10 docker]# docker build -t "iflytek/mywiki:v1" .构建过程省略。。。。[root@wiki-10 docker]# docker run --name mywiki -itd -p 80:80 iflytek/mywiki:v1 #启动镜像[root@wiki-10 docker]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESde76843959fd iflytek/mywiki:v1 "/usr/bin/supervisord" 44 minutes ago Up 44 minutes 0.0.0.0:80->80/tcp mywiki
最后搭建完成的wiki:

5.资源限制
5.1 资源限制介绍
默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源,Docker 提供了控制容器可以限制容器使用多少内存或CPU的方法,设置docker run命令的运行时配置标志。
其中许多功能都要求宿主机的内核支持Linux 功能,要检查支持,可以使用docker info命令,如果内核中禁用了某项功能,可能会在输出结尾处看到警告,如下所示:
WARNING: No swap limit supportr
对于Linux 主机,如果没有足够的内容来执行其他重要的系统任务,将会抛出00M (Out of Memory Exception,内存溢出、内存泄漏、内存异常),随后系统会开始杀死进程以释放内存,凡是运行在宿主机的进程都有可能被kill, 包括Dockerd和其它的应用程序,如果重要的系统进程被Kill,会导致和该进程相关的服务全部宕机。
产生00M异常时,Dockerd尝试通过调整Docker守护程序上的00M优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死,但是容器的00M优先级未调整,这使得单个容器被杀死的可能性比Docker 守护程序或其他系统进程被杀死的可能性更大,不推荐通过在守护程序或容器上手动设置oom-score-adj为极端负数,或通过在容器上设置-oomkill-disable来绕过这些安全措施。
5.2 OOM优先级机制
linux会为每个进程算一个分数,最终他会将分数最高的进程kill。
/proc/PID/oom_ score_ adj #范围为-1000到1000, 值越高越容易被宿主机kill掉,如果将该值设置为-1000, 则进程永远不会被宿主机kernel kill 。/proc/PID/oom_ adj #范围为-17到+15,取值越高越容易被干掉,如果是-17,则表示不能被kill,该设置参数的存在是为了和旧版本的Linux内核兼容。/proc/PID/oom score #这个值是系统综合进程的内存消耗量、CPU时间(utime + stime)、存活时间(uptime一start time)和oom adj计算出的进程得分,消耗内存越多得分越高,越容易被宿主机kernel强制杀死。
5.3 内存限额
与操作系统类似,容器可使用的内存包括两部分:物理内存和swap。Docker通过下面参数来控制容器内存的使用量。


5.4 CPU限额
一个宿主机,有几十个核心的CPU,但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务,多进程共用一个CPU的核心依赖计数就是为可压缩资源,即一个核心的CPU可以通过调度而运行多个进程,但是同一个单位时间内只能有一个进程在CPU上运行, 那么这么多的进程怎么在CPU上执行和调度的呢?
实时优先级: 0-99。
非实时优先级(nice): -20-19, 对应100-139的进程优先级。
Linux kernel进程的调度基于CFS(Completely Fair Scheduler),完全公平调度。
CPU密集型的场景:优先级越低越好,计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、数据处理、对视频进行高清解码等等,全靠CPU的运算能力。
IO密集型的场景:优先级值高点,涉及到网络、磁盘10的任务都是I0密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待I0操作完成(因为I0的速度远远低于CPU和内存的速度),比如Web应用,高并发,数据量大的动态网站来说,数据库应该为IO密集型。
默认情况下,每个容器对主机CPU周期的访问权限是不受限制的,但是我们可以设置各种约束来限制给定容器访问主机的CPU周期,大多数用户使用的是默认的CFS调度方式,在Docker1.13及更高版本中,还可以配置实时优先级。
参数:
1、--cpus:指定容器可以使用的CPU数量。该参数指定的是百分比,并不是具体的个数。比如:主机有4个逻辑CPU,限制容器—cpus=2,那么该容器最多可以使用的CPU时间是200%,但是4个CPU分配的时间可能是每个CPU各50%,而不一定是有其中2个CPU使用100%,而另2个CPU使用0%。--cpus是docker 1.13之后才出来的参数,目的是替代--cpu-period和--cpu-quota两个参数,从而使配置更简单。2、--cpu-period表示的是设置CPU时间周期,默认值是100000,单位是us,即0.1s。3、--cpu-quota指示容器可以使用的最大的CPU时间,配合--cpu-period值使用。如果—cpu-quota=200000,即0.2s。那就是说在0.1s周期内改容器可以使用0.2s的CPU时间,显然1个CPU是无法满足要求的,需要至少2个CPU才能满足。4、--cpuset-cpus设置容器具体可以使用哪些个CPU。如--cpuset-cpus=”0,1,2”或者--cpuset-cpus=”0-2”,则容器会使用第0-2个CPU。5、--cpu-shares,容器使用CPU的权重,默认值是1024,数值越大权重越大。该参数仅当有多个容器竞争同一个CPU时生效。对于单核CPU,如果容器A设置为--cpu-shares=2048,容器B设置为--cpus-shres=1024,仅当两个容器需要使用的CPU时间超过整个CPU周期的时候,容器A会被分配66%的CPU时间,容器B被分配33%的CPU时间,大约是2:1;对于多核CPU,仅当多个容器竞争同一个CPU的时候该值生效。
6.Docker使用Portainer搭建可视化界面
6.1 Portainer介绍
Portainer是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作(包括上传下载镜像,创建容器等操作)、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录用户管理和控制等功能。功能十分全面,基本能满足中小型单位对容器管理的全部需求。
6.2 安装Portainer
#1、下载Portainer镜像[root@portainer ~]# docker pull docker.io/portainer/portainer#2、运行容器[root@portainer ~]# docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /portainer:/data portainer/portainer该语句用宿主机9000端口关联容器中的9000端口,并给容器起名为portainer。执行完该命令之后,使用该机器IP:PORT即可访问Portainer#3、访问方式http://IP:9000
首次登陆需要注册用户,给admin用户设置密码:

单机版这里选择local即可,选择完毕,点击connect即可连接到本地docker。

注意:该页面上有提示需要挂载本地 /var/run/docker.socker与容器内的/var/run/docker.socker连接。因此,在启动时必须指定该挂载文件。
首页:

6.3 Portainer汉化
因为Portainer只支持英文的,对于英文不太好的我来说,不是很友好,所以我们接下来就让它支持汉化吧!
#汉化项目https://www.quchao.net/Portainer-CN.html下载地址:https://pan.baidu.com/s/13ra6jXHR_7vajLLlf5GVEw 提取码: nzue#部署过程# 1、新建文件夹命名为 public ,把 Portainer-CN.zip 解压至里面。[root@portainer ~]# mkdir -p /opt/pubic/[root@portainer pubic]# lsPortainer-CN.zip[root@portainer pubic]# pwd/opt/pubic[root@portainer pubic]# unzip Portainer-CN.zip# 2、然后按需执行以下命令[root@portainer ~]# docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /portainer:/data -v /opt/pubic/:/public portainer/portainer您只需要使用浏览器访问运行Portainer的Docker引擎的端口9000

汉化成功,到此基本的安装已经结束了!
6.4 Portainer基本使用
6.4.1 容器使用
容器列表

点击容器列表中的容器名Name,即可查看容器详情:


6.4.2 镜像
镜像列表

可以拉取镜像至本地


[root@portainer ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEcentos latest 300e315adb2f 7 weeks ago 209MBportainer/portainer latest 62771b0b9b09 6 months ago 79.1MB我们可以看到已经拉取镜像至本地
6.4.3 集群运行
更多的情况下,我们会有一个docker集群,可能有几台机器,也可能有几十台机器,因此,进行集群管理就十分重要了,Portainer也支持集群管理。现在让我来演示一下如何进行管理一台docker服务器:
# 环境说明:10.0.0.100 docker10.0.0.103 Portainer# 在添加docker节点之前,我们需要在docker的启动文件里配置可监听端口,这样才能远程管理[root@docker-100 ~]# cat /usr/lib/systemd/system/docker.serviceExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock #添加2375端口[root@docker-100 ~]# systemctl daemon-reload[root@docker-100 ~]# systemctl restart docker[root@docker-100 ~]# ss -lntp|grep 2375LISTEN 0 128 :::2375 :::* users:(("dockerd",pid=39046,fd=5))
添加节点



添加成功

我们回到首页

我们可以看到所添加的docker节点

7.单机编排之Docker compose
当在宿主机启动较多的容器时候,如果都是手动操作会觉得比较麻烦,而且容器容易出错,这个时候推荐使用docker单机编排工具docker compose, docker-compose是docker容器的一种单机编排服务,docker-compose 是一个管理多个容器的工具,比如可以解决容器之间的依赖关系,就像启动一个nginx前端服务的时候会调用后端的tomcat,那就得先启动tomcat,但是启动tomcat容器还需要依赖数据库,那就还得先启动数据库,docker-compose就可以解决这样的嵌套依赖关系,
其完全可以替代dockerrun对容器进行创建、启动和停止。docker-compose项目是Docker 官方的开源项目,负责实现对Docker容器集群的快速编排, docker-compose将所管理的容器分为三层,分别是工程(project),服务(service) 以及容器(container)。
github地址https://github.com/docker/compose
7.1 基础环境准备
7.1.1 二进制安装docker-compose
官网下载地址:https://github.com/docker/compose/releases#1、下载二进制文件[root@docker-100 ~]# cd /usr/local/src/[root@docker-100 src]# wget https://github.com/docker/compose/releases/download/1.28.2/docker-compose-Linux-x86_64#2、赋予二进制文件执行权限[root@docker-100 src]# mv docker-compose-Linux-x86_64 docker-compose[root@docker-100 src]# chmod +x docker-compose[root@docker-100 src]# mv docker-compose /usr/bin/#3、验证docker-compose版本[root@docker-100 src]# docker-compose versiondocker-compose version 1.28.2, build 67630359docker-py version: 4.4.1CPython version: 3.7.9OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
7.1.2 查看docker-compose帮助
[root@docker-100 src]# docker-compose --helpOptions:-f, --file FILE #指定compose模板文件,默认为docker-compose.yml-p, --project-name NAME #指定项目名称,默认将使用当前所在目录名称作为项目名--verbose #显示更多输出信息--log-level LEVEL #定义日志级别-v, --version #显示版本Commands: #需要在docker-compose.yml文件目录执行build #通过docker-compose构建镜像config -q #查看当前配置,没有错误不输出任何信息create #创建服务down #停止和删除所有容器、网络、镜像和卷events #从容器接受实时时间,可以指定json日志格式exec #进入指定容器进行操作help #显示帮助信息images #显示当前服务器的docker镜像信息kill #强制终止运行中的容器logs #查看容器的日志pause #暂停服务port #查看端口ps #列出容器pull #重新拉取镜像push #上传镜像restart #重启服务rm #删除已经停止的服务run #一次性运行容器,等于docker run --rmscale #设置指定服务运行的容器个数 docker-compose scale nginx=2start #启动服务stop #停止服务top #显示容器运行状态unpause #取消暂停up #创建并启动容器up -d #创建、并后台启动容器version #显示docker-compose版本信息
7.2 从docker compose启动单个容器
7.2.1 单个容器的docker compose文件
编写一个yml格式的docker-compose文件,启动一个nginx文件,由于格式为yml格式,因此要注意前后的缩进及上下行的等级关系。
#1、先创建一个目录[root@docker-100 ~]# mkdir -p /data/docker-compose[root@docker-100 docker-compose]# pwd/data/docker-compose#2、配置docker-compose.yml文件[root@docker-100 docker-compose]# cat docker-compose.ymlservice-nginx-web:image: 10.0.0.101/xxg/xxg/alpine-nginx:v1expose:- 80- 443ports:- "80:80"- "443:443"#3、启动容器,必须要在docker compose文件所在的目录执行[root@docker-100 docker-compose]# pwd/data/docker-compose[root@docker-100 docker-compose]# docker-compose up -d #加上-d参数,表示后台启动Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/Pulling service-nginx-web (10.0.0.101/xxg/xxg/alpine-nginx:v1)...v1: Pulling from xxg/xxg/alpine-nginxDigest: sha256:68cf189050d1531f121be659654ce43395573ecde182c56571b0052cbc26374aStatus: Downloaded newer image for 10.0.0.101/xxg/xxg/alpine-nginx:v1docker-compose_service-nginx-web_1 is up-to-date[root@docker-100 docker-compose]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa09886538442 10.0.0.101/xxg/xxg/alpine-nginx:v1 "nginx" 7 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp docker-compose_service-nginx-web_1
web访问测试

7.2.2 自定义容器名称
[root@docker-100 docker-compose]# cat docker-compose.ymlservice-nginx-web:image: 10.0.0.101/xxg/xxg/alpine-nginx:v1container_name: nginx-web01 #自定义容器名称expose:- 80- 443ports:- "80:80"- "443:443"[root@docker-100 docker-compose]# docker-compose up -dBuilding with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/Creating nginx-web01 ... done#验证容器名称[root@docker-100 docker-compose]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES651d139cdb68 10.0.0.101/xxg/xxg/alpine-nginx:v1 "nginx" 19 seconds ago Up 6 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-web01
7.3 从docker compose启动多个容器
7.3.1 编辑docker-compose文件
[root@docker-100 docker-compose]# cat docker-compose.ymlservice-nginx-web01:image: 10.0.0.101/xxg/xxg/alpine-nginx:v1container_name: nginx-web01expose:- 80- 443ports:- "80:80"- "443:443"service-linux-centos:image: tomcat:8-jdk8-correttocontainer_name: tomcat-app1expose:- 8080ports:- "8080:8080"#重启启动容器[root@docker-100 docker-compose]# docker-compose stop[root@docker-100 docker-compose]# docker-compose up -dBuilding with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/Pulling service-linux-centos (tomcat:8-jdk8-corretto)...Creating tomcat-app1 ... doneCreating nginx-web01 ... done
测试web页面


7.4 定义数据卷挂载
7.4.1 创建数据目录和文件
#1、创建数据目录和文件[root@docker-100 docker-compose]# mkdir -p /data/nginx[root@docker-100 docker-compose]# cd /data/nginx[root@docker-100 nginx]# echo "linux" > /data/nginx/index.html#2、编辑compose配置文件[root@docker-100 nginx]# cd -/data/docker-compose[root@docker-100 docker-compose]# vim docker-compose.ymlservice-nginx-web01:image: 10.0.0.101/xxg/xxg/alpine-nginx:v1container_name: nginx-web01volumes:- /data/nginx:/application/nginx/html #添加数据卷至容器中expose:- 80- 443ports:- "80:80"- "443:443"service-linux-centos:image: tomcat:8-jdk8-correttocontainer_name: tomcat-app1expose:- 8080ports:- "8080:8080"#3、重启容器[root@docker-100 docker-compose]# docker-compose stopStopping nginx-web01 ... doneStopping tomcat-app1 ... done[root@docker-100 docker-compose]# docker-compose up -dBuilding with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/Starting tomcat-app1 ... doneRecreating nginx-web01 ... done
web验证测试

