Docker 进阶篇(二)数据管理,网络管理,使用Dockerfile构建镜像
数据管理
Docker挂载数据卷的形式有一下三种
- 使用现有本地目录自定义挂载
- 使用Docker Volumes挂载
- 使用数据卷容器挂载
使用现有本地目录挂载
## 命令格式为 -v /宿主机目录/:/容器目录/
##在宿主及上手动创建目录
[root@node_1 ~]# mkdir /data
[root@node_1 ~]# echo "Nginx test" >> /data/index.html
##运行容器测试
[root@node_1 ~]# docker run -d -p 80:80 -v /data/:/usr/share/nginx/html --name nginx_test nginx:latest
3151524a01b51c76ae0bfd50e79f63edd25a6bfeed806a065aabe4209fe834e4
[root@node_1 ~]# curl 127.0.0.1
Nginx test
[root@node_1 ~]# echo "Nginx test 2" > /data/index.html
[root@node_1 ~]# curl 127.0.0.1
Nginx test 2
##删除容器测试
[root@node_1 ~]# docker stop nginx_test
nginx_test
[root@node_1 ~]# docker rm nginx_test
nginx_test
[root@node_1 ~]# ls /data/
index.html
##宿主机节点数据不会受到影响
使用Docker Volumes挂载
## 命令格式为 -v /容器目录/
[root@node_1 ~]# docker run -d -p 80:80 --name nginx_test -v /usr/share/nginx/html nginx:latest
d41c1762134ecfa4f19874a0173d17fe833f8d76e7fa44c163a05c442795f141
##查看容器挂载目录对应关系
[root@node_1 ~]# docker inspect -f {{.Mounts}} nginx_test
[{volume 8bc32cf5b71faf78552fd9a5fa6af95e07c5a3ea7f24d5357e577acc4a07a6f6 /var/lib/docker/volumes/8bc32cf5b71faf78552fd9a5fa6af95e07c5a3ea7f24d5357e577acc4a07a6f6/_data /usr/share/nginx/html local true }]
##写入文件测试
[root@node_1 ~]# echo "Nginx test" > /var/lib/docker/volumes/8bc32cf5b71faf78552fd9a5fa6af95e07c5a3ea7f24d5357e577acc4a07a6f6/_data/index.html
[root@node_1 ~]# curl 127.0.0.1
Nginx test
##删除容器测试
[root@node_1 ~]# docker stop nginx_test
nginx_test
[root@node_1 ~]# docker rm nginx_test
nginx_test
[root@node_1 ~]# ls /var/lib/docker/volumes/8bc32cf5b71faf78552fd9a5fa6af95e07c5a3ea7f24d5357e577acc4a07a6f6/_data/
50x.html index.html
[root@node_1 ~]# docker volume ls
DRIVER VOLUME NAME
local 8bc32cf5b71faf78552fd9a5fa6af95e07c5a3ea7f24d5357e577acc4a07a6f6
##Docker Volumes数据不会受到影响
##若要删除容器并且删除Volume 可在docker rm 后面加上-v参数
[root@node_1 ~]# docker run -d -p 80:80 --name nginx_test -v /usr/share/nginx/html nginx:latest
da053b579e13bcd05710b2e316b8bb0183a5e0d577706d487f6ce11875dda2e3
[root@node_1 ~]# docker volume ls
DRIVER VOLUME NAME
local d30bff9f4617a395bfd7c5d9c4f4aa76971ff329fb33c02f779f13c58dbeff78
[root@node_1 ~]# docker stop nginx_test
nginx_test
[root@node_1 ~]# docker rm -v nginx_test
nginx_test
[root@node_1 ~]# docker volume ls
DRIVER VOLUME NAME
##如果使用 docker run -v 启动的容器被删除时没有加-v参数,那么会在主机上会遗留下来孤单的卷。
##可以使用下面的简单方法来做清理(在删除是先看一下卷中的数据是否无用,确认无用后再进行操作):
[root@node_1 ~]# for i in `docker volume ls -qf dangling=true` ;do docker volume rm $i ;done
使用数据卷容器挂载
有时候,我们需要多个容器之间相互共享数据,类似于linux里面的NFS,所以就可以搭建一个专门的数据卷容器,然后其他容器直接挂载该数据卷。当然在创建数据卷容器的时候也可以使用本地已经创建好的目录
##创建数据卷容器
[root@node_1 ~]# docker run -itd -v /data/ --name volume_data centos:6 bash
599f5373dc17ca7f301d3e8dc6c25b17a089b430dfab6b1e92ca44997f115821
[root@node_1 ~]# docker exec -it volume_data bash
[root@599f5373dc17 /]# echo "test" >/data/test
##创建客户端关联
[root@node_1 ~]# docker run -itd --volumes-from volume_data --name client centos:6 bash
0547c0c212941998cba58310c6bcf4b0eee791fc6fa24f5de9b923766c76eb82
[root@node_1 ~]# docker exec -it client cat /data/test
test
网络管理
外部访问容器
外部访问容器可以在运行容器时指定-p 参数映射,如果需要同时映射多个端口,只需增加多个-p参数即可
##运行容器
##将本地80端口映射到容器的80端口上
[root@node_1 ~]# docker run -d -p 80:80 --name nginx nginx:latest
[root@node_1 ~]# curl 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
Docker 的网络模式
- Host模式 :使用docker run时使用–net=host指定,共享宿主机的IP地址
- Container模式 :使用–net=container:container_id/container_name,多个容器使用共同的网络,看到的ip是一样的
- none模式 :使用–net=none指定,这种模式下,不会配置任何网络
- bridge模式 :使用–net=bridge指定,Dcoker 网络的默认模式。这种模式会为每个容器分配一个独立的Network Namespace。类似于vmware的nat网络模式。同一个宿主机上的所有容器会在同一个网段下,相互之间是可以通信的。
Host模式
使用docker run时使用–net=host指定,共享宿主机的IP地址,无需加-p参数映射端口,但需要注意在运行多个容器使用host模式时ip端口冲突的问题
[root@node_1 ~]# docker run -itd --net=host --name host centos:6 bash
68ccd7753e853531db1b6c69aa7a0fbf7f5ed068ed8456db12ea449812e295a1
[root@node_1 ~]# docker exec -it host ifconfig
ens33 Link encap:Ethernet HWaddr 00:0C:29:0C:D9:24
inet addr:192.168.100.150 Bcast:192.168.100.255 Mask:255.255.255.0
inet6 addr: fe80::97ef:3c22:1c0e:3784/64 Scope:Link
[root@node_1 ~]# docker run -d --net=host --name nginx nginx:latest
f3a4caba37fb162fe59b5cb2e1d1b8f13d847b12ef3d6556701cd4bfe6676c7d
[root@node_1 ~]# curl 192.168.100.150
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
Container模式
使用–net=container:container_id/container_name,多个容器使用共同的网络,看到的ip是一样的
##运行一个Nginx容器
[root@node_1 ~]# docker run -d --name nginx_server nginx:latest
af34bf9e6a7fc7d5c3aa765a362761091fefb2a5fe53ff5bc51585ada6a1efb6
##在运行一个客户端容器,访问本地端口的80端口,看能否通信
[root@node_1 ~]# docker run -it --net=container:nginx_server --name nginx_server_client centos:6 curl 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
##运行的client 容器里面没有启动http服务,理论上容器和容器之间是隔离的,但是client容器使用--net参数链接到了nginx_server_client,两个容器的ip是一样的,所以在client端能够访问到本地的127.0.0.1 的80端口
none模式
使用–net=none指定,这种模式下,不会配置任何网络,适用于启动容器做数据备份,或者启动不需要网络支持的容器
由于用处较少,在这里不做展示
bridge模式
使用–net=bridge指定,Dcoker 网络的默认模式。这种模式会为每个容器分配一个独立的Network Namespace。类似于vmware的nat网络模式。同一个宿主机上的所有容器会在同一个网段下,相互之间是可以通信的。
##查看本地docker 网卡信息
[root@node_1 ~]# ip a
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:1a:ae:22:e8 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:1aff:feae:22e8/64 scope link
valid_lft forever preferred_lft forever
##运行两个容器验证ip地址是否在同一网段时候能工通过内部ip进行通信
[root@node_1 ~]# docker run -d --name c1 nginx:latest bash
5eda666dd0c0e8e91470c5546e2042f4876ea45f262e67102f30e542ba5886bd
[root@node_1 ~]# docker run -d --name c2 nginx:latest bash
3a4790af3117d09bf06638b0bcb7510b598734b4e213d14fa4ee46ea72bec8ce
##查看两个容器的ip地址
[root@node_1 ~]# docker inspect c1 |grep "IPAddress"
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.7",
"IPAddress": "172.17.0.7",
[root@node_1 ~]# docker inspect c2 |grep "IPAddress"
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.6",
"IPAddress": "172.17.0.6",
##验证在容器内部两个容器是能够通过内网IP进行通信
[root@node_1 ~]# docker exec -it c2 curl 172.17.0.7
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
配置容器使用宿主机网段IP
为了使本地网络中的机器和Docker容器更方便的通信,我们经常会有将Docker容器配置到和主机同一网段的需求。这个需求其实很容易实现,我们只要将Docker容器和宿主机的网卡桥接起来,再给Docker容器配上IP就可以了。
##添加桥接网卡
[root@node_1 ~]# cd /etc/sysconfig/network-scripts/
[root@node_1 network-scripts]# cp ifcfg-ens33 ifcfg-br0
[root@node_1 network-scripts]# vi ifcfg-ens33
删除 IPADDR,GATEWAY,NETMASK,DNS1
增加BRIDGE=br0
[root@node_1 network-scripts]# vi ifcfg-br0
修改NAME=br0
修改TYPE=Bridge
修改DEVICE=br0
[root@node_1 network-scripts]# systemctl restart network
##安装pipwork工具
[root@node_1 ~]# git clone https://github.com/jpetazzo/pipework
[root@node_1 ~]# cp pipework/pipework /usr/bin/
##运行容器
[root@node_1 ~]# docker run -itd --net=none --name net-br centos:6 bash b0c798d1714ffa1d46e3579c37451f81fc52b46202523644c02b19a40154a163
##为容器分配ip地址
[root@node_1 ~]# pipework br0 net-br 192.168.100.151/24@192.168.100.2
## net-br为刚才运行容器的name,151为容器的ip,@后面的ip为网关ip
[root@node_1 ~]# docker exec -it net-br bash
[root@b0c798d1714f /]# ifconfig
eth1 Link encap:Ethernet HWaddr D2:0A:3E:EB:66:86
inet addr:192.168.100.151 Bcast:192.168.100.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:12 errors:0 dropped:0 overruns:0 frame:0
TX packets:1 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1520 (1.4 KiB) TX bytes:42 (42.0 b)
在宿主机上ping测试一下,或者在其他同网段机器中测试
使用Dockerfile构建镜像
之前有介绍过在容器里面操作然后通过docker commit命令保存容器状态,相当于是一种容器的“快照”,里面包括了容器正在运行时所产生的数据,增加了镜像的大小
而通过Dockerfile的形式构建镜像的话他可以使用指定的容器来进行构建镜像,里面也就不会存在一些垃圾数据导致镜像文件过大的问题
Dockerfile常用指令
FROM # 所使用的基础镜像,一切从这里开始构建
MAINTAINER # 镜像信息,可自定义
ENV # 构建的时候设置环境变量,跟 -e 是一个意思
RUN # 镜像构建的时候所需要在容器中运行的命令
ADD # 将本地的一个文件或目录拷贝到容器的某个目录里
COPY # 类似ADD,将我们文件拷贝到镜像中
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录,可选,在运行容器的时候可以手动添加-v选项
EXPOSE # 容器所需暴露的端口
CMD # 指定这个容器启动时要执行的命令,只有最后一个命令会生效,可被docker run命令最后跟的参数替代
USER # 指定容器内部运行的用户
ONBUILD # 当构建一个被继承DockerFile 这个时候就会运行ONBUILD的指令。触发指令
ENTRYPOINT # 指定这个容器启动的时候要执行的命令,只有最后一个命令会生效,不可被docker run命令最后跟的参数替代,但可以作为ENTRYPOINT 命令的最后一个参数
假如我定义 ENTRYPOINT [“echo”, “test”]
我运行容器: docker run -it xmtao 123
则会输出 test 123 ,这相当于容器在启动时执行命令 echo test 123
使用Dockerfile的形式简单构建一个NGINX
##创建Nginx的Dockerfile
[root@node_1 ~]# mkdir Nginx
[root@node_1 ~]# cd Nginx
[root@node_1 Nginx ]# vi Dockerfile
#使用基于centos6的镜像制作
FROM centos:6
#容器所暴露端口
EXPOSE 80
#安装编译工具
RUN yum -y install gcc-c++ gcc wget
#下载依赖包,编译安装
RUN wget https://sourceforge.net/projects/pcre/files/pcre/8.42/pcre-8.42.tar.gz/download -O pcre-8.42.tar.gz
RUN tar zxf pcre-8.42.tar.gz
RUN cd /pcre-8.42 &&./configure && make && make install && cd /
RUN wget http://www.zlib.net/zlib-1.2.11.tar.gz
RUN tar zxf zlib-1.2.11.tar.gz
RUN cd /zlib-1.2.11 && ./configure && make && make install && cd /
#下载nginx 进行编译安装
RUN wget http://nginx.org/download/nginx-1.16.1.tar.gz
RUN tar zxf nginx-1.16.1.tar.gz
RUN cd /nginx-1.16.1 && ./configure --prefix=/usr/local/nginx --with-pcre=/pcre-8.42 --with-zlib=/zlib-1.2.11 && make && make install
#删除无用压缩包
RUN rm -rf /pcre-8.42.tar.gz && rm -rf /zlib-1.2.11.tar.gz && rm -rf nginx-1.16.1.tar.gz
#将当前目录的index.html 添加到 /usr/local/nginx/html/ 下,并命名为index.html
ADD ./index.html /usr/local/nginx/html/index.html
#容器启动所执行的命令
ENTRYPOINT ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
[root@node_1 Nginx ]# echo "Nginx Test" > index.html
##构建镜像
[root@node_1 Nginx ]# docker build -t mynginx:1.16.1 .
##构建成功后查看大小
[root@node_1 Nginx ]# docker images |grep mynginx
mynginx 1.16.1 37a41c1d0a03 5 minutes ago 529MB
##运行测试
docker run -d --p 80:80 --name mynginx mynginx:1.16.1
[root@node_1 Nginx ]# curl 127.0.0.1
Nginx Test