基础知识不回顾了,直接上。
docker的安装与启动
yum remove docker -y
yum install docker-io -y # 需要先配置好epel源
/etc/init.d/docker start
chkconfig docker on
获取镜像
docker pull centos # 从docker仓库下载一个镜像例如:docker pull centos:6.7
docker images #列出本地已存在的镜像
docker images centos # 查看指定的镜像
运行
# docker run centos /bin/echo'Hello world'
# docker run -i -t centos:6.7/bin/bash
-i表示输入终端保持打开状态
-t表示开一个伪终端,并绑定到标准输入上
-c限制运行的某个容器的CPU配额【最大默认是1024】
--cpuset-cpus= 设置可以绑定使用几个CPU,具体可以看help
-d 表示后台运行容器,只输出容器的ID到屏幕
-P表示--publish-all=false Publish all exposed ports to random ports
--hostname=docker1.demo.com 表示修改容器的hsotname
--name=lnmp1 表示给启动的容器命名,不用随机名称
--dns=xx.xx.xx.xx 自定义DNS服务器地址【不指定该参数的话,就是要外部主机的/etc/resolv.conf来配置容器】
--add-host "www.demo.com:192.168.2.2" 在容器的/etc/hosts添加一条指定的DNS解析记录
--expose80 --expose 8080 # 暴露端口在外部Expose a port or a range of ports
--memory1G 限制容器最大使用的内存
*centos后面如果不指定版本,则默认选择latest版本
输入exit或者Ctrl+d退出
# docker run -ti --name test3--hostname=docker1.demo.com --dns=192.168.2.2 --dns=8.8.8.8 lanmp:v1 /bin/bash # 复杂的写法
# docker run -d ubuntu:14.04/bin/sh -c "while true; do echo hello world; sleep 1; done" 以后台进程模式运行
# docker logs 后面跟容器的NAMES
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
检查本地是否存在指定的镜像,不存在就从公有仓库下载
利用镜像创建并启动一个容器
分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
从地址池配置一个 ip 地址给容器
执行用户指定的应用程序
执行完毕后容器被终止
# docker ps 查看在运行中的docker实例进程
# docker logs insane_babbage 查看容器中的标准输出
# docker stop insane_babbage 停止某个容器
# docker ps可以看到刚才启动的那个centos容器没有了
# docker ps -a 可以看到所有的容器(包括已停止的)
# docker start insane_babbage # 如果加-i参数可以进入交互式的容器
# docker version 查看docker客户端版本和进程的版本信息
ubuntu容器安装软件:
默认安装好的ubuntu docker是没有vim和ping这些命令的。
进入容器后,执行
# apt-get update
# apt-get install vim -y
然后vi /etc/apt/sources.list 添加阿里云的源地址。
# apt-get install inetutils-ping-y
# ping www.qq.com 即可
查看帮助信息
# docker 只输入docker指令,系统会自动列出全部可用的命令列表
# docker images --help
创建镜像方法1:修改镜像
# docker run -i -t centos:6.7/bin/bash 记下容器的ID,例如:e2d6c890682f
在容器中添加LAMP环境
# yum install httpd mysql mysql-server php php-mysql -y
# exit 退出容器
# docker commit -m "Add LAMPenv" -a "CentOS_LAMP" e2d6c890682f 6.7lamp 提交更新后的副本
-m message
-a author
# docker images 可以看到已经生成了一个镜像
# docker run -i -t 6.7lamp/bin/bash 用刚才创建的镜像启动容器
另外,可以使用docker commit -m 'my nignx' e2d6c890682fdemo/my_nginx:v1 这种创建带明显标志的镜像。
启动的话使用docker run -d -p 88:80 --name "ningx_1" demo/my_nginx:v1 即可。
方法2、dockerfile创建基于centos6.7的nginx的容器
mkdir /opt/docker-file
cd /opt/docker-file
mkdir nginx && cd nginx
vi Dockerfile 内容如下:
# This is My First Dockerfile
# Verson 1.0
# Author: Lee
FROM centos:6.7
MAINTAINER Lee
ADD pcre-8.36.tar.gz/usr/local/src <--- 1、需要事先把这个tar.gz包拷贝到当前目录下,即和Dockerfile在同一个目录下
ADD nginx-1.11.5.tar.gz/usr/local/src <---2、如果是个压缩包,拷到容器后会自动解压的,无需我们解压操作
RUN rm -fr /etc/yum.repos.d/*
RUN wget -O/etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
RUN wget -O/etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
RUN yum clean all
RUN yum install -y wget gcc gcc-c++ make openssl-devel
RUN useradd -s /sbin/nologin -Mwww
WORKDIR/usr/local/src/nginx-1.11.5
RUN ./configure--prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status--with-pcre=/usr/local/src/pcre-8.36 && make && make install
RUN echo 'daemon off;' >>/usr/local/nginx/conf/nginx.conf
RUN sed 's@#user nobody;@user www;@g' nginx.conf
ENV PATH/usr/local/nginx/sbin:$PATH
EXPOSE 80
CMD ["nginx"]
docker build -t dockfile:v2 . 这样就可以创建镜像了
启动刚才创建的nginx docker容器的话,使用docker run -d -p 8888:80 dockfile:v2即可。
参数说明:
指令:
FROM <image>[:tag>] 或者FROM <image>@<digest> # 必须是第一个非注释的行,用于指定所用到的基础镜像
MAINTAINER <author's detail>
COPY ["<src>", ..."<dest>"] 复制本地主机的目录到容器里的指定目录
<src>是要复制的源文件或目录,支持通配符
<dest>目标路径,正在创建的镜像文件的文件系统路径(建议使用绝对路径)
说明:所有新复制生成的目录文件的UID和GID都是0
例如: COPY /home/template/server.xml/etc/tomcat/server.xml
COPY *.conf /etc/httpd/conf.d/
注意:src 必须是build上下文的路径,即不能使用类似../../conf/*.conf,但是还是可以使用绝对路径例如/home/conf.d/*.conf ;src如果是目录的话,递归复制会自动进行;如果有多个src,包括在src上使用了通配符,此时dest必须是目录,而且必须得以/结尾。
dest如果事先不存在,它会被自动创建,包括其父目录。
ADD 类似COPY指令,额外还支持复制tar格式的文件及URL路径。【ADD比COPY用得更常见些】
例如:ADD haproxy.cfg /etc/haproxy/haproxy.cfg
ADDlogstash_*.cnf /etc/logstash/
ADD http://www.demo.com/download/nginx.conf/etc/nginx/ 【URL格式指定的源文件,下载完成后其目标文件权限为600】
如果src是一个宿主机上的tar文件,则它将被解压展开成要给目录(类似tar xf命令,如果通过URL下载的是个tar文件,则不会被自动展开)
ENV 定义环境变量,此些变量可以被当前dockerfile文件中的其它指令所调用,调用格式为$variable_name或${variable_name}
语法:
ENV<key> <value> 一次定义一个变量
或者 ENV <key>=<value>... 一次可以定义多个变量,如果value中有空白字符,要是\进行转义
如: ENV myName="Tom Lee" myDog='wang cai'
说明:ENV定义的环境变量在镜像运行的整个过程中一直存在,因此可以使用docker inspect查看,甚至可以用docker run --env=xxx 来修改其值
USER 指定运行容器时,或者运行RUN CMD ENTRYPOINT指令指定的程序时使用的用户名或者UID
格式: USER <UID>|<Username>
WORKDIR 为后续的RUN、CMD、ENTRYPOINT、COPY、ADD指令配置工作目录
如:
WORKDIR/a
WORKDIRb
WORKDIRc
RUNpwd
则最终路径为 /a/b/c
另外, WORKDIR还可以调用由ENV定义的环境变量的值,如: WORKDIR $STATEPATH
ENTRYPOINT
VOLUME 在目标镜像文件中创建一个挂载点,用来挂载主机上的卷或其他容器的卷。一般用来存放数据库和需要保持的数据等。
VOLUME<mountpoint>
例如: VOLUME ["/data/mysql","/data/Images"]
注意:如果mountpoint路径下事先有文件存在,则在挂载完成后,会同时显示当前的文件和挂载前的文件(AUFS的叠加原理)。
RUN
每个RUN都会另起一层,所以建议将多个命令放到一行,减少AUFS的层数。
格式:
RUN <command> # 会启动一个shell解释器
或RUN ["<executeable>","<param1>","<parma2>",...] # 不会启动shell解释器
例如:
RUNyum install iproute nginx && yum clean all
RUN['/bin/bash','-c','yum','install','httpd']
CMD 设定在docker run时默认执行的命令
格式: CMD <command> 或CMD ["<executeable>","<param1>","<parma2>"]
或CMD["<param1>","<param2>",...] 为ENTRYPOINT指令指定的程序提供默认参数。
如果dockerfile中存在多个CMD指令,则只有最后一个生效。
例如:
CMD["/usr/sbin/httpd","-c","/etc/httpd/conf/httpd.conf"]
ENTRYPOINT 类似CMD指令,但其不会被docker run的命令行参数指定的指令所覆盖。且这些命令行参数会被当中参数送给ENTRYPOINT指令指定的程序
如果运行docker run时使用了--entrypoint选项,则此选项的参数可以覆盖掉dockerfile默认的entrypoint参数。
格式:
ENTRYPOUNT<command>
ENTRYPOUNT["executeable","<param1>","<param2>",...]
例如:
注意:
如果CMD和ENTRYPOINT都存在的话,则CMD的指令会被附加到ENTRYPOINT后,变成ENTRYPOINT的参数。
EXPOSE 用于为容器指定要暴露的端口
格式:EXPOSE<port>[/protocol>][<port>[/<protocol>]]...
如:
EXPOSE11211/tcp 11211/udp
ONBUILD 配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令
例如: ONBUILD ADD my.cnf /etc/mysql/my.cnf
注意:ONBUILD不能自我嵌套,且不会触发。
导出镜像
# docker save -o/root/centos_lamp_v3.tar centos/lamp:v3
导入镜像
# docker load--input /root/centos_lamp_v3.tar
或者docker load </root/centos_lamp_v3.tar
# 这将导入镜像以及其相关的元数据信息(包括标签等)
移除镜像
# docker rmicentos/lamp:v3
注意:在删除镜像之前要先用dockerrm 删掉依赖于这个镜像的所有容器。
想要删除untagged images,也就是那些id为<None>的image的话可以用
# docker rmi$(docker images | grep "^<none>" | awk "{print $2}")
要删除全部image的话
# docker rmi$(docker images -q)
删除已停止的容器
# docker rm -f$(docker ps -a -q)
移除容器
# docker rm5d6da6754d01
停止所有的container,这样才能够删除其中的images:
# docker stop$(docker ps -a -q)
如果想要删除所有container的话再加一个指令:
# docker rm$(docker ps -a -q)
从本地文件系统导入一个镜像
要从本地文件系统导入一个镜像,可以使用 openvz(容器虚拟化的先锋技术)的模板来创建: openvz 的
模板下载地址为 templates 。
比如,先下载了一个 ubuntu-14.04 的镜像,之后使用以下命令导入:
catubuntu-14.04-x86_64-minimal.tar.gz |docker import - ubuntu:14.04
上传镜像
docker pushouruser/sinatra
进入容器
在使用 -d 参数时,容器启动后会进入后台。某些时候需要进入容器进行操作,有很多种方法,包括使用docker attach 命令或 nsenter 工具等
# docker attach 容器NAME
或者docker exec-ti 容器ID /bin/bash
但是使用 attach 命令有时候并不方便。当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。使用attach进到容器后要退出的话,只能关闭xshell了,使用exit会导致整个容器的退出。
nsenter 这个进入容器的命令也很好用(如果没有的话需要安装util-linux-ng)。
方法:
dockerinspect --format"``.`State`.`Pid`" 容器NAME或者容器ID号 # 结果会输出一个容器的pid号
nsenter --target 容器的pid号 --mount --uts --ipc --net--pid
上面2条命令可以做成脚本,in.sh 内容如下:
#!/bin/bash
CNAME=$1
CPID=$(dockerinspect --format"``.`State`.`Pid`" $CNAME)
nsenter--target $CPID --mount --uts --ipc --net --pid
sh in.sh 容器的NAME或者ID号,即可进入容器。
导出容器快照到本地文件
# docker ps -a
# docker export 容器名称 > ubuntu.tar
导入容器快照为镜像
# cat ubuntu2.tar |docker import - test/ubuntu:v1
# docker images
自己基于centos构建nginx容器:
首先启动一个centos容器,然后在里面安装nginx(我这里是yum安装的nginx)。
修改nginx的配置文件,加上daemon off; 参数。
然后继续。下面有2种方法启动容器时候让它自动启动nginx
方法1:
dockercommit -m 'nginx_v1' eb919426f773 6.7_nginx_v1
dockerrun -d -p 888:88 --name 'nginx_v1' 6.7_nginx_v1 /usr/sbin/nginx
这样就可以了。
方法2:
修改容器的/etc/bashrc 加上/usr/sbin/nginx -c/etc/nginx/nginx.conf
dockerrun -d -p 888:88 --name 'nginx_v1' 6.7_nginx_v1 /bin/bash
docker私有仓库的搭建
【作为仓库的虚拟机IP为:192.168.2.11】:
# 必须先启动docker registry【centos6上是这样的。在centos7上则变成了一个守护进程,需要用systemctl来启动】
# docker pullregistry
# docker run -d-p 5000:5000 -v /opt/data/registry:/tmp/registry registry
# docker ps 记下容器NAME为kickass_wright
# 默认情况下,仓库会被创建在容器的 /tmp/registry 下。可以通过 -v 参数来将镜像文件存放在本地的指定路径。
# docker images 列出当前的镜像
# docker tag88e44a5cbd17 192.168.2.11:5000/centos/lamp
格式:dockertag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
# docker images
Docker从1.3.X之后,与docker registry交互默认使用的是https,然而此处搭建的私有仓库只提供http服务,所以当与私有仓库交互时就会报上面的错误。为了解决这个问题需要在启动docker server时增加启动参数为默认使用http访问。
修改docker配置文件将代码加到/etc/sysconfig/docker的other_args="--insecure-registry192.168.2.11:5000"里面。
# docker stopkickass_wright 停掉registry容器
#/etc/init.d/docker restart 重启docker
# docker startkickass_wright 启动registry容器
# docker push192.168.2.11:5000/centos/lamp 将本地镜像推送到本机上的私有服务器上
这样本地镜像就是上次到私有docker 仓库了。
我们可以在其他节点测试能否下载这个镜像。如果没问题的话,就可以在本机上删除原有的docker镜像,如下:
# docker rmi 192.168.2.11:5000/centos/lamp
在Node2节点(192.168.2.12)测试:
# yum installdocker-io -y
修改docker配置文件将代码加到/etc/sysconfig/docker的other_args="--insecure-registry192.168.2.11:5000"里面。
#/etc/init.d/docker restart 重启docker
# docker pull192.168.2.11:5000/centos/lamp 从192.168.2.11的私有仓库下载镜像
# docker images 可以看到已经下载好了相关的镜像
docker的监控命令:
docker ps [-a]
docker images
docker stats Container_name # 实时查看某个容器的负载情况
docker top Container_name # 实时查看某个容器的状态统计(类似top命令)
dockerinspect # 查看容器或镜像的底层信息
例如:docker inspect -f'``.`Config`.`Hostname`' d413082da04e 类似ansible的 ansible -m setup的输出格式
此外,还有谷歌提供的CAdvisor web界面的监控工具;Scout工具,Data Dog工具,等。具体可参考: http://dockone.io/article/397
数据卷:
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
-
数据卷可以在容器之间共享和重用
-
对数据卷的修改会立马生效
-
对数据卷的更新,不会影响镜像
-
卷会一直存在,直到没有容器使用
*数据卷的使用,类似于 Linux 下对目录或文件进行 mount
下面创建一个web 容器,并加载一个数据卷到容器的/webapp 目录:
# docker run -d-P --name web -v /webapp training/webapp python app.py
# 这样只写名容器中的目录不写宿主机的目录的话,实际上是在宿主机的/var/lib/docker/volumes/xxxx/目录下的。不常用这种写法。
-v 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷
*注意:也可以在 Dockerfile 中使用 VOLUME 来添加一个或者多个新的卷到由该镜像创建的任意容器。
挂载一个主机目录src/webapp作为容器的数据卷:
# docker run -d-P --name web2 -v /src/webapp:/opt/webapp training/webapp python app.py
# 格式:-v 本地路径:容器路径
* 上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp 目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。
* 本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。
* 注意:Dockerfile 中不支持这种用法,这是因为 Dockerfile 是为了移植和分享用的。然而,不同操作系统的路径格式不一样,所以目前还不能支持。
Docker 挂载数据卷的默认权限是读写,用户也可以通过:ro 指定为只读。
# sudo docker run-d -P --name web -v /src/webapp:/opt/webapp:ro training/webapppython app.py
-v 标记也可以从主机挂载单个文件到容器中
# docker run --rm-it -v ~/.bash_history:/.bash_history ubuntu /bin/bash 【不同shell版本有所不同】
*注意:如果直接挂载一个文件,很多文件编辑工具,包括 vi 或者 sed --in-place ,可能会造成文件inode 的改变,从 Docker 1.1 .0起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。
数据卷容器:
如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。
数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。
首先,创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata:
# docker run -i-t -v /dbdata --name dbdata ubuntu:12.04/bin/bash
再启动2个容器测试
# docker run -i-t --volumes-from dbdata --name db1 ubuntu:12.04/bin/bash
# docker run -i-t --volumes-from dbdata --name db2 ubuntu:12.04/bin/bash
# 注意:--volumes-from后面跟的是具备容器卷的那个容器名
此时容器db1和db2都挂载同一个数据卷到相同的/dbdata目录。三个容器任何一方在该目录下的写入,其他容器都可以看到。[即便原来的那个数据卷容器已经停止了]
查看数据卷实际的存放路径:
docker inspect -f``.`Volumes` 数据卷容器的NAME或ID
map[/dbdata:/var/lib/docker/volumes/7c12ca73fe29f884ea5bee12c54da521c7450705264f76fe8629877302cd48aa/_data]
可以看到这个容器卷是把文件写入到/var/lib/docker/volumes下面的某个很长的字符串的目录下的_data/里面
容器和宿主机间文件拷贝的解决方法:
docker ps 获取目标容器的ID或者容器的名称 # 我这里的是容器ID为52261df2fab6
docker inspect-f'``.`Id`' 容器的ID # 获取容器的ID全名称
得到一串类似52261df2fab612b24b3502c4ad98c22aff70ce9fa641c5c9f735ac2415e92da3
cp /root/test.log/var/lib/docker/devicemapper/mnt/52261d...xxx/rootfs/root/ # 这样就把宿主机的test.log拷贝到容器的/root/目录下了。
# 说明:上面的这个方法在CentOS6.7通过yum安装的docker-io测试通过。我另一台测试机安装的是docker-engine,则根本没有/rootfs/这个目录。
还可以使用多个--volumes-from 参数来从多个容器挂载多个数据卷。
# docker run -i-t -v /dbdata --name dbdata ubuntu:12.04/bin/bash
# docker run -i-t -v /webdata --name webdata ubuntu:12.04/bin/bash
# docker run -i-t --volumes-from dbdata --name db1 --volumes-fromwebdata --name web1 ubuntu:12.04 /bin/bash
此外,也可以从其他已经挂载了数据卷的容器来挂载数据卷。
*注意:
使用 --volumes-from 参数所挂载数据卷的容器自己并不需要保持在运行状态。
如果删除了挂载的容器(包括 dbdata、db1 和 db2),数据卷并不会被自动删除。
如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 "docker rm -v 容器名" 命令来指定同时删除关联的容器。这可以让用户在容器之间升级和移动数据卷。另外,如果启动时候加了--rm参数,则容器关闭时自动删除容器并删除卷。
利用数据卷容器来备份数据
# docker run -i-t -v /dbdata --name dbdata ubuntu:12.04 /bin/bash
# cp /etc/issue/etc/group /dbdata
另外启动一个容器,对刚才的容器数据进行备份操作
# docker run --volumes-fromdbdata -v $(pwd):/backup --name bk1 ubuntu:12.04 tar czf/backup/backup.tar.gz /dbdata
# 格式:dockerrun --volumes-from要备份的容器名-v 宿主机目录:/backup ubuntu:12.04 tar czf /backup/xx.tar.gz 需要备份的容器的卷名称
*容器启动后,使用了 tar 命令来将 dbdata 卷备份为容器下的/backup/backup.tar.gz,这个容器执行完就自动退出了(因为没有-ti 或-d参数),
*同时在宿主机下当前目录下生成backup.tar.gz压缩文件(参数-v $(pwd):/backup就是这个作用).
利用数据卷容器来恢复数据
如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2。
# docker run -it-v /dbdata --name dbdata2 ubuntu:12.04 /bin/bash
随便在/dbdata里面复制些文件,以便后面恢复数据时用于识别。
然后创建另一个容器,挂载 dbdata2 的容器,并使用tar解压备份文件到挂载的容器卷中。
#docker run --volumes-from dbdata2 -v $(pwd):/backup ubuntu:12.04 tar xf/backup/backup.tar.gz