1、Docker镜像的建立方法
docker镜像是除了docker的核心技术以外,也是应用发布的标准格式。一个完整的docker镜像能够支撑一个docker容器的运行,在docker的整个使用过程当中,进入一个已经定型的容器以后,就能够在容器中进行操做,最多见的操做就是在容器中安装应用服务,若是要把已经安装的服务进行迁移,就须要把环境及搭建的服务生成新的镜像。html
建立镜像的方法有三种,分别是基于已有镜像建立、基于本地模板建立及基于dockerfile建立。node
一、基于已有镜像建立
基于已有镜像建立主要使用 docker commit 命令,其实质就是把一个容器里面运行的程序及该程序的运行环境打包起来生成新的镜像。linux
命令格式:docker commit [选项] 容器ID/名称 仓库名称:[标签]
经常使用选项
-m:说明信息;
-a:做者信息;
-p:生成过程当中中止容器的运行;docker
启动一个镜像,在容器里作修改,而后将修改后的容器提交为新的镜像,须要记住该容器的ID号apache
[root@test /]# docker ps -a # 查看当前容器 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bdd5bb814008 docker.io/networkboot/dhcpd "/entrypoint.sh /b..." 5 seconds ago Created stupefied_ptolemy [root@test /]# docker exec -it bdd5bb814008 /bin/bash # 进入到该容器,建立一个测试文件 root@bdd5bb814008:/# ls bin boot core dev entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var root@bdd5bb814008:/# touch test.txt root@bdd5bb814008:/# exit exit [root@test /]# docker commit -m "newdhcp" -a "test" bdd5bb814008 docker:mydhcp # 将已有容器创为镜像 sha256:d6197c6e3f650d3ef69d13324634759705821b0ed516e8fe631fded72acb9d54 [root@test /]# docker images | grep docker # 查看刚刚建立好的镜像 docker mydhcp d6197c6e3f65 24 seconds ago 125 MB docker.io/networkboot/dhcpd latest 6f98b6b9b486 19 months ago 125 MB [root@test /]# docker create -it docker:mydhcp /bin/bash # 添加为容器 ea434b08d511867be662704ee81d0b5876e922efa50f5f52843daa762185c16a [root@test /]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ea434b08d511 docker:mydhcp "/entrypoint.sh /b..." 25 seconds ago Created compassionate_shirley bdd5bb814008 docker.io/networkboot/dhcpd "/entrypoint.sh /b..." 5 minutes ago Up 4 minutes stupefied_ptolemy [root@test /]# docker start ea434b08d511 # 启动该容器 ea434b08d511 [root@test /]# docker exec -it ea434b08d511 /bin/bash # 进入到该容器,查看刚刚所建立的测试文件 root@ea434b08d511:/# ls bin boot core dev entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys test.txt tmp usr var
二、基于本地模板建立
经过导入操做系统模板文件能够生成镜像,模板能够从 OPENVZ 开源项目下载,下载地址为:http://openvz.org/Download/template/precreated json
[root@test /]# wget http://download.openvz.org/template/precreated/ubuntu-14.04-x86_64-minimal.tar.gz # 下载一个迷你版的Ubuntu模板 [root@test /]# cat ubuntu-14.04-x86_64-minimal.tar.gz | docker import - docker:new sha256:7457fecee0fb28ab06d935e7a9a5a040d9d6ec8931959b752f596cde76a5d647 # 将模板导入 [root@test /]# docker images |grep new # 查看已经导入 docker new 7457fecee0fb About a minute ago 215 MB
三、基于 Dockerfile 建立
dockerfile是由一组指令组成的文件,其中每条指令对应Linux中的一条命令,docker程序将读取dockerfile中的指令生成指定镜像。ubuntu
dockerfile结构大体分为四个部分:基础镜像信息、维护者信息、镜像操做指令和容器启动时执行指令。dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用“#”号开头的注释。
dockerfile中的配置项介绍:vim
[root@localhost ~]# docker tag docker:new centos7:system #将上面下载的centos 7迷你镜像更改下名字及标签,以便区分 [root@localhost ~]# docker images | grep system #确认基础镜像已经准备好(就是一个centos 7的迷你系统进行) centos7 system c065d5c0571d About an hour ago 435 MB [root@localhost ~]# vim Dockerfile #编辑一个Dockerfile文件,注意:文件名最好就是Dockerfile FROM centos #第一行必须指明基于的基础镜像(该镜像必须存在) MAINTAINER The centos project <ljz@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时,有严格的格式须要遵循:第一行必须使用FROM指令指明所基于的镜像名称;以后使用MAINTAINER指令说明维护该镜像的用户信息;而后是镜像操做相关指令,如RUN指令,每运行一条指令,都会给基础镜像添加新的一层;最后使用CMD指令来指定启动容器时要运行的命令操做。centos
dockerfile有十几条命令可用于构建镜像,其中常见的指令以下:缓存
例:使用dockerfile建立apache镜像并在容器中运行
[root@test /]# mkdir apache # 建立工做目录 [root@test /]# cd /apache/ [root@test apache]# vim Dockerfile # 建立并编写 Dockerfile文件 FROM centos # 基于的基础镜像centos MAINTAINER the centos # 维护该镜像的用户信息 RUN yum -y update # 镜像操做指令安装 Apache 软件包 RUN yum -y install httpd EXPOSE 80 # 开启80端口 ADD index.html /var/www/html/index.html # 复制网站首页文件 ADD run.sh /run.sh # 将执行脚本复制到镜像中 RUN chmod 775 /run.sh RUN systemctl disable httpd # 设置Apache服务不自行启动 CMD ["/run.sh"] # 启动容器时执行脚本 [root@test apache]# vim run.sh # 编写执行脚本内容 #!/bin/bash rm -rf /run/httpd/* # 清理 httpd 缓存 exec /usr/sbin/apachectl -D FOREGROUND # 启动Apache服务 [root@test apache]# echo "www.test.com" > index.html # 建立测试页面 [root@test apache]# ls Dockerfile index.html run.sh [root@test apache]# docker build -t httpd:centos . ............................ // 省略部份内容 # 注意注意注意:这条命令后面有一个“.” 表明当前路径,不然会报错,切记千万不要忘记
[root@test apache]# docker run -d -p 12345:80 httpd:centos # 使用新的镜像运行容器,-p 选项实现从本地端口12345到容器的80端口映射 0721b1641ce0651d618a393b85d34606180dd33d4795621db320865cda8f3a0a [root@test apache]# docker ps -a # 查看容器 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0721b1641ce0 httpd:centos "/run.sh" 6 seconds ago Up 6 seconds 0.0.0.0:12345->80/tcp sad_mcclintock
访问容器中的apache服务
2、搭建私有库及其使用方法
随着建立的镜像增多,就须要有一个保存镜像的地方,这就是仓库,目前有两种仓库:公共仓库和私有仓库,公司的生产环境中大多数都是保存到私有仓库的,最简单的仍是在公共仓库上下载镜像,如果上传镜像至公共仓库,还须要注册并登录,关于公共仓库的上传,能够参考https://blog.51cto.com/14227204/2453408
怎么构建私有仓库呢?可使用registry来搭建本地私有仓库
[root@test ~]# docker search registry #查询关键字“registry” INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED docker.io docker.io/registry The Docker Registry 2.0 implementation for... 2679 [OK] ..................#省略部份内容 [root@localhost ~]# docker pull docker.io/registry #下载排名靠前的镜像 ..................#省略部份内容 Status: Downloaded newer image for docker.io/registry:latest #下载成功 [root@localhost ~]# vim /etc/sysconfig/docker #修改docker配置文件指定私有仓库URL,不然在自定义的私有仓库中上传镜像时会报错 # /etc/sysconfig/docker # Modify these options if you want to change the way the docker daemon runs OPTIONS='--selinux-enabled --insecure-registry=192.168.1.1:5000' #更改上面一行内容,其中的IP地址是做为私有仓库服务器的IP地址,这里就是本机的IP地址。 ..................#省略部分 #修改完毕后保存退出 [root@test ~]# systemctl restart docker #重启docker
使用下载好的registry镜像启动一个容器,默认状况下仓库存放于容器内的/tmp/registry目录下,使用-v选项能够将本地目录挂载到容器内的/tmp/registry目录下使用,这样就不怕容器被删除后镜像也会随之丢失。在本地启动一个私有仓库服务,监听端口号为5000。
注意:我本地有一个/data/registry目录(挂载的是一个高可用的GFS文件系统,也可使用NFS,自行选择便可,可是建议对于重要的数据存放目录,必定要保证容量的动态扩展以及磁盘损坏形成数据丢失的问题),将要挂载到私有仓库容器中的/tmp/registry目录中用于存放上传到私有仓库的镜像文件。
[root@test ~]# df -hT /data/registry/ #查看我这个目录所使用的文件系统 文件系统 类型 容量 已用 可用 已用% 挂载点 node4:dis-stripe fuse.glusterfs 80G 130M 80G 1% /data/registry [root@test ~]# docker run -d -p 5000:5000 -v /data/registry/:/tmp/registry docker.io/registry #启动私有仓库,并作端口映射到主机的5000端口,将本地的/data/registry目录挂载到容器中的/tmp/registry目录 #docker.io/registry是刚才下载的私有仓库镜像。 a6bf726c612b826e203d6a5bc9eaba26c36195913d3ea546c2111ce290a5524d [root@test ~]# docker tag docker.io/registry 192.168.1.1:5000/registry #使用docker tag命令将要上传的镜像docker.io/registry改一下标记,其中的IP及端口为固定的,不然没法链接到私有仓库 #由于在上面运行容器时,作了端口映射,将私有仓库的端口号映射到了宿主机的5000端 口, #因此直接访问宿主机的5000端口,就至关于访问了私有仓库。 [root@test ~]# docker images | grep 5000 #找到要上传的镜像 192.168.1.1:5000/registry latest f32a97de94e1 6 months ago 25.8 MB [root@test ~]# docker push 192.168.1.1:5000/registry #上传至刚刚运行的私有仓库 The push refers to a repository [192.168.1.1:5000/registry] 73d61bf022fd: Pushed 5bbc5831d696: Pushed d5974ddb5a45: Pushed f641ef7a37ad: Pushed d9ff549177a9: Pushed latest: digest: sha256:b1165286043f2745f45ea637873d61939bff6d9a59f76539d6228abf79f87774 size: 1363 #下面再上传一个镜像,进行测试。 [root@test ~]# docker images | grep mynamed #就上传它了 docker mynamed e178f320e482 4 hours ago 323 MB [root@test ~]# docker tag docker:mynamed 192.168.1.1:5000/named:test #老规矩,必须改仓库名,注意:若标签不是默认的latest,那么还须要在仓库名后面接上标签名 [root@test ~]# docker images | grep 192.168.1.1:5000/named #肯定更改为功 192.168.1.1:5000/named test e178f320e482 4 hours ago 323 MB [root@test ~]# docker push 192.168.1.1:5000/named:test #上传至私有仓库 The push refers to a repository [192.168.1.1:5000/named] c756b9ec7fb0: Pushed 7d8d01394159: Pushed 72b7cd87d69b: Pushed 3be48ef75683: Pushed 9b28c58ad64b: Pushed 75e70aa52609: Pushed dda151859818: Pushed fbd2732ad777: Pushed ba9de9d8475e: Pushed test: digest: sha256:44894a684eac72a518ae5fa66bcbe4e4a9429428ef7ac6f4761022f8ac45ac5f size: 2403
至此,测试就完毕了,可是,如何证实私有仓库使用的是本地的/data/registry这个目录呢?以及如何查看上传的镜像呢?(上传至私有仓库的镜像是没法使用普通的ls命令查看的)。
[root@test ~]# df -hT /data/registry/ #先查看本地/data/registry/ 挂载的文件系统 文件系统 类型 容量 已用 可用 已用% 挂载点 node4:dis-stripe fuse.glusterfs 80G 130M 80G 1% /data/registry [root@test ~]# docker exec -it a6bf726c612b /bin/sh #进入私有仓库的容器中,该容器没有/bin/bash,因此使用的是/bin/sh。 / # df -hT /tmp/registry/ #查看发现,该目录挂载的和宿主机挂载的文件系统是同一个,说明没问题。 Filesystem Type Size Used Available Use% Mounted on node4:dis-stripe fuse.glusterfs 80.0G 129.4M 79.8G 0% /tmp/registry —————————————————————— #那么如何查看上传至私有仓库的镜像呢?请看下面: [root@test ~]# curl -XGET http://192.168.1.1:5000/v2/_catalog #查看已经上传的镜像,能够看到刚刚上传的那两个镜像 {"repositories":["named","registry"]} #只知道镜像名还不够,若要下载,还须要镜像对应的标签,那么怎么查看某个镜像的标签呢? [root@test ~]# curl -XGET http://192.168.1.1:5000/v2/named/tags/list #就这样查看咯,上面URL路径中的named就是镜像名,查看的就是镜像named对应的标签 {"name":"named","tags":["test"]} [root@test ~]# docker pull 192.168.1.1:5000/named:test #将私有仓库中的镜像下载下来 #前面必须指定私有仓库的访问地址,就是上传时的名字是什么,下载时就是什么,哪怕查询的镜像名中没有IP地址。 Trying to pull repository 192.168.1.1:5000/named ... sha256:44894a684eac72a518ae5fa66bcbe4e4a9429428ef7ac6f4761022f8ac45ac5f: Pulling from 192.168.1.1:5000/named Digest: sha256:44894a684eac72a518ae5fa66bcbe4e4a9429428ef7ac6f4761022f8ac45ac5f Status: Downloaded newer image for 192.168.1.1:5000/named:test
若须要在其余服务器上下载私有仓库的镜像,须要在那个其余服务器上执行如下命令,以便指定私有仓库服务器地址:
[root@node1 ~]# echo '{ "insecure-registries":["xxx.xxx.xxx.xxx:5000"] }' > /etc/docker/daemon.json #其中xxx.xxx.xxx.xxx:5000表明访问私有仓库的IP地址及端口,根据本身的服务器状况来定 [root@node1 ~]#systemctl restart docker #重启docker服务