docker容器技术笔记
1.docker架构 http://www.infoq.com/cn/articles/docker-source-code-analysis-part1/ Docker架构内各模块:Client、Docker Daemon、Docker Registry、Graph、Driver、libcontainer 以及Docker container。 2.下载docker工具网址 https://www.docker.com/docker-toolbox 3.下载dockerimage模板网址 http://download.openvz.org/template/precreated/ 4.dockerfile的作用 Dockerfile用来创建一个自定义的image http://blog.csdn.net/wsscy2004/article/details/25878223 基于Dockerfile搭建JAVA Tomcat运行环境:http://www.blogjava.net/yongboy/archive/2013/12/16/407643.html 阿里云服务器: 120.25.223.73:4200 120.25.88.150:4200 112.74.22.173:4200 sudo HTTP_PROXY=http://proxyx.com.cn:80 docker -d sudo docker pull ubuntu # 下载最新ubuntu镜像 Docker 主站点:https://www.docker.io Docker 注册中心API:http://docs.docker.com/reference/api/registry_api/ Docker Hub API:http://docs.docker.com/reference/api/docker-io_api/ Docker 迖端应用API:http://docs.docker.com/reference/api/docker_remote_api/ Dockerfile 参考:https://docs.docker.com/reference/builder/ Dockerfile 最佳实践:https://docs.docker.com/articles/dockerfile_best-practices/ docker参数详解 useage of docker -D 默认false 允许调试模式(debugmode) -H 默认是unix:///var/run/docker.sock tcp://[host[:port]]来绑定 或者unix://[/path/to/socket]来使用(二进制文件的时候),当主机ip host=[0.0.0.0],(端口)port=[4243] 或者 path=[/var/run/docker.sock]是缺省值,做为默认值来使用 -api-enable-cors 默认flase 允许CORS header远程api -b 默认是空,附加在已存在的网桥上,如果是用’none’参数,就禁用了容器的网络 -bip 默认是空,使用提供的CIDR(ClasslessInter-Domain Routing-无类型域间选路)标记地址动态创建网桥(dcoker0),和-b参数冲突 -d 默认false 允许进程模式(daemonmode) -dns 默认是空,使docker使用指定的DNS服务器 -g 默认是”/var/lib/docker”:作为docker使用的根路径 -icc 默认true,允许inter-container来通信 -ip 默认”0.0.0.0″:绑定容器端口的默认Ip地址 -iptables 默认true 禁用docker添加iptables规则 -mtu 默认1500 : 设置容器网络传输的最大单元(mtu) -p 默认是/var/run/docker.pid进程pid使用的文件路径 -r 默认是true 重启之前运行的容器 -s 默认是空 ,这个是docker运行是使用一个指定的存储驱动器 -v 默认false 打印版本信息和退出 docker run命令详解 Usage: docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG…] Run a command in a new container -a=map[]: 附加标准输入、输出或者错误输出 -c=0: 共享CPU格式(相对重要) -cidfile=””: 将容器的ID标识写入文件 -d=false: 分离模式,在后台运行容器,并且打印出容器ID -e=[]:设置环境变量 -h=””: 容器的主机名称 -i=false: 保持输入流开放即使没有附加输入流 -privileged=false: 给容器扩展的权限 -m=””: 内存限制 (格式:<number><optional unit>, unit单位 = b, k, m or g) -n=true: 允许镜像使用网络 -p=[]: 匹配镜像内的网络端口号 -rm=false:当容器退出时自动删除容器 (不能跟 -d一起使用) -t=false: 分配一个伪造的终端输入 -u=””: 用户名或者ID -dns=[]: 自定义容器的DNS服务器 -v=[]: 创建一个挂载绑定:[host-dir]:[container-dir]:[rw|ro].如果容器目录丢失,docker会 创建一个新的卷 -volumes-from=””: 挂载容器所有的卷 -entrypoint=””: 覆盖镜像设置默认的入口点 -w=””: 工作目录内的容器 -lxc-conf=[]: 添加自定义-lxc-conf=”lxc.cgroup.cpuset.cpus = 0,1″ -sig-proxy=true: 代理接收所有进程信号(even in non-tty mode) -expose=[]: 让你主机没有开放的端口 -link=””: 连接到另一个容器(name:alias) -name=””: 分配容器的名称,如果没有指定就会随机生成一个 -P=false: Publish all exposed ports to thehost interfaces 公布所有显示的端口主机接口 docker常用命令总结 docker pull <镜像名:tag> #从官网拉取镜像 docker search <镜像名> #搜索在线可用镜像名 查询容器、镜像、日志 docker top <container> #显示容器内运行的进程 docker images #查询所有的镜像,默认是最近创建的排在最上。 docker ps #查看正在运行的容器 docker ps -l #查看最后退出的容器的ID docker ps -a #查看所有的容器,包括退出的。 docker logs {容器ID|容器名称} #查询某个容器的所有操作记录。 docker logs -f {容器ID|容器名称} #实时查看容易的操作记录。 删除容器与镜像 docker rm$(docker ps -a -q) #删除所有容器 docker rm <容器名or ID> #删除单个容器 docker rmi <ID> #删除单个镜像 docker rmi$(docker images | grep none | awk ‘{print $3}’ | sort -r)#删除所有镜像 启动停止容器 docker stop <容器名or ID> #停止某个容器 docker start <容器名or ID> #启动某个容器 docker kill <容器名or ID> #杀掉某个容器 容器迁移 docker export <CONTAINER ID> > /home/export.tar #导出 cat /home/export.tar | sudo docker import – busybox-1-export:latest# 导入export.tar文件 docker save debian> /home/save.tar #将debian容器打包 docker load< /home/save.tar #在另一台服务器上加载打包文件 save和export的对比参考地址:http://www.fanli7.net/a/bianchengyuyan/C__/20140423/452256.html 运行一个新容器 #运行一个新容器,同时为它命名、端口映射。以debian02镜像为例 docker run -h=”redis-test” –name redis-test -d -p 51000:22 -p51001:3306 -p 51003:6379 -p 51004:6381 -p 51005:80 -p 51006:8000 -p 51007:8888 debian02 /etc/rc.local #从container中拷贝文件,当container已经关闭后,在里面的文件还可以拷贝出来。 sudo docker cp 7bb0e258aefe:/etc/debian_version . #把容器中的/etc/debian_version拷贝到 当前目录下。 2.映像操作 cat layer.tar | sudo docker import - ubuntu:3.0#从本地文件系统导入镜像 docker images docker pull ubuntu:12.04 <=> docker pull registry.hub.docker.com/ubuntu:12.04#从docker hub下载镜像 docker rmi <image id> #删除image docker rmi `docker images -a | awk '{if($2==0.0) print $3;}'`#删除tag==0.1的映像 docker rmi -f `docker images -a -q`#强制删除所有映像 docker commit [-m "..." -a "..."] containerID rep:tag#将容器导出为映像 sudo docker save -o ubuntu_14.04.tar ubuntu:14.04#将映像ubuntu:14.04保存到本地当前目录下的ubuntu_14.04.tar(要用.tar后缀) sudo docker load --input ubuntu_14.04.tar 或 sudo docker load < ubuntu_14.04.tar#载入save保存的镜像,也可以使用 docker import docker tag imageid 10.9.111.221:5000/ubuntu:12.0 docker pull 10.9.111.221:5000/ubuntu #在私有库中拉取最新的ubuntu docker search 10.9.111.221:5000/ubuntu#搜索私有库中的ubuntu库 curl http://104.131.173.242:5000/v1/search #查询私有仓库 3.容器操作 docker run -i ubuntu:3.0 /usr/bin/bash #启动容器,并且进入到Ubuntu容器的bash命令 -t伪造一个虚拟终端,当执行脚本时不能用-t选项 docker run -i -t --name mycontainer ubuntu:3.0 echo "liujidngd"#-i打开标准输出;-t允许伪终端;--name容器名字;--rm容器退出时强制删除容器 docker run -i -t --rm ubuntu:3.0 echo "liujidngd"#运行完该命令后,删除容器 docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...] docker ps#列出当前所有正在运行的container docker ps -l#列出最近一次启动的,且正在运行的container docker ps -a#列出所有的container docker rm `docker ps -a -q`#删除所有容器 docker rm $CONTAINER_ID#删除容器id为CONTAINER_ID的容器 docker stop CONTAINER_ID#停止docker实例 docker logs containerName#查看后台运行的容器的日志 ctrl +p+q 将容器推入后台运行 docker attach containerName#重新进入容器,或将容器提到前台 docker export CONTAINER_ID > ubuntu.tar#导出容器快照到本地当前文件夹下 cat layer.tar | docker import - ubuntu:3.0#从本地文件系统导入容器快照为镜像 docker commit containerID imagename #将容器导出为映像 4.Docker 数据管理(数据卷的使用,类似亍 Linux 下对目录戒文件迕行 mount) docker run -d -v /webapp ubuntu:0.1 echo "lk"#运行容器时在根目录下加载一个数据卷(创建了一个数据卷容器) docker run -d -v /src/webapp:/opt/webapp ubuntu:0.1 echo "lk"#挂载本地主机目录/src/webapp到容器目录/opt/webapp docker run -d -v /src/webapp:/opt/webapp:ro ubuntu:0.1 echo "lk"#挂载时指定只读权限 docker run -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash #将本地文件~/.bash_history挂载到主机文件/.bash_history docker run -d -v /data --name dbdata ubuntu:0.1 echo "lk"#创建了一个数据卷容器 docker run -d --volumes-from dbdata --name db1 ubuntu:0.1 echo "lk"#挂载数据卷dbdata下所有的数据卷,用于容器目录共享 docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata#将数据卷容器的数据备份到本地目录 5.Docker 中的网络功能 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。 当使用 -P 标记时,Docker 会映射一个 本地49000~49900 的随机端口到内部容器被开放使用的网络端口。 docker run -d -P training/webapp python app.py#使用随机端口绑定到容器在使用的端口 docker run -d -p 5000:5000 training/webapp python app.py#使用固定端口绑定到容器 docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py docker run -d -p 127.0.0.1::5000 training/webapp python app.py#映射到指定地址的任意端口 docker run --link db:dbalias --name web training/webapp env#将容器的db的随机端口与容器web使用的端口相连 docker port CONTAINER_ID portnum#查看容器中的端口port对应主机的端口号 6.命令 Docker 的命令可以采用 docker-CMD 戒者 docker CMD 的方式执行。两者一致。 docker-attach依附到一个正在运行的容器中。 docker-build从一个 Dockerfile 创建一个镜像 docker-commit从一个容器的修改中创建一个新的镜像 docker-cp(1)从容器中复制文件到宿主系统中 docker-diff(1)检查一个容器文件系统的修改 docker-events从服务端获取实时的事件 docker-export导出容器内容为一个 tar 包 docker-history显示一个镜像的历叱 docker-images列出存在的镜像 docker-import导入一个文件(典型为 tar 包)路径戒目录来创建一个镜像 docker-info显示一些相关的系统信息 docker-inspect显示一个容器的底层具体信息。 docker-kill关闭一个运行中的容器 (包括迕程和所有资源) docker-load从一个 tar 包中加载一个镜像 docker-login注册戒登录到一个 Docker 的仏库服务器 docker-logout从 Docker 的仏库服务器登出 docker-logs获取容器的 log 信息 docker-pause暂停一个容器中的所有迕程 docker-port查找一个 nat 到一个私有网口的公共口 docker-ps列出容器 docker-pull从一个Docker的仏库服务器下拉一个镜像戒仏库 docker-push将一个镜像戒者仏库推送到一个 Docker 的注册服务器 docker-restart重吪一个运行中的容器 docker-rm删除给定的若干个容器 docker-rmi删除给定的若干个镜像 docker-run创建一个新容器,幵在其中运行给定命令 docker-save保存一个镜像为 tar 包文件 docker-search在 Docker index 中搜索一个镜像 docker-start启动一个容器 docker-stop终止一个运行中的容器 docker-tag为一个镜像打标签 docker-top查看一个容器中的正在运行的迕程信息 docker-unpause将一个容器内所有的迕程从暂停状态中恢复 docker-version输出 Docker 的版本信息 docker-wait阻塞直到一个容器终止,然后输出它的退出符 7.dockerfile 文件创建分层映像 第一步:在本地的当前目录下创建Dockerfile FROM ubuntu:test3 //使用ubuntu:test3作为基础映像 RUN mkdir work RUN echo "Hello docker!" >/work/lj //在该映像上加一层 第二步:编译生成一个新的映像 docker build -t="ubuntu:v1" /home/mepa/test //使用/home/mepa/test目录(该目录下最好只有一个Dockerfile文件)下的Dockerfile生成一个新的映像ubuntu:v1 第三步:运行新的映像ubuntu:v1 docker run -d -v /home/mapa/work:/work1 ubuntu:v1 //使用dockerfile生成的映像可以没有/bin/sh命令 1.docker与传统虚拟机的优势 a.启动快:docker的启动可以在秒级实现,而传统虚拟机需要分级 b.对系统资源的利用率高:一台主机可以同时允许数千个docker容器,而传统虚拟机一般只能运行几十个。传统的虚拟机运行10个不同的应用需要启动10个不同的虚拟机,而docker只需要启动10个隔离的应用即可。 c.运行效率高:Docker容器的运行不需要额外的hypervisor(中间件)支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。 d.更简单的管理:使用Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。 e.一次创建,随处运行 Docker底层的核心技术包括Linux上的名字空间( Namespaces)、控制组( Control groups)、Union文件系统( Union file systems)和容器格式( Container format)。传统的虚拟机通过在宿主主机中运行hypervisor来模拟一整套完整的硬件环境提供给虚拟机的 操作系统,实现了操作系统级的隔离,而docker是在操作系统的基础上实现的是进程级的隔离。 2.容器之间的网络连接 a.系统外部访问容器内部 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P或-p参数来指定端口映射。 从而可以使得互联网通过访问主机端口来访问容器 b.容器之间的访问 --link=CONTAINER_NAME:ALIAS选项会在创建容器的时候,添加一个其他容器的主机名到/etc/hosts文件中, 让新容器的进程可以使用主机名ALIAS就可以连接它。(容器在创建的时候,默认就已经通过docker0网桥互联了,--link只是给容器ip取一个别名) 如: $sudo docker run -d --name db training/postgres 不用向外映射任何端口 $sudo docker run -d -P--name web --link db:mydb ubuntu /bin/bash >ping mydb >cat /etc/hosts 当Docker服务器启动时,会自动在主机上创建一个docker0虚拟网桥,相当于一个软件交换机,可以在挂载到它的网口之间进行数据转发。 该软交换机有一个ip比如172.17.42.1/16,启动的每一个容器也有一个同一网段的ip。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。 Docker就创建了在主机和所有容器之间一个虚拟共享网络。 docker自动建立的网络模型如下:!()[https://github.com/liujin123/sundry/blob/master/docker_soft_switch.png?raw=true] >docker run -it --link pedantic_borg:myubunutu ubuntu /bin/sh #ping myubunutu PING myubunutu (172.17.0.3): 56 data bytes #可以看到myubunutu的ip地址 64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.187 ms 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.165 ms 其实不需要--link选项容器与容器之间也是可以ping通的,只是要先知道另外一个容器的ip,这个可以attach到容器中,然后在/etc/hosts文件中查看。 或者在本容器/etc/hosts中添加一个其它容器ip与主机名的映射,也可以通过主机名访问其它容器。 c.常用的与网络相关的命令 -bBRIDGEor--bridge=BRIDGE--指定容器挂载的网桥 --bip=CIDR--定制docker0的掩码 -HSOCKET...or--host=SOCKET...--Docker服务端接收命令的通道 --icc=true|false--是否支持容器之间进行通信 --ip-forward=true|false--本地linux系统转发本容器数据本 --iptables=true|false--禁止Docker添加本地系统的iptables规则 --mtu=BYTES--容器网络中的MTU 下面2个命令选项既可以在启动服务时指定,也可以Docker容器启动(dockerrun) 时候指定。在 Docker服务启动的时候指定则会成为默认值,后面执行dockerrun时可以覆盖设置的默认值。 --dns=IP_ADDRESS...--使用指定的DNS服务器 --dns-search=DOMAIN...--指定DNS搜索域 最后这些选项只有在dockerrun执行时使用,因为它是针对容器的特性内容。 -hHOSTNAMEor--hostname=HOSTNAME--配置容器主机名 --link=CONTAINER_NAME:ALIAS--添加到另一个容器的连接 --net=bridge|none|container:NAME_or_ID|host--配置容器的桥接模式 -pSPECor--publish=SPEC--映射容器端口到宿主主机 -Por--publish-all=true|false--映射容器所有端口到宿主主机 3.容器的访问控制 容器的访问控制主要通过linux的防火墙软件iptables进行管理实现。每个容器的虚拟网卡veth都需要连接到linux系统创建的docker0网桥上才能工作。 a.容器访问外部网络 容器访问外部网络需要本地linux系统的支持:网卡设置允许网络转发 $sysctlnet.ipv4.ip_forward #查看 net.ipv4.ip_forward=0 $sysctl-wnet.ipv4.ip_forward=1 #设置 /etc/init.d/procps.sh restart #生效 默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。 容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。 这是使用 iptables的源地址伪装操作实现的。 $sudo iptables -t nat -nL #查看主机的NAT(网络地址转换)规则。 ... ChainPOSTROUTING(policyACCEPT) targetprotoptsourcedestination MASQUERADEall--172.17.0.0/16!172.17.0.0/16 ... 其中,上述规则将所有源地址在 172.17.0.0/16网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。 MASQUERADE跟传统SNAT的好处是它能动态从网卡获取地址。容器允许外部访问,可以在 dockerrun时候通过 -p或 -P参数来启用。 不管用那种办法,其实也是在本地的 iptable的nat表中添加相应的规则。 $sudo iptables -t nat -nL ... ChainDOCKER(2references) target protopt sourcedestination DNATtcp--0.0.0.0/00.0.0.0 tcpdpt:49153to:172.17.0.2:80 b.容器之间的访问 (默认互联) ** 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到docker0网桥上。 ** 本地系统的防火墙软件--iptables是否允许通过。 * c.网桥 每个容器都有虚拟网卡ceth,而docker网桥只是将这些虚拟网卡桥接。 c1.默认网桥docker0 Docker服务默认会创建一个 docker0网桥。在内核层连通了所有的虚拟网卡,但是并没有连接到物理网卡,并且docker0网桥没有配置文件,要想桥接物理网卡,只能重新新建一个虚拟网桥。 每次创建一个新容器的时候, Docker从可用的地址段中选择一个空闲的IP地址分配给容器的eth0端口。使用本地主机上docker0接口的IP作为所有容器的默认网关。 >brctl show #显示网桥桥接了那些网卡 c2.自定义网桥 《docker技术入门与实践pdf》 在启动Docker服务的时候,使用-b BRIDGE或--bridge=BRIDGE 来指定使用的网桥,也可以修改配置文件。 自定义网桥是linux系统的功能,如果docker服务已经运行,那需要先停止服务,并删除旧的网桥。 [root@opnvz~]#brctlshow #显示linux主机上的网桥 bridgenamebridgeidSTPenabledinterfaces docker08000.56847afe9799noveth0889 $sudoservicedockerstop $sudoiplinksetdevdocker0down $sudobrctldel brdocker0 然后创建一个网桥bridge0。 $sudobrctladd brbridge0 $sudoipaddradd192.168.5.1/24devbridge0 $sudoiplinksetdevbridge0up 查看确认网桥创建并启动。 $ipaddrshowbridge0 配置Docker服务,默认桥接到创建的网桥上。 $echo'DOCKER_OPTS="-b=bridge0"'>>/etc/default/docker $sudoservicedockerstart c3.跨物理网络的容器为什么能通信? 本地系统上运行的虚拟机或容器在访问外网时与本地进程使用相同的一套主机端口,因而数据准确送达容器进程或本地主机进程。 容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。 这是使用iptables的源地址伪装操作实现的。互联网访问容器也是通过端口一一映射实现的。 d.ambassador 容器实现跨物理主机的容器间通信 《docker技术入门与实践pdf》 ambassador 容器提供C/S模型,可以让容器只存在本机的局域网,而使用ambassador 容器来提供网络互联。 4.联合文件系统 UnionFS 联合文件系统( UnionFS)是一种分层、 轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(uniteseveraldirectoriesintoa singlevirtualfilesystem)。联合文件系统是Docker镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。 5.数据卷 在容器中管理数据主要有两种方式:数据卷和数据卷容器 数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性: *数据卷可以在容器之间共享和重用 *对数据卷的修改会立马生效 *对数据卷的更新,不会影响镜像 *卷会一直存在,直到没有容器使用 在用docker run命令的时候,使用-v标记来创建一个数据卷并挂载到容器里。在一次run中多次使用可以挂载多个数据卷 $sudo docker run -d --name web -v /webapp training/webapp python app.py 在容器中挂载一个数据卷 $sudo docker run -d --name web -v /src/webapp:/opt/webapp training/webapp python app.py 挂载一个主机目录作为数据卷 $sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash 挂载一个主机文件作为数据卷 数据卷容器:其实就是一个正常的容器, 专门用来提供数据卷供其它容器挂载的。 $sudo docker run -d --name web -v /dbdata --name dbdatatraining/db 专门被其它容器挂载:凡是存在数据卷的容器都可以被其它容器挂载 $sudo docker run -d --volumes-from dbdata --name db1training/postgres 挂载其它容器的数据卷 $sudo docker run -d --volumes-from db1 --name db2training/postgres 从db1挂载 从数据卷中迁移数据: $sudo docker run --volumes-fromdbdata-v $(pwd):/backup ubuntu tar cvf /backup/backup.tar 新建一个容器从而可以将数据备份到主机目录 本文转自 a_liujin 51CTO博客,原文链接:http://blog.51cto.com/a1liujin/1730861,如需转载请自行联系原作者