前言:在docker1.12中默认增加了swarm mode 编排功能,并且官方支持更多的插件来进行docker的网路和外接存储插件,不过目前测试swarm mode的功能并不是特别理想,还存在一些问题,以后文章可能会讲到,当然毕竟swarm是在docker1.12中新加进来的,想必以后会做的更好,赶超mesos+marathon和kubernetes还是很有希望的。
1.Docker存储驱动详解:
需要注意的是,docker默认支持集中存储驱动:devicemapper,aufs,overlay,btrfs等。在ubuntu系列,默认的的存储驱动是aufs,这种方式是比较适合上生产的;在centos系列上默认的存储驱动是devicemapper,这种方式目前不建议上生产,因为默认使用的是/dev/loop1虚拟设备进行存储数据的,这样可能导致数据的不稳定,以及未来的不可扩展(官方建议是使用devicemapper的时候使用direct-lvm)。
详细的存储驱动官方文档如下:
Device Mapper:
Ubuntu默认使用AUFS作为存储驱动,但是AUFS并没有被包括在Linux的主线内核中。CentOS中可以使用Device Mapper作为存储驱动,这是在2.6.9内核版本引入的新功能。我们需要先确认是否启用该功能(相应的包为device-mapper):# ll /sys/class/misc/device-mapperlrwxrwxrwx 1 root root 0 Jul 20 14:27 /sys/class/misc/device-mapper -> ../../devices/virtual/misc/device-mapper
然而从官方文档以及上面的各种存储驱动比较图中可以看到,devicemapper在centos上默认使用的/dev/loop设备还是不建议在生产中使用的。然而解决这个问题办法就两种,使用lvm方式存放在存储上,或者直接使用额外的分区。
使用官方建议的direct-lvm模式进行搭建docker存储:
DOCKER_STORAGE_OPTIONS="--storage-driver devicemapper --storage-opt dm.fs=xfs --storage-opt dm.thinpooldev=/dev/mapper/centos-docker--pool --storage-opt dm.use_deferred_removal=true --storage-opt dm.use_deferred_deletion=true "
2.基本环境搭建
- 环境基础:centos7.2 Docker1.12:
# uname -r 3.10.0-327.el7.x86_64# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core)必须要使用centos7的yum源,因为安装过程中需要依赖某些组件,比如libgroup之类的
不建议直接使用docker官方的docker yum源进行安装,因为会依据系统版本去选择docker版本,不能指定相应的版本进行选择安装。本篇文章将使用docker1.12进行部署。
可以直接在github上获取docker各个版本包:
上面链接中提供了所有的docker核心包,详细包如下: - 安装docker1,12
可以直接使用yum localinstall进行安装部署。默认会从centos7的官方源中安装依赖(audit-libs-python.x86_64 0:2.4.1-5.el7 checkpolicy.x86_64 0:2.1.12-6.el7 libcgroup.x86_64 0:0.41-8.el7 libseccomp.x86_64 0:2.2.1-1.el7 libsemanage-python.x86_64 0:2.1.10-18.el7 libtool-ltdl.x86_64 0:2.4.2-20.el7 policycoreutils-python.x86_64 0:2.2.5-20.el7 python-IPy.noarch 0:0.75-6.el7 setools-libs.x86_64 0:3.3.7-46.el7 )#yum localinstall docker-engine-1.12.0-1.el7.centos.x86_64.rpm docker-engine-debuginfo-1.12.0-1.el7.centos.x86_64.rpm docker-engine-selinux-1.12.0-1.el7.centos.noarch.rpm -y
- 验证docker是否安装成功: 注意:centos7中docker1.12中默认使用docker作为客户端程序,使用dockerd作为服务端程序。
# docker versionClient: Version: 1.12.0 API version: 1.24 Go version: go1.6.3 Git commit: 8eab29e Built: OS/Arch: linux/amd64Cannot connect to the Docker daemon. Is the docker daemon running on this host?注意:以上显示当前docker版本为1.12,并且docker 服务端程序没有启动。可以使用默认的dockerd启动,也可以使用默认 systemctl status docker .同时也可以使用docker --help查看相关功能特性
- 启动docker daemon程序: 在docker1.12中,默认的daemon程序是dockerd,可以执行dockerd或者使用系统再带systemd去管理服务。但是需要注意的是,默认用的都是默认的参数,比如私有网段默认使用172.17.0.0/16 ,网桥使用docker0等等
# dockerd INFO[0000] libcontainerd: new containerd process, pid: 10622 WARN[0000] containerd: low RLIMIT_NOFILE changing to max current=1024 max=4096WARN[0001] devmapper: Usage of loopback devices is strongly discouraged for production use. Please use `--storage-opt dm.thinpooldev` or use `man docker` to refer to dm.thinpooldev section. WARN[0001] devmapper: Base device already exists and has filesystem xfs on it. User specified filesystem will be ignored. INFO[0001] [graphdriver] using prior storage driver "devicemapper" INFO[0001] Graph migration to content-addressability took 0.00 seconds WARN[0001] mountpoint for pids not found INFO[0001] Loading containers: start. INFO[0001] Firewalld running: false INFO[0001] Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address INFO[0001] Loading containers: done. INFO[0001] Daemon has completed initialization INFO[0001] Docker daemon commit=8eab29e graphdriver=devicemapper version=1.12.0INFO[0001] API listen on /var/run/docker.sock 注意:其实在提示中我们可以看出来使用的桥接网络docker0的172.17.0.0/16,并且用的是devicemapper存储引擎,以及当前docker的版本。
通过centos系统自带的systemd服务管理docker:
#systemctl restart/stop/start/reload/status docker
- 查看docker相关参数以及相关使用帮助 先看docker 服务客户端程序以及服务端启动的相关参数:
# docker infoContainers: 0 Running: 0 Paused: 0 Stopped: 0Images: 0Server Version: 1.12.0Storage Driver: devicemapper #默认使用的存储引擎,centos使用devicemapper,ubuntu系列使用的是aufs Pool Name: docker-8:2-34118597-pool Pool Blocksize: 65.54 kB Base Device Size: 10.74 GB Backing Filesystem: xfs #当前系统使用的文件系统 Data file: /dev/loop0 #docker的数据存储设备,默认使用的是本地虚拟的一块设备,局限是最大只能承受100G。 Metadata file: /dev/loop1 #docker的元数据存储设备 Data Space Used: 11.8 MB Data Space Total: 107.4 GB Data Space Available: 31.06 GB Metadata Space Used: 581.6 kB Metadata Space Total: 2.147 GB Metadata Space Available: 2.147 GB Thin Pool Minimum Free Space: 10.74 GB Udev Sync Supported: true Deferred Removal Enabled: false Deferred Deletion Enabled: false Deferred Deleted Device Count: 0 Data loop file: /var/lib/docker/devicemapper/devicemapper/data #docker数据存储文件 WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device. Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata #元数据存储目录 Library Version: 1.02.107-RHEL7 (2015-10-14)Logging Driver: json-fileCgroup Driver: cgroupfs #cgroup驱动使用的是cgroupfsPlugins: #当前docker使用的插件 Volume: local #volume默认使用的是本地,之后我们会扩展使用nfs Network: null overlay bridge host #默认使用的是本地桥接方式,overlay方式可以支持多主机之间的容器互相通信,当然也可以使用一些第三方插件,比如pipnetworkSwarm: inactive #swarm目前是可以用的,一种docker集群编排方式Runtimes: runcDefault Runtime: runcSecurity Options: seccompKernel Version: 3.10.0-327.el7.x86_64 #内核以及操作系统相关信息Operating System: CentOS Linux 7 (Core)OSType: linuxArchitecture: x86_64CPUs: 4Total Memory: 3.702 GiBName: xxxxxID: JUNK:WIJU:463W:VBKM:YT2X:FTE3:F5G4:T5DK:2HTP:HPFB:J4ER:3Y72Docker Root Dir: /var/lib/docker #docker默认的家目录,数据相关的最后都会存储在这个地方Debug Mode (client): falseDebug Mode (server): falseRegistry: https://index.docker.io/v1/WARNING: bridge-nf-call-iptables is disabledWARNING: bridge-nf-call-ip6tables is disabledInsecure Registries: 127.0.0.0/8 注意:上面bridge-nf-call-iptables的警告是内核没有开启桥接模式的iptables。这个应该只是影响nat表中的prerouting链,所以之后的实验中应该用不到,但是如果想要开启的话执行以下命令。 #echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables #echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tables
使用dockerd –help可以查看docker启动相关的参数:
#dockerd --help(其实dockerd就相当于之前的docker -d)-b, --bridge #指定容器使用的网络接口,默认为docker0,也可以指定其他网络接口--bip #指定桥接地址,即定义一个容器的私有网络--cgroup-parent #为所有的容器指定父cgroup--cluster-advertise #为集群设定一个地址或者名字--cluster-store #后端分布式存储的URL--cluster-store-opt=map[] #设置集群存储参数--config-file=/etc/docker/daemon.json #指定配置文件-D #启动debug模式--default-gateway #为容器设定默认的ipv4网关(--default-gateway-v6)--dns=[] #设置dns--dns-opt=[] #设置dns参数--dns-search=[] #设置dns域--exec-opt=[] #运行时附加参数--exec-root=/var/run/docker #设置运行状态文件存储目录--fixed-cidr #为ipv4子网绑定ip-G, --group=docker #设置docker运行时的属组-g, --graph=/var/lib/docker #设置docker运行时的家目录-H, --host=[] #设置docker程序启动后套接字连接地址--icc=true #是内部容器可以互相通信,环境中需要禁止内部容器访问--insecure-registry=[] #设置内部私有注册中心地址--ip=0.0.0.0 #当映射容器端口的时候默认的ip(这个应该是在多主机网络的时候会比较有用)--ip-forward=true #使net.ipv4.ip_forward生效,其实就是内核里面forward--ip-masq=true #启用ip伪装技术(容器访问外部程序默认不会暴露自己的ip)--iptables=true #启用容器使用iptables规则-l, --log-level=info #设置日志级别--live-restore #启用热启动(重启docker,保证容器一直运行1.12新特性)--log-driver=json-file #容器日志默认的驱动--max-concurrent-downloads=3 #为每个pull设置最大并发下载--max-concurrent-uploads=5 #为每个push设置最大并发上传--mtu #设置容器网络的MTU--oom-score-adjust=-500 #设置内存oom的平分策略(-1000/1000)-p, --pidfile=/var/run/docker.pid #指定pid所在位置-s, --storage-driver #设置docker存储驱动--selinux-enabled #启用selinux的支持--storage-opt=[] #存储参数驱动--swarm-default-advertise-addr #设置swarm默认的node节点--tls #使用tls加密--tlscacert=~/.docker/ca.pem #配置tls CA 认证--tlscert=~/.docker/cert.pem #指定认证文件--tlskey=~/.docker/key.pem #指定认证keys--userland-proxy=true #为回环接口使用用户代理--userns-remap #为用户态的namespaces设定用户或组
注意:因为默认的dockerd参数不一定适合我们使用的环境,因此在启动的时候我们需要针对实际情况去配置相应的参数,比如docker数据家目录以及默认容器的私有地址等等
- Docker 启动参数的配置 1.docker存储驱动的配置,devicemapper下的direct-lvm模式,创建一个/dev/mapper/docker-thinpool设备.lvm管理就不再多讲了,网上资料太多。。。
#!/bin/bashpvcreate /dev/vda1vgcreate docker /dev/vda1lvcreate --wipesignatures y -n thinpool docker -l 95%VGlvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VGlvconvert -y --zero n -c 512K --thinpool docker/thinpool --poolmetadata docker/thinpoolmetaecho "activation { thin_pool_autoextend_threshold=80 thin_pool_autoextend_percent=20}" > /etc/lvm/profile/docker-thinpool.profilelvchange --metadataprofile docker-thinpool docker/thinpoolecho "Print the vgs:"vgdisplayecho "Print the lvs:"lvdisplaylvs -o+seg_monitorsystemctl daemon-reloadsystemctl start docker
2.修改和配置centos7中docker启动配置文件:
centos系统的配置文件/usr/lib/systemd/system/docker.service,这个是模板文件:
#mkdir /etc/systemd/system/docker.service.d#touch /etc/systemd/system/docker.service.d/docker.conf #cat /etc/systemd/system/docker.service.d/docker.conf##线上详细配置ExecStart=/bin/dockerd --storage-driver=devicemapper --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --storage-opt dm.use_deferred_removal=true -D -H tcp://0.0.0.0:5256 -H unix:///var/run/docker.sock --pidfile=/var/run/docker.pid --swarm-default-advertise-addr=172.25.47.210 --bip=10.0.0.1/24 --icc=false --insecure-registry=172.25.46.8:5001注意:#存储驱动参数--storage-opt详情dm.thinpooldev 为docker存储的thin pool指定一个可用的块存储设备(默认的是/dev/loop设备;生产环境建议使用direct-lvm)dm.basesize 当创建一个基础设备(用来限制images和container的大小)的时候,指定大小。默认会给一个容器10G。需要注意的是,base device size 可用在docker重启的时候增加。但是每次修改完配置后必须把相应的/var/lib/docker底下的相关目录删除掉。否则重启会检测失败。dm.fs 为base device指定使用的文件系统类型(ext4,xfs默认)dm.mkfsarg 指定额外的格式化参数(--storage-opt "dm.mkfsarg=-O ^has_journal")dm.datadev/dm.metadatadev 设置docker存储的data和metadata,不过已经过时了,目前使用的基本都是dm.thinpooldev参数(--storage-opt dm.datadev=/dev/sdb1 --storage-opt dm.metadatadev=/dev/sdc1)
修改完配置文件之后需要刷新下配置:
systemctl daemon-reload systemctl restart docker 查看相关日志: journalctl -u dockerubuntun系统的配置文件默认在/etc/default/docker
- Docker1.12容器管理-自动启动容器 1.当使用docker start -a参数,docker会自动attach到容器里面,或者在需要的时候启动它,为了当一个容器停止并且重启它的时候管理程序(systemd)够检测到. 实例:
[Unit]Description=Redis containerRequires=docker.serviceAfter=docker.service[Service]Restart=alwaysExecStart=/usr/bin/docker start -a redis_serverExecStop=/usr/bin/docker stop -t 2 redis_server[Install]WantedBy=default.target
如果把这个容器作为一个系统服务,需要将上面的配置添加到文件/etc/systemd/system/docker-redis_server.service.
如果需要传入参数到到容器里面,比如–env那你必须使用docker run,而不是docker start,这样在每次服务启动的时候会创建一个新的容器。[Service]...ExecStart=/usr/bin/docker run --env foo=bar --name redis_server redisExecStop=/usr/bin/docker stop -t 2 redis_serverExecStopPost=/usr/bin/docker rm -f redis_server...
启动上面的docker容器:
systemctl daemon-reload systemctl start docker-redis_server.service systemctl enable docker-redis_server.service- Docker1.12容器管理-docker不可用期间保持容器存活
1.首先我们得确认docker在启动的时候支持热加载选项,两种方式如下:
docker已启动,又不想停止,可以增加一个配置文件到docker服务的配置文件中
#vim /etc/docker/daemon.json{"live-restore": true }
修改完配置之后必须发送一个SIGHUB
信号给docker守护进程以便重新加载配置。
要么就在启动的时候加上--live-restore参数
2.这种热启动其实可以用在docker的升级期间。但是如果你是跳过一个版本去升级的,守护进程可能不会重新加载连接到容器,如果不能连接到容器的话,你就必须手动的去管理容器了,守护进程不会去关掉这些断开连接的容器。
3.热重启用在restart docker守护进程的时候,可以减少用户的卡顿(但是前提是重启的时候主配置不能变,比如网桥啦,还有数据存储目录啦) 4.热重启对运行中的容器的影响。守护进程的长时间卡顿可能影响运行中的容器。因为容器进程会写FIFO日志,以便供守护进程消费,如果守护进程不可用,不能消费容器输出内容,buffer酒会慢,并且堵塞不能写进日志。默认的buffer大小为64k,此时必须重启docker去刷新buffer。 buffer大小的修改:/proc/sys/fs/pipe-max-size
5.热重启和swarm 模式
热重启参数和docker swarm模式不兼容,当docker1⃣️swarm模式运行,整个docker流程主要用来管理任务和保证容器按照一定的服务标准运行。- Docker1.12容器管理-使用systemd管理和配置docker
1.使用systemd管理docker
#systemctl stop/start/status/enable/restart docker`默认systemd管理的服务都会放在/usr/lib/systemd/system/docker.service类此这样的目录.当然也是可以自定义加载配置文件的`
2.自定义docker启动选项
有多种推荐的方式去自定义修改docker启动参数,这里推荐的一种就是使用systemd的drop-in文件去加载相应的参数。其实就是创建一个目录/etc/systemd/system/docker.service.d,然后在目录里面加载相应的配置文件*.conf.注意:这种方式需要注意会默认包含/etc/systemd/system/docker.service,因为这个文件是从/lib/systemd/system/docker.service复制过来的
# cat /etc/systemd/system/docker.service.d/docker.conf [Service]ExecStart=ExecStart=/bin/dockerd -D -H tcp://0.0.0.0:5256 -H unix:///var/run/docker.sock --pidfile=/var/run/docker.pid --swarm-default-advertise-addr=172.25.47.210 --bip=10.0.0.1/24 --icc=false -g /export/lib/docker --insecure-registry=172.25.46.8:5001
需要注意的是,必须配置两个execstart才能正确启动docker
使用systemctl show可以查看服务相关的配置,比如以下查看启动时加载参数:
也可以查看docker环境加载配置systemctl show docker | grep EnvironmentFile
EnvironmentFile=-/etc/sysconfig/docker (ignore_errors=yes)
# systemctl show docker | grep ExecStartExecStart={ path=/bin/dockerd ; argv[]=/bin/dockerd -D -H tcp://0.0.0.0:5256 -H unix:///var/run/docker.sock --pidfile=/var/run/docker.pid --swarm-default-advertise-addr=172.25.47.210 --bip=10.0.0.1/24 --icc=false -g /export/lib/docker --insecure-registry=172.25.46.8:5001 ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
配置运行时目录以及存储引擎相关:
其实上面的启动配置中已经加载了运行时目录为-g /export/lib/docker 设置存储引擎–storage-driver=overlay/devicemapper/aufs配置http代理
#cat /etc/systemd/system/docker.service.d/http-proxy.conf[Service]Environment="HTTP_PROXY=http://proxy.example.com:80/"如果:内部的docker registries 不需要通过代理去连接,可以按照以下配置:Environment="HTTP_PROXY=http://proxy.example.com:80/" "NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com"
刷新配置查看配置文件正确后重启:
systemctl daemon-reload systemctl show –property=Environment docker systemctl restart docker- Docker1.12容器管理-格式化命令以及输出:
示例:
# docker ps --format '{ {json .Names}}'"xxbandy-1""xxbandy"# docker ps --format '{ {json .Ports}}'"0.0.0.0:2221-\u003e8000/tcp""0.0.0.0:2222-\u003e8000/tcp"#docker inspect --format '{ {json .Config}}' xxbandy {"Hostname":"jupyterhub","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"8000/tcp":{}},"Tty":true,"OpenStdin":true,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["bash"],"Image":"172.25.46.8:5001/jupyter","Volumes":null,"WorkingDir":"/export","Entrypoint":null,"OnBuild":null,"Labels":{"build-date":"20160701","license":"GPLv2","name":"CentOS Base Image","vendor":"CentOS"}}# docker inspect --format '{ {json .NetworkSettings.IPAddress}}' xxbandy "10.0.0.2"# docker inspect --format '{ {json .NetworkSettings.Ports}}' xxbandy {"8000/tcp":[{"HostIp":"0.0.0.0","HostPort":"2222"}]}默认是map映射格式:# docker inspect --format '{ { .NetworkSettings.Ports}}' xxbandy map[8000/tcp:[{0.0.0.0 2222}]]
- Docker1.12容器管理-日志相关: 1.配置日志驱动: 默认支持很多种日志驱常见的有json-file,rsyslog,journald,可以使用在docker run 的时候使用–log-driver= 设定需要的日志驱动,默认使用的是json-flie格式。 需要注意的是,docker logs命令目前只吃吃json-file和journald格式 json-file格式相关参数: –log-opt max-size= 当容器日志达到一定程度就会回滚 2.为日志打标签
- Docker1.12容器管理-运行状态测量:
1.docker使用docker stats命令来查看容器的运行状态,支持查看CPU ,MEM,NET等状态。
# docker stats --no-stream xxbandyCONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDSxxbandy 0.01% 123.2 MiB / 3.702 GiB 3.25% 6.632 MB / 4.066 MB 52.11 MB / 6.328 MB 0
2.Cgroups
linux容器技术依赖于cgroup技术,通过cgroup相关文件可以暴露出来cpu,内存以及I/0的使用情况。cgroup通过一个pseudo-filesystem暴露使用详情,因此你可以在/sys/fs/cgroup中去找到相关的查找。当然也有一些老的linux系统会将cgroup挂载在/cgroup下,这个可以查看cgroup包具体讲一些软件装在什么地方。当然也可以直接使用以下命令发现当前系统挂载点:# grep cgroup /proc/mounts
3.列举cgroup可以管控的资源信息:
# cat /proc/cgroups
当然也可以使用/proc/pid/cgroup查看一个进程属于哪个控制组信息,或者通过查看某一个正在运行容器使用的内存限制:/sys/fs/cgroup/memory/docker/longid/.
4.内存,cpu,block I/O上的限制:
可以使用memory.stat文件进行内存上的限制,# cat /sys/fs/cgroup/memory/docker/memory.stat cache 20082688rss 0rss_huge 0mapped_file 6488064swap 0pgpgin 4903pgpgout 0pgfault 0pgmajfault 0inactive_anon 0active_anon 0inactive_file 13438976active_file 6643712unevictable 0hierarchical_memory_limit 9223372036854775807hierarchical_memsw_limit 9223372036854775807total_cache 20082688total_rss 3604480total_rss_huge 0total_mapped_file 6488064total_swap 0total_pgpgin 7694total_pgpgout 2422total_pgfault 5083total_pgmajfault 0total_inactive_anon 0total_active_anon 3604480total_inactive_file 13438976total_active_file 6643712total_unevictable 0
上图中前半部分没有以total_开头的是在cgroups中有关进程的统计,后半部分包含sub-cgrouops的统计。
cache:这个被cgroup控制进程的内存值会在block设备上分配一个block,当在读写disk上的文件,这个值会增加。这也是被tmpfs使用的内存值 rss:这个值不会和磁盘上的一致:stacks,heaps, anonymous memory maps mapped_file:表示映射到cgroup里面进程的内存量,不会告诉你使用了多少内存信息,只会告诉你他怎样被使用的。 swap:cgroup中被进程使用的当前swap值可以使用cpuacct.stat文件对容器的cpu进行相关限制:
显示当前所有容器中进程占用的cpu# cat /sys/fs/cgroup/cpu,cpuacct/docker/cpuacct.stat user 1153system 717
/sys/fs/cgroup/blkio目录中存放block I/O相关信息
5.网络资源的测量:
网络资源部直接由cgroup控制,网络接口直接存在于network namespace。内核能够通过一组进程计算每个包和发送/接受字节的长度,但是这些值一般并没有什么用。 So,一般会使用以下工具进行收集网络状况信息:# iptables -I OUTPUT -p tcp --sport 80# iptables -nxvL OUTPUTChain OUTPUT (policy ACCEPT 3 packets, 396 bytes) pkts bytes target prot opt in out source destination 0 0 tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp spt:80