博文大纲:
1、Docker镜像的建立方法
1.基于已有镜像建立
2.基于本地模板建立
3.基于Dockerfile建立
2、Docker的数据管理
1.数据卷
2.数据卷容器
3、Docker网络通讯
1.端口映射
2.容器互联html
Docker镜像除了是Docker的核心技术以外,也是应用发布的标准格式。一个完整的Docker镜像能够支撑一个Docker容器的运行,在Docker的整个使用过程当中,进入一个已经定型的容器以后,就能够在容器中进行操做,最多见的操做就是在容器中安装应用服务,若是要把已经安装的服务进行迁移,就须要把环境及搭建的服务生成新的镜像。nginx
建立最多见的三种方法:web
- 基于已有镜像建立;
- 基于本地模板建立;
- 基于Dockerfile建立;
基于已有镜像建立主要使用“docker commit”命令,其实质就是把一个容器里面运行的程序及该程序的运行环境打包起来生成新的镜像。docker
命令格式:shell
docker commit [选项] 容器ID/名称 仓库名称:[标签]
经常使用的选项:
-m:说明信息;
-a:做者信息;
-p:生成过程当中中止容器的运行;apache
方法以下:
(1)使用镜像建立一个新的容器,并进行修改。vim
[root@localhost ~]# docker images //查看本地的Docker镜像 REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/centos latest 0f3e07c0138f 6 weeks ago 220 MB [root@localhost ~]# docker run --privileged -d -it --name centos docker.io/centos init 794df7dc4cebeb43afb2a1d7cf424578a4f10c2344bcdb7208d6632609ce087c //使用centos镜像生成一个名为centos的容器,让容器以root的身份权限加载init守护进程 [root@localhost ~]# docker exec -it centos /bin/bash //指定一个shell进入容器 [root@794df7dc4ceb /]# yum -y install vsftpd //在容器中安装一个ftp服务 [root@794df7dc4ceb /]# systemctl start vsftpd //安装完成后,启动服务 [root@794df7dc4ceb /]# exit //退出容器
(2)使用“docker commit”命令建立一个新的镜像。centos
[root@localhost ~]# docker commit -m "vsftpd" -a "lzj" centos lzj:ftp sha256:ccba2c39b90a56373139196c3dc079b6df5c7f4f280bc35a7f1abf578962b52 //基于刚才建立的容器生成一个新的镜像,名称为lzj:ftp
(3)建立完成后,查看本地镜像是否已经有新生成的镜像。缓存
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE lzj ftp ccba2c39b90a 57 seconds ago 279 MB docker.io/centos latest 75835a67d134 13 months ago 200 MB
经过导入操做系统模板文件能够生成镜像。模板能够从OPENVZ开源项目下载,或者 https://wiki.openvz.org/Download/template/precreated ,优先使用OPENVZ开源项目那个连接。安全
其实,就把使用“docker load < 文件名”将一个文件导入成镜像而已,这里就很少介绍了!
除了手动生成docker镜像以外,还可使用Dockerfile自动生成镜像。Dockerfile是由一组指令组成的文件,其中每条指令对应Linux中的一条命令,Docker程序将读取Dockerfile中的指令生成指定镜像。
Dockerfile结构大体分为4个部分:基础镜像信息、维护者信息、镜像操做指令和容器启动时候执行指令。Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#”号开头的注释。
一个简单的小例子:
[root@localhost ~]# vim Dokerfile FROM centos #第一行必须指明基于的基础镜像 MAINTAINER The CentOS project <cloud-ops@centos.org> #维护该镜像的用户信息 RUN yum -y update RUN yum -y install openssh-server RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key #镜像操做指令 EXPOSE 22 #开启22端口 CMD ["/usr/sbin/sshd","-D"] #启动容器时执行指令
Dockerfile有十几条命令可用于构建镜像,其中指令如图:
Dockerfile经常使用的指令有:
1)FROM:构建镜像基于哪一个镜像; 2)MAINTAINER:镜像维护者姓名或邮箱地址; 3)RUN:构建镜像时运行的shell指令; 4)CMD:运行容器时执行的shell环境; 5)EXPOSE:声明容器的服务端口(仅仅是声明); 6)ENV:设置容器环境变量; 7)ADD:拷贝文件或目录到容器中,若是是URL或压缩包便会自动下载或自动解压; 8)COPY:拷贝文件或目录到容器中,跟ADD相似,但不具有自动下载或解压的功能; 9)ENTRYPOINT:运行容器时执行的shell命令; 10)VOLUME:指定容器挂载点到宿主机自动生成的目录或其余容器; 11)USER:为RUN、CMD、和ENTRYPOINT执行命令指定运行用户; 12)WORKDIR:为RUN、CMD、ENTRYPOINT、COPY和ADD设置工做目录,意思为切换目录; 13)HEALTHCHECH:健康检查; 14)ARG:构建时指定的一些参数;
编写Dockerfile的注意事项
(1)RUN在building时运行,能够写多条; (2)CMD和ENTRYPOINT在运行container时,只能写一条,若是写多条,最后一条生效; (3)CMD在构建容器时能够被COMMAND覆盖,ENTRYPOINT不会被COMMAND覆盖,但能够指定——entrypoint覆盖; (4)若是在Dockerfile文件中须要往镜像中导入文件,则该文件必须在Dockerfile所在目录或子目录中; (5)每一个目录下最好就只有一个Dockerfile,若是有多个Dockerfile文件时,使用Dockerfile生成镜像时便须要使用“-f”来指定具体的Dockerfile文件; (6)指令必须所有为大写; (7)使用Dockerfile生成镜像时,保证Dockerfile中所需的软件、文件与Dockerfile在同一个目录下;
案例:
[root@localhost ~]# mkdir apache [root@localhost ~]# cd apache/
[root@localhost apache]# vim Dockerfile FROM docker.io/centos MAINTAINER The CentOS Projects <cloud-ops@centos.org> RUN yum -y update RUN yum -y install httpd EXPOSE 80 ADD index.html /var/www/html/index.html ADD run.sh /run.sh RUN chmod 775 /run.sh RUN systemctl disable httpd CMD ["/run.sh"]
此Dockerfile文件使用的基础镜像是centos,因此要保证首先获取此基础镜像,使用“docker pull docker.io/centos” 获取镜像,以后的容器运行才会有效;
[root@localhost apache]# vim run.sh #!/bin/bash rm -rf /run/httpd/* //清理httpd的缓存 exec /usr/sbin/apachectl -D FOREGROUND //启动apache服务 //启动容器时,进程、脚本必须在前台启动
[root@localhost apache]# echo "weclome" > index.html //建立首页文件 [root@localhost apache]# ls Dockerfile index.html run.sh //这三个文件最好是在同一目录下
编写完成Dockerfile及相关内容后,能够经过“docker build”命令来建立镜像。
命令格式:
docker build [选项] 路径 //经常使用选项“-t”指定镜像的标签信息
[root@localhost apache]# docker build -t httpd:centos . 使用刚才创键的Dockerfile 自动生成镜像,最后必需要有一个“.”表示当前路径
[root@localhost ~]# docker run -d -p 12345:80 httpd:centos ee9adf324443b006ead23f2d9c71f86d1a4eb73358fb684ee3a2d058a0ac4243 //使用新生成的镜像加载到容器中运行 //“-p”选项实现从本地端口12345到容器中80端口的映射 [root@localhost web]# docker run -itd --name nginx centos:nginx nginx -g "daemon off;" //不进入容器,便可开启容器中的Nginx服务
[root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ee9adf324443 httpd:centos "/run.sh" About a minute ago Up About a minute 0.0.0.0:12345->80/tcp admiring_bardeen //查看该镜像已经在容器中的状态
验证访问结果:
随着创键的镜像增多,就须要有一个保存镜像的地方,这就是仓库。目前有两种仓库:公共仓库和私有仓库。最方便的就是使用公共仓库上传和下载,下载公共仓库的镜像是不须要注册的,可是上传时,是须要注册的。下面介绍如何建立私有仓库。
方法以下:
[root@localhost ~]# docker pull registry:2 //下载registry:2的镜像 [root@localhost ~]# docker run -itd --name registry --restart=always -p 5000:5000 -v /registry:/var/lib/registry registry:2 //-p:端口映射(前面是宿主机端口:后面是容器暴露的端口) //-v:挂载目录(前面是宿主机的目录:后面的是容器的目录)自动建立宿主机的目录 [root@localhost ~]# docker tag centos:nginx 192.168.1.1:5000/centos:nginx [root@localhost ~]# vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd --insecure-registry 192.168.1.1:5000 //修改本来的配置文件添加不安全的仓库,地址是宿主机的IP地址与5000端口 [root@localhost ~]# systemctl daemon-reload [root@localhost ~]# systemctl restart docker //从新启动docker服务 [root@localhost ~]# docker ps //确认registry容器正常运行 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2645c31b2306 registry:2 "/entrypoint.sh /etc…" 21 minutes ago Up 42 seconds 0.0.0.0:5000->5000/tcp registry [root@localhost ~]# docker push 192.168.1.1:5000/centos:nginx //上传镜像到私有仓库
私有仓库搭建完成,验证成功!这时打开另外一台docker主机下载进行测试:
[root@localhost ~]# vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd --insecure-registry 192.168.1.1:5000 //修改本来的配置文件添加不安全的仓库,地址是registry主机的IP地址与5000端口 [root@localhost ~]# systemctl daemon-reload [root@localhost ~]# systemctl restart docker //从新启动docker服务 [root@localhost ~]# docker run -itd --name nginx 192.168.1.1:5000/centos:nginx nginx -g "daemon off;" //基于镜像建立容器 [root@localhost ~]# docker inspect nginx //查看容器的详细信息 [root@localhost ~]# curl 172.17.0.3 //测试访问
私有仓库这是才算搭建完成!测试完成!
在Docker中,为了方便查看容器内产生的数据或者将多个容器之间的数据实现共享,会涉及容器的数据管理操做。
管理Docker容器中的数据主要有两种方式:数据卷和数据卷容器。
数据卷是一个供容器使用的特殊目录,位于容器中,可将宿主机的目录挂载到数据卷上,对数据卷的修改操做马上可见,而且更新数据不会影响镜像,从而实如今宿主机与容器之间的迁移,数据卷的使用相似于Linux下对目录进行的挂载操做。
在“docker run”命令中使用“-v”选项能够在容器内建立数据卷。屡次使用“-v”选项能够建立多个数据卷。使用“--name”选项能够给容器建立一个友好的自定义名称。
[root@localhost ~]# docker run -itd -v /data1 -v /data2 --name web httpd:centos /bin/bash 27f2f2dad06de5685d253da6baab3808165e0f02fb99ed3fefbdd68e231f7c1b //使用httpd:centos镜像建立一个名为web的容器,并建立两个数据卷挂载到/data1和/data2目录上 [root@localhost ~]# docker exec -it web /bin/bash //进入容器并查看两个目录是否存在 [root@27f2f2dad06d /]# ls | grep data data1 data2
使用“-v”选项能够在建立数据卷的同时,将宿主机的目录挂载到数据卷上使用,以实现宿主机与容器之间的数据迁移。
注意:宿主机本地目录的路径必须使用绝对路径,若是路径不存在,Docker会自动建立相应的路径。
[root@localhost ~]# docker run -itd -v /var/www:/data1 --name web1 httpd:centos /bin/bash ded73d50ff68ac43e789d8acf3bf9d0135f43bec28e99e14739e4085fb2ce802 //使用httpd:centos镜像建立一个名为web1的容器,并将宿主机的/var/www目录挂载到容器的/data1目录上 [root@localhost ~]# touch /var/www/file //宿主机本地建立测试文件 [root@localhost ~]# docker exec -it web1 /bin/bash [root@ded73d50ff68 /]# ls /data1 //容器中相应的目录也会存在相应的文件 file
宿主机的目录发生的变化会自动同步到容器中,相反也是同样!
若是须要在容器之间共享一些数据,最简单的方法就是使用数据卷容器。数据卷容器就是一个普通的容器,专门提供数据卷给其余容器挂载使用。
[root@localhost ~]# docker run -it --volumes-from web1 --name db1 httpd:centos /bin/bash //使用实现建立好的容器web1,使用“--volumes-from”来挂载web1容器中的数据间到新的容器db1 [root@fb4b0f01b102 /]# ls /data1 file [root@fb4b0f01b102 /]# touch /data1/file1 //db1容器在/data1目录下建立一个新的文件 [root@fb4b0f01b102 /]# exit exit [root@localhost ~]# docker exec -it web1 /bin/bash [root@ded73d50ff68 /]# ls /data1 //进入web1容器查看 file file1
这样就能够经过数据卷容器实现容器之间的数据共享。
经过这些机制,即便容器在运行过程当中出现故障,用户也不用担忧数据发生丢失。若是发生意外,只需快速从新建立容器便可!
注意:生产环境中最注重的就是存储的可靠性,以及存储的可动态扩展性,必定要在作数据卷时考虑到这一点,在这方面比较出色的还要数GFS文件系统了,我上面只是作了简单的配置,若在生产环境中,必定要好好考虑,就好比上面作的镜像卷容器,就能够在宿主机本地挂载GFS文件系统,而后建立镜像卷容器时,将挂载GFS的目录映射到容器中的镜像卷,这样才是一个合格的镜像卷容器。
Docker提供了映射容器端口到宿主机和容器互联机制来为容器提供网络服务。
在启动容器的时候,若是不指定对应的端口,在容器外是没法经过网络来访问容器内的服务的。Docker提供端口映射机制来将容器内的服务提供给外部网络访问,实质上就要将宿主机的端口映射到容器中,使得外部网络访问宿主机的端口能够访问容器内的服务。
实现端口映射,须要在运行“docker run”命令时使用“-P(大写)”选项能够实现随机映射,Docker会随机映射一个端口范围在49000~49900的端口到容器内部开放的网络端口,可是不是绝对的,也有例外不会映射到这个范围内。这种状况并非很经常使用。
[root@localhost ~]# docker run -d --name httpd -P httpd:centos //建立容器httpd,并随即生成一个端口 52791358bfbb6d054e3d5ea65ad6e87c68c538328ceef66c7398571eddd2b066 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 52791358bfbb httpd:centos "/run.sh" 8 seconds ago Up 7 seconds 0.0.0.0:32769->80/tcp httpd //查询得知,内部的80端口映射到本机的32769端口
这种方法并不经常使用。通常都使用“-p(小写)”指定要映射的端口。
[root@localhost ~]# docker run -d --name httpd -p 49888:80 httpd:centos //将容器的80端口映射到本机的49888端口 f015df59a80b2e7048f63dacebd35b75db033bcb3bb529074849912bc7e7003f [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f015df59a80b httpd:centos "/run.sh" 3 seconds ago Up 3 seconds 0.0.0.0:49888->80/tcp httpd
容器互联是经过容器的名称在容器间创建一条专门的网络通讯隧道从而实现的互联。
注意:容器互联是经过容器的名称来执行的,“--name”选项能够给容器建立一个友好的名称,这个名称是惟一的,若是已经命名了一个相同名称的容器,当要再次使用这个名称的时候,需先使用“docker run”来删除以前建立的同名容器。
[root@localhost ~]# docker run -tid -P --name w1 httpd:centos /bin/bash fb8f64661062565e48a969b30759eb781ffddc60913aa93ff6b63f098e8f2c6a //使用“docker run”命令建立容器A,指定名称为web1
[root@localhost ~]# docker run -tid -P --name w2 --link w1:w1 httpd:centos /bin/bash fda898cc44e1c5415679c92e7b2ab65f3dfb56a0bc5b8563086c988070a02a3a //使用“docker run”命令建立容器B,指定名称为web2,使用“--link”选项与web1互联
[root@localhost ~]# docker exec -it w2 /bin/bash [root@fda898cc44e1 /]# ping w1 PING w1 (172.17.0.2) 56(84) bytes of data. 64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.051 ms 64 bytes from web1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.072 ms //这时能够看出web2容器已经和web1容器创建互联关系
若是如今还要在加入一个容器C,使容器C与容器A和容器B进行互联,进行一下操做:
[root@localhost ~]# docker run -dit -P --name w3 --link w1:w1 --link w2:w2 httpd:centos /bin/bash bfedb9d94d18d07af2eda92d06e176479e22f342cfad7f5d8b034116e05040fd //建立容器C,使其与容器A、容器B进行互联 [root@localhost ~]# docker exec -it b3 /bin/bash [root@bfedb9d94d18 /]# ping w1 PING w1 (172.17.0.2) 56(84) bytes of data. 64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.052 ms 64 bytes from web1 (172.17.0.2): icmp_seq=2 ttl=64 time=0.166 ms ^C --- web1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.052/0.109/0.166/0.057 ms [root@bfedb9d94d18 /]# ping w2 PING w2 (172.17.0.3) 56(84) bytes of data. 64 bytes from web2 (172.17.0.3): icmp_seq=1 ttl=64 time=0.051 ms 64 bytes from web2 (172.17.0.3): icmp_seq=2 ttl=64 time=0.063 ms ^C --- web2 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.051/0.057/0.063/0.006 ms //测试成功
———————— 本文至此结束,感谢阅读 ————————