整理自《Docker容器与容器云》一书。


1、非root 用户使用docker 命令

将普通用户加入docker用户组:

$ sudo usermod -aG docker your-user


2、设置容器的ulimit 参数
$ docker run --ulimit nofile=1024:1024 --ulimit nproc=1024:1024 --rm debian ulimit -n


3、备份、恢复或迁移volume

源容器(带volume):

$ docker run -it --name vol_simple -v /data ubuntu /bin/bash


1)备份

备份源容器的volume:(启动一个临时容器)

$ docker run --rm --volumes-from vol_simple -v $(pwd):/backup ubuntu tar cvf /backup/data.tar /data


2)恢复

新容器:

$ docker run -it --name vol_bck -v /data ubuntu /bin/bash

恢复源容器的数据到新容器:(启动一个临时容器)

$ docker run --rm --volumes-from vol_bck -v $(pwd):/backup ubuntu tar xvf /backup/data.tar -C /


4、SSH服务器的替代方案

容器实际上是一个进程,显然我们不会在进程里再启动一个SSH服务器。

Docker提供了 docker exec 命令,可以在已运行的容器中执行想要的命令,并得到反馈的结果。这个命令实际上可以解决大部分需要ssh进入容器的问题,同样也可以解决诸如定时任务等问题。

对于需要进入容器修改配置文件的需求:

  • 如果需要长期使用这份配置文件,它应该被集成到镜像中

  • 如果需要经常修改这份配置文件,那么应该使用volume共享这份配置

对于某些特殊需求需要进入容器,如程序调试等,则可以使用docker exec 直接在容器中启动一个shell:

$ docker exec -it <containerName> /bin/bash


5、Docker容器内应用日志的管理方案

容器的stdout和stderr 输出存在了 /var/lib/docker/containers/<containerID>/<containerID>-json.log 文件下( /var/lib/docker/ 即 docker graph 目录),docker logs 命令就是从这里读取日志的。

docker logs存在的问题:

  • JSON消息格式存储,日志文件增长过快

  • 日志文件没有自动切分功能(待验证)

  • docker logs命令返回的日志记录也过于冗长

主流解决方案,3种:

  1. 在容器内收集:

    1. 容器内启动一个日志收集进程

    2. 需要定制Docker镜像,典型代表为 baseimage-docker 项目

  2. 在容器外收集:

    1. 宿主机上运行一个单独收集日志的代理,收集所有容器的日志

    2. 容器挂载 volume 数据卷,把日志记录在挂载卷中

    3. 也可以直接处理 docker graph 目录下的容器日志,开源项目Fluentd

  3. 在专用容器中收集:

    1. 在宿主机运行日志收集代理的变种方案,该代理运行在一个容器中

    2. 且该容器的volume 使用docker run 的 --volumes-from 选项被绑定给其他应用程序容器

    3. 参考 Docker and Logstash 一文 



环境说明:Centos 7.1 64Bit + Docker 1.9.1,仓库的存储以使用本地磁盘为例。

一、安装配置registry server v2

官方部署指南:Deploying a registry server 

由于v1版本的registry要被官方废弃了,所以我们选择安装v2版本。(注:v2版本需要TLS加密连接)

1、Get a certificate(为域名TLS访问配置证书)

创建一个 certs 目录:

$ mkdir -p certs

然后将仓库域名在权威机构申请的证书 crt 文件放入并命名为certs/domain.crt,将 key 文件放入并命名为  certs/domain.key

如果使用私有证书,可以这么创建:

$ mkdir -p certs && openssl req \
   -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
   -x509 -days 365 -out certs/domain.crt

为了让 docker 客户端信任私有证书,需要将证书文件放入使用该仓库的所有 docker 客户端的服务器上:

以仓库所在的 docker 本机为例:

$ sudo mkdir /etc/docker/certs.d/docker-hub.yourdomain.com:5000/ -p
$ sudo cp certs/domain.crt /etc/docker/certs.d/docker-hub.yourdomain.com\:5000/ca.crt

 

2、Native basic auth(配置登陆认证,本例使用 htpasswd 方式)

使用 htpasswd 命令生成密码文件前,需要先安装 httpd-tools 。另外 htpasswd 授权必须配合TLS一同使用,并且只支持 bcrypt 格式的密码。

创建 htpasswd 密码文件,并添加一个用户user1

$ mkdir auth
$ htpasswd -cB auth/htpasswd user1

再添加一个用户user2

$ htpasswd -B htpasswd user2

 

3、启动 registry 容器(本例网络使用 host 模式)
$ docker pull registry:2
$ docker run -d --net=host --restart=always --name registry \
   -v `pwd`/data:/var/lib/registry \     (注:仓库的数据目录)
   -v `pwd`/auth:/auth \
   -e "REGISTRY_AUTH=htpasswd" \
   -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
   -v `pwd`/certs:/certs \
   -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
   -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
   registry:2

 

4、启动成功,测试一下
$ docker pull ubuntu
$ docker tag ubuntu docker-hub.yourdomain.com:5000/ubuntu:latest
$ docker login -u user1 -p yourpasswd -e "your@email-address.com" docker-hub.yourdomain.com:5000
$ docker push docker-hub.yourdomain.com:5000/ubuntu:latest
$ docker pull docker-hub.yourdomain.com:5000/ubuntu:latest

- 阅读剩余部分 -


一、macvlan 介绍(some-notes-on-macvlanmacvtap

一般来说,我们在自定义Docker与外部网络通信的网络,除了NAT,还有Linux Bridge、Open vSwitch、MacVLAN几种选择。MacVLAN相对于前两者,拥有更好的性能。

macvlan可以看做是物理网卡的子接口,每个macvlan子接口有其自己的MAC地址(跟物理网卡的也不同),而且可以为每个macvlan子接口设置IP地址。

即在同一个物理网卡上设置多个不同的IP+MAC地址的子接口,我们称macvlan子接口所依附的物理网卡为lower device。

MacVLAN有4种模式,参考这里。 VEPA需要接入交换机支持hairpin mode。相对而言,Bridge mode更加常用。

 

macvlan可以工作在四种模式下:

  • VEPA(Virtual Ethernet Port Aggregator)mode:default 模式,If the lower device receives data from a macvlan in VEPA mode, this data is always sent "out" to the upstream switch or bridge, even if it's destined for another macvlan in the same lower device.

  • Brideg mode:this works almost like a traditional bridge, in that data received on a macvlan in bridge mode and destined for another macvlan of the same lower device is sent directly to the target (if the target macvlan is also in bridge mode), rather than being sent outside.

  • Private mode:this is essentially like VEPA mode, but with the added feature that no macvlans on the same lower device can communicate, regardless of where the packets come from (so even if inter-VM traffic is sent back by a hairpin switch or an IP router, the target macvlan is prevented from receiving it).

  • Passthru mode:this mode was added later, to work around some limitation of macvlans (more details  here ).

MACVLAN工作方式补充:

有时我们可能需要一块物理网卡绑定多个 IP 以及多个 MAC 地址,虽然绑定多个 IP 很容易,但是这些 IP 会共享物理网卡的 MAC 地址,可能无法满足我们的设计需求,所以有了 MACVLAN 设备,其工作方式如下:

MACVLAN 会根据收到包的目的 MAC 地址判断这个包需要交给哪个虚拟网卡。单独使用 MACVLAN 好像毫无意义,但是配合容器的 network namespace 使用,我们可以构建这样的网络:

由于 macvlan 与 eth0 处于不同的 namespace,拥有不同的 network stack,这样使用可以不需要建立 bridge 在 virtual namespace 里面使用网络。

- 阅读剩余部分 -


0、Centos 7 安装

最小安装 + 基本开发包(Minimal Install + Development Tools) 即可。

1、升级内核
1)升级内核
# wget http://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-ml-4.2.5-1.el7.elrepo.x86_64.rpm
# rpm -ivh kernel-ml-4.2.5-1.el7.elrepo.x86_64.rpm
2)grub2启动项配置

查看启动项

# cat /boot/grub2/grub.cfg |grep menuentry
 
menuentry 'CentOS Linux (4.2.5-1.el7.elrepo.x86_64) 7 (Core)' --class centos ...
menuentry 'CentOS Linux (3.10.0-229.20.1.el7.x86_64) 7 (Core)' --class centos ...

# cat /boot/grub2/grubenv     //这里记录了默认启动项
# GRUB Environment Block
saved_entry=CentOS Linux (3.10.0-229.20.1.el7.x86_64) 7 (Core)

 

修改默认启动内核为4.2.5:

# grub2-set-default 'CentOS Linux (4.2.5-1.el7.elrepo.x86_64) 7 (Core)'
 
# grub2-editenv list
saved_entry=CentOS Linux (4.2.5-1.el7.elrepo.x86_64) 7 (Core)


3)开启 User namespaces

# grubby --args="user_namespace.enable=1" --update-kernel=/boot/vmlinuz-4.2.5-1.el7.elrepo.x86_64
 
检查一下,应该已经在 boot command line 上加上启动参数了:
# grep user_namespace /boot/grub2/grub.cfg
 
# reboot


2、关闭SELinux
# vi /etc/selinux/config 
SELINUX=disabled

# reboot


3、关闭firewalld(以免和docker创建iptables规则冲突

改用传统的iptables-service 来管理iptables规则

# systemctl stop firewalld
# systemctl disable firewalld

# yum install iptables-services
# systemctl disable iptables.service  //不需要启用这个服务,docker会自动启动iptables


4、安装docker
# wget -qO- https://get.docker.com/ | sh

 

5、配置和启动Docker
1)配置docker服务开机自动启动:
# systemctl list-unit-files |grep [d]ocker
# systemctl enable docker.service
2)配置docker启动参数:

官网的建议方法如下:(好处是不用修改docker的systemd配置文件,这样在docker升级后不用重新修改该文件)

# mkdir /etc/systemd/system/docker.service.d/

# vi /etc/systemd/system/docker.service.d/docker.conf   (注意这个文件名,不能是 docker 或者 docker.service )

[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// --storage-driver=overlay
(这段启动命令从 /usr/lib/systemd/system/docker.service 拷贝而来,再加入我们需要的启动参数即可)


# systemctl daemon-reload 

# systemctl start docker


老方法(不建议了):

*************************************************************************************************

# vi /usr/lib/systemd/system/docker.service 
 
[Service]
EnvironmentFile=-/etc/sysconfig/docker  (加入这一行)
Type=notify
ExecStart=/usr/bin/docker daemon -H fd:// $OPTIONS  (加入$OPTIONS)
 
# vi /etc/sysconfig/docker 

OPTIONS="--storage-driver=overlay"
 
# systemctl daemon-reload
 
# systemctl start docker

*************************************************************************************************

6、常用命令做成脚本(方便我们查看容器的PID和IP)
# vi /usr/local/bin/docker-pid 
 
#!/bin/sh
exec docker inspect --format '{{ .State.Pid }}' "$@"
 
--
 
# vi /usr/local/bin/docker-ip
 
 
#!/bin/sh
exec docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$@"
 
# chmod 755 /usr/local/bin/docker-*
7、启动第一个容器试试(hello-world)
# docker run hello-world


附:官方提供了内核环境的检查脚本 docker/contrib/check-config.sh ( wget raw_file )