Docker学习总结

docker是个好东西,虽然年轻,但很有前途。一些大的公司(包括谷歌、IBM、惠普、微软等)都有在使用。有些人不太愿意使用新的技术,怕不稳定,但我个人认为好的东西主要勇于使用,大公司都在使用,怕什么呢,新技术不敢于使用,怎么能进步呢^_^
docker相关的概念请大家自行谷歌,还是谷歌好…

如果是没有docker基础的话,建议买一本<<第一本docker书 修订版>>,入门不错。
docker正式环境只能在linux中使用,所以本文以vagrant+centos7为例介绍。具体环境请参考Vagrant环境搭建

操作系统要求

Docker只能运行在64位Linux中,并且内核需要3.8以上,建议使用centos 7版本。以下是我本机的环境,请参考:

1
2
3
4
5
6
7
8
[root@www ~] cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core)
[root@www ~] uname -a
Linux www.mymydocker.com 3.10.0-327.4.5.el7.x86_64 #1 SMP Mon Jan 25 22:07:14 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[root@www ~] ll /sys/class/misc/device-mapper
lrwxrwxrwx 1 root root 0 Dec 13 08:19 /sys/class/misc/device-mapper -> ../../devices/virtual/misc/device-mapper
[root@www ~] grep device-mapper /proc/devices
253 device-mapper

安装docker

卸载旧的docker版本

当前docker最新版本为1.12,请先卸载旧的docker版本:

1
2
3
rpm -e docker-1.10.3-59.el7.centos.x86_64 \
docker-common-1.10.3-59.el7.centos.x86_64 \
container-selinux-1.10.3-59.el7.centos.x86_64

修改配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#修改dns配置
cat /etc/NetworkManager/NetworkManager.conf|grep "dns=none" > /dev/null
if [[ $? != 0 ]]; then
echo "dns=none" >> /etc/NetworkManager/NetworkManager.conf
systemctl restart NetworkManager.service
fi

#修改时区
ln -sf /usr/share/zoneinfo/Asia/Chongqing /etc/localtime

#关闭内核安全
sed -i 's;SELINUX=.*;SELINUX=disabled;' /etc/selinux/config
setenforce 0
getenforce

#关闭防火墙
systemctl disable iptables
systemctl stop iptables
systemctl disable firewalld
systemctl stop firewalld

#优化内核
cat /etc/security/limits.conf|grep 65535 > /dev/null
if [[ $? != 0 ]]; then
cat >> /etc/security/limits.conf << EOF
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
EOF
fi

#打开端口转发
#永久修改:/etc/sysctl.conf中的net.ipv4.ip_forward=1,生效:sysctl -p
#临时修改:echo 1 > /proc/sys/net/ipv4/ip_forward,重启后失效

cat /etc/sysctl.conf|grep "net.ipv4.ip_forward" > /dev/null
if [[ $? != 0 ]]; then
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.ip_forward = 1
EOF
sysctl -p
fi

添加docker用户组

注意:rpm安装已经自动创建了该组,无需再创建。

1
2
groupadd -g 2016 docker
#useradd docker -u 2016 -g 2016

当发现有docker组时,会自动以docker组启动。

添加yum源:

1
2
3
4
5
6
7
8
tee /etc/yum.repos.d/docker.repo <<-'EOF'
[docker]
name=Docker Repository
baseurl=http://mirrors.aliyun.com/docker-engine/yum/repo/main/centos/7/
enabled=1
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/docker-engine/yum/gpg
EOF

安装

1
yum install docker-engine

手动启动

rpm安装的通过systemctl start docker启动。如果是二进制文件的话,通过以下方式启动:

1
2
3
4
5
#默认以/var/run/docker.sock文件监听
#手动启动:
#-D为debug
docker daemon -D -H tcp://0.0.0.0:2375 \
-H unix://var/run/docker.sock

如出现Devices cgroup isn’t mounted的错误,请执行以下操作:

1
2
wget https://github.com/tianon/cgroupfs-mount/raw/master/cgroupfs-mount
sh cgroupfs-mount

docker加速

官网的速度太慢了,可以使用daocloud加速。请参考what-is-daocloud-accelerator
具体操作如下:

注册https://www.daocloud.io/账户
点击加速器,获取地址
修改/usr/lib/systemd/system/docker.service文件:

1
2
3
4
#ExecStart=/usr/bin/dockerd --bip=10.1.10.1/24 --insecure-registry=192.168.10.6:5000 --registry-mirror=http://3fecfd09.m.daocloud.io
sed -i "s;^ExecStart=/usr/bin/dockerd$;ExecStart=/usr/bin/dockerd \
--registry-mirror=http://3fecfd09.m.daocloud.io;" \
/usr/lib/systemd/system/docker.service

添加代理

国内网站无法访问google的一些资源,可以通过docker代理方式访问:

1
2
3
4
5
6
7
8
9
10
11
12
13
mkdir -p /etc/systemd/system/docker.service.d
cat >> /etc/systemd/system/docker.service.d/http-proxy.conf << EOF
[Service]
Environment="HTTP_PROXY=http://xxxx:xxxx"
Environment="HTTPS_PROXY=http://xxxx:xxxx"
Environment="NO_PROXY=127.0.0.1,localhost,10.0.0.0/8,172.0.0.0/8,192.168.0.0/16,*.zerofinance.net"
EOF

systemctl daemon-reload
systemctl show --property=Environment docker

systemctl restart docker
systemctl enable docker

如执行docker info后出现:
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
按照以下办法解决:
修改/etc/sysctl.conf文件,添加:

1
2
3
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1

执行sysctl -p后生效。

然后 ps aux | grep docker 然后你就会发现带有镜像的启动参数了。

由于我这边的HTTP_PROXY与HTTPS_PROXY是付费购买的,同时只能几个client访问,需要的话请自行搜索或者购买。

Windows安装

win10可以通过InstallDocker.msi直接安装,但win10以下的话,只能通过DockerToolbox安装:

1
2
3
4
5
docker-machine create -d virtualbox \
--engine-registry-mirror http://3fecfd09.m.daocloud.io \
--engine-registry-mirror https://3gbbfq7n.mirror.aliyuncs.com \
--engine-registry-mirror http://zhaoxunyong.m.alauda.cn \
default

Docker Registry

参考

http://www.cnblogs.com/lienhua34/p/4922130.html
https://docs.docker.com/registry/deploying/

安装registry:2

普通安装方式

安装:

1
2
docker create -p 5000:5000 --restart=always --name private_registry \
-v /docker/registry:/var/lib/registry registry:2

映射主机的/docker/registry目录到容器的/var/lib/registry

异常解决:
当出现Get https://192.168.10.6:5000/v1/_ping: Connection failed错误时,由于改为http方式,需要修改以下配置:

1
2
3
4
5
6
vim /usr/lib/systemd/system/docker.service
#添加--insecure-registry参数
ExecStart=/usr/bin/dockerd --insecure-registry=192.168.10.6:5000
#重启
systemctl daemon-reload
systemctl restart docker

证书安装方式

参考: https://www.tianmaying.com/tutorial/docker-registry
先/etc/pki/tls/openssl.cnf配置,在该文件中找到[ v3_ca ],在它下面添加如下内容:

1
2
3
[ v3_ca ]
# Extensions for a typical CA
subjectAltName = IP:192.168.10.6

以上也可以不配置,在openssl加上reqexts SAN参数设置。

安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
openssl req \
-subj "/C=CN/ST=GuangDong/L=ShenZhen/CN=registry.gcalls.cn" \
-reqexts SAN -config <(cat /etc/pki/tls/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:www.abc.com,IP:192.168.10.6")) \
-newkey rsa:4096 -nodes -sha256 -keyout domain.key \
-x509 -days 365 -out domain.crt

mkdir -p /etc/docker/certs.d/192.168.10.6:5000
cp domain.crt /etc/docker/certs.d/192.168.10.6:5000/ca.crt
mkdir -p /root/certs/
cp domain.crt domain.key /root/certs/

docker run \
-d \
--name private_registry --restart=always \
-e SETTINGS_FLAVOUR=dev \
-e STORAGE_PATH=/registry-storage \
-v /docker/registry:/var/lib/registry \
-u root \
-p 5000:5000 \
-v /root/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2

注意:如果采用证书方式,需要去掉/usr/lib/systemd/system/docker.service中的–insecure-registry参数,然后再重启:

1
2
systemctl daemon-reload
systemctl restart docker

如果要用docker pull或者docker push的客户端,都需要执行以下命令:

1
2
mkdir -p /etc/docker/certs.d/192.168.10.6:5000
cp domain.crt /etc/docker/certs.d/192.168.10.6:5000/ca.crt

否则,会报以下错误:

1
Error response from daemon: Get https://192.168.10.6:5000/v1/_ping: x509: certificate signed by unknown authority

测试

1
2
3
docker pull hello-world
docker tag hello-world 192.168.10.6:5000/hello-world
docker push 192.168.10.6:5000/hello-world

如测试出现:
Get https://192.168.10.6:5000/v1/_ping: net/http: TLS handshake timeout
有可以本地与docker开启了代理,需要关闭docker代理或者将ip添加到NO_PROXY中,文件位于:
/etc/systemd/system/docker.service.d/http-proxy.conf

Get https://192.168.10.6:5000/v1/_ping: x509: cannot validate certificate for 192.168.10.6 because it doesn’t contain any IP SANs
这个是由于CN为registry.gcalls.cn,但通过ip,需要添加SAN信息:
先/etc/pki/tls/openssl.cnf配置,在该文件中找到[ v3_ca ],在它下面添加如下内容:

1
2
3
[ v3_ca ]
# Extensions for a typical CA
subjectAltName = IP:192.168.10.6

也可以直接在创建crt时,传-reqexts SAN。

删除镜像文件

删除private registry中的镜像:

1
2
3
docker exec -it private_registry /bin/sh
#删除/var/lib/registry/docker/registry/v2/repositories目录下对应的目录
rm /var/lib/registry/docker/registry/v2/repositories/*

启动

1
docker start private_registry

查看ip

1
docker exec private_registry ip addr

Docker mirror Registry

参考:https://mritd.me/2016/09/24/Docker-mirror-Registry/

导出registry配置

1
docker run -it --rm --entrypoint cat registry:2 /etc/docker/registry/config.yml > config.yml

修改配置

如果想要使用mirror功能只需在下面增加proxy选项即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :5000
headers:
X-Content-Type-Options: [nosniff]
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
proxy:
remoteurl: https://registry-1.docker.io
username: [username]
password: [password]

username与password是可选项,当填写username与password以后就可以从hub pull私有镜像了。

启动mirror registry

1
2
3
4
docker run -dt --name docker-registry-mirror \
-v /docker/registry:/var/lib/registry \
-v $PWD/config.yml:/etc/docker/registry/config.yml \
-p 5000:5000 registry:2

导入本地的images到私服中

push.sh:

1
2
3
4
5
6
7
8
#!/bin/sh
imgs=$(docker images|awk '{print $1":"$2}')
for img in $imgs
do
docker tag $img 192.168.10.6:5000/$img
docker push 192.168.10.6:5000/$img
docker rmi 192.168.10.6:5000/$img
done

安装shipyard

shipyard可以通过web的方式操作本地的镜像,还可以浏览指定的private registry,具体安装方式如下:

1
2
3
4
#dockerui:
#docker run -d -p 9000:9000 --name dockerui -v /var/run/docker.sock:/var/run/docker.sock uifd/ui-for-docker
#docker start dockerui
wget -O shipyard.sh https://shipyard-project.com/deploy

安装:

1
2
#curl -s https://shipyard-project.com/deploy | bash -s
export ACTION=deploy;export PORT=9001;sh shipyard.sh

更新:

1
2
#curl -s https://shipyard-project.com/deploy | ACTION=upgrade bash -s
export ACTION=upgrade;export PORT=9001;sh shipyard.sh

移除:

1
2
#curl -s https://shipyard-project.com/deploy | ACTION=remove bash -s
export ACTION=remove;sh shipyard.sh

更多查看:

1
sh shipyard.sh -h

访问地址:

1
http://192.168.10.6:9001/

注意:

防火墙要放行2375端口,否则看不到container
添加registry时,需要指定https的地址,如:https://192.168.10.6:5000
login: admin/shipyard

安装registry ui

registry ui有很多,包括:

docker-registry-frontend

可以使用docker-registry-frontend,具体安装方式如下:

普通安装方式

1
2
3
4
5
6
7
8
9
10
#docker run -d -p 8080:8080 atcol/docker-registry-ui(不支持V2,不能使用)
sudo docker run \
-d \
-e ENV_DOCKER_REGISTRY_HOST=192.168.10.6 \
-e ENV_DOCKER_REGISTRY_PORT=5000 \
-p 9002:80 \
konradkleine/docker-registry-frontend:v2
#重启:
docker stop $(docker ps -a |grep docker-registry-frontend|awk '{print $1}')
docker start $(docker ps -a |grep docker-registry-frontend|awk '{print $1}')

访问:

1
http://192.168.10.6:9002

证书安装方式

1
2
3
4
5
6
7
8
9
10
sudo docker run \
-d \
-e ENV_DOCKER_REGISTRY_HOST=192.168.10.6 \
-e ENV_DOCKER_REGISTRY_PORT=5000 \
-e ENV_DOCKER_REGISTRY_USE_SSL=1 \
-e ENV_USE_SSL=yes \
-v /root/certs/domain.crt:/etc/apache2/server.crt:ro \
-v /root/certs/domain.key:/etc/apache2/server.key:ro \
-p 9002:443 \
konradkleine/docker-registry-frontend:v2

异常解决:
如果出现The proxy server could not handle the request GET /v2/_catalog的错误,需要添加:

1
-e ENV_DOCKER_REGISTRY_USE_SSL=1

访问:
https://192.168.10.6:9002

Nexus

参考:https://mritd.me/2017/01/08/set-up-docker-registry-by-nexus/
安装稍后补充。

harbor

参考:https://vmware.github.io/harbor/index_cn.html
https://mritd.me/2016/09/15/Harbor-%E4%BC%81%E4%B8%9A%E7%BA%A7-Docker-Registry-%E7%AC%AC%E4%BA%8C%E5%BC%B9/
注意:harbor不需要事先安装docker registry。

安装

1
2
3
wget https://github.com/vmware/harbor/releases/download/0.5.0/harbor-offline-installer-0.5.0.tgz
tar zxvf harbor-offline-installer-0.5.0.tgz
cd harbor

修改配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[root@zhaoxy harbor]# grep -v ^# harbor.cfg 

#修改hostname
hostname = registry.gcalls.cn
ui_url_protocol = https

#修改email
email_identity =
email_server = smtp.exmail.qq.com
email_server_port = 25
email_username = xxx@xxx.com
email_password = xxx
email_from = xxx@xxx.com
email_ssl = false

harbor_admin_password = Harbor12345
auth_mode = db_auth
ldap_url = ldaps://ldap.mydomain.com
ldap_basedn = ou=people,dc=mydomain,dc=com
ldap_uid = uid
ldap_scope = 3
db_password = root123

#开放用户注册
self_registration = on

use_compressed_js = on
max_job_workers = 3
token_expiration = 30
verify_remote_cert = on

customize_crt = on

#证书信息
crt_country = CN
crt_state = guangdong
crt_location = shenzhen
crt_organization = Gcalls.cn
crt_organizationalunit = Gcalls.cn
crt_commonname = registry.gcalls.cn
crt_email = zhaoxunyong@qq.com

project_creation_restriction = everyone

#nginx的证书路径
ssl_cert = /docker/works/harbor/ca/registry.gcalls.cn.crt
ssl_cert_key = /docker/works/harbor/ca/registry.gcalls.cn.key

证书生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#创建CA
mkdir ca
cd ca
openssl req \
-subj "/C=CN/ST=guangdong/L=shenzhen/CN=*.gcalls.cn" \
-newkey rsa:4096 -nodes -sha256 -keyout ca.key \
-x509 -days 365 -out ca.crt

#创建签名请求
openssl req \
-subj "/C=CN/ST=guangdong/L=shenzhen/CN=registry.gcalls.cn" \
-newkey rsa:4096 -nodes -sha256 -keyout registry.gcalls.cn.key \
-out registry.gcalls.cn.csr

#初始化,不然下面的操作会报错
cd /etc/pki/CA/
touch index.txt
echo '01' > serial
cd -

#签署证书
#openssl x509 -req -days 365 -in /csr/abc.req.csr -signkey /csr/abc.key.pem.encrypted -out /csr/abc.cert.crt
openssl ca -in registry.gcalls.cn.csr -out registry.gcalls.cn.crt -cert ca.crt -keyfile ca.key -outdir .

安装

1
2
3
4
5
6
7
#先安装docker-compose
yum install epel-release
yum install python2-pip
pip install -U docker-compose

#安装harbor
./install.sh

访问地址

登录密码默认为:admin/Harbor12345

1
https://registry.gcalls.cn

push测试

注意:需要push的客户端要先把ca.crt文件复制到/etc/docker/certs.d/registry.gcalls.cn/目录下

1
2
3
4
5
6
7
8
9
#init
mkdir -p /etc/docker/certs.d/registry.gcalls.cn
cp ca/ca.crt /etc/docker/certs.d/registry.gcalls.cn/

#login
docker login registry.gcalls.cn
docker tag nginx:1.11.5 registry.gcalls.cn/harbor/nginx:1.11.5
#需要先通过访问https://registry.gcalls.cn登录后创建harbor项目
docker push registry.gcalls.cn/harbor/nginx:1.11.5

Harbor镜像仓库

注意:镜像仓库不允许 push 操作,只作为官方仓库缓存。

1
2
3
4
5
6
7
8
vim common/templates/registry/config.yml
# 增加以下内容
proxy:
remoteurl: https://registry-1.docker.io
# 然后重新部署即可
docker-compose down
rm /data/database /data/job_logs /data/registry /data/secretkey
docker up -d

基本命令

创建容器交互式容器:

1
2
3
4
5
6
7
8
9
docker run --name web -i -t docker.io/centos /bin/bash
docker run -it -e TZ=Asia/Shanghai ubuntu bash
--name:容器命名
--rm: 创建并运行一次后自动删除
-d: 守护式容器,不加-d的话,会直接进入docker命令行,exit后容器也退出了。
--restart=on-failure:5 当容器退出代码为非0时,自动尝试重启5次
--restart=always 容器退出时,总会自动启动
-v $PWD/website:/var/www/html/website:ro 挂载目录到容器,挂载website目录到容器的var/www/htmlwebsite,权限为ro, rw为可读写(默认) ro为只读
--volumes-from containername 把containername所有的VOLUME挂载到新容器中。

显示正在运行的容器:

1
docker ps

显示所有的容器:

1
docker ps -a

显示所有的容器的id:

1
docker ps -a -q

显示最近一个运行的容器:

1
docker ps -l

删除:

1
docker rm <CONTAINER ID>

删除数据卷:
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v这个命令。无主的数据卷可能会占据很多空间,要清理会很麻烦。

1
docker rm -vf <CONTAINER ID>

-f:表示强制删除运行中的容器。

停止所有的docker容器:

1
docker stop $(docker ps -q -a)

启动与停止:

1
2
docker start <NAME>
docker stop <NAME>

特权运行:

1
2
#true:Docker将拥有访问host所有设备的权限
docker run --privileged=true ......

进入已启动的容器:

1
docker attach <NAME>

注意:进入容器后,执行exit后,容器会关掉。要:CTRL+P+Q才不会退出容器
docker rm后,再创建容器会恢复到原始内容。

查看已运行的容器日志:

1
2
3
4
5
6
7
8
9
docker run --name daemon_dave -d docker.io/centos /bin/sh -c "while true;do echo hello world;sleep 1;done"
docker run --log-driver="syslog" --name dave -d docker.io/centos /bin/sh -c "while true;do echo hello world;sleep 1;done"
#显示最近100条的记录:
docker logs --tail 100 web
#捕捉最新的日志:
docker logs -f web

#将日志输出到/var/log/message中,通过docker logs会禁用
--log-driver="syslog"

容器内进程:

1
docker top|stats <NAME1> <NAME2>

在容器外部执行容器内的命令:

1
2
3
docker exec -d web touch /etc/new_config_file
docker exec -it web /bin/bash
#类似于docker attach web,但容器不会自动退出

docker的目录:
/var/lib/docker,包括了镜像、配置。

显示本机中的docker镜像:

1
docker images

虚悬镜像:
镜像列表中,还可以看到一个特殊的镜像,这个镜像既没有仓库名,也没有标签,均为 ,这类无标签镜像也被称为 虚悬镜像(dangling image) ,可
以用下面的命令专门删除这类镜像:

1
2
3
4
5
6
#列出虚悬镜像:
docker images -f dangling=true
#删除虚悬镜像:
docker rmi $(docker images -q -f dangling=true)
#删除所有在 mongo:3.2 之前的镜像:
docker rmi $(docker images -q -f before=mongo:3.2)

搜索:

1
docker search redis

checkout:

1
2
docker login
docker pull docker.io/redis

commit到hub.docker.com:
commit本机:

1
docker commit -m "A newcustom image" -a "zhaoxunyong" redis zhaoxunyong/redis:1.0.0-SNAPSHOT

commit到hub.docker.com:

1
docker push zhaoxunyong/redis:1.0.0-SNAPSHOT

指定端口:

1
2
docker run -d -p 80 --name nginx zhaoxunyong/mycentos nginx -g "daemon off;"
docker run -d -p 8080:80 --name nginx zhaoxunyong/mycentos nginx -g "daemon off;"

-p 8080:80: 表示把容器中的80端口映射到宿主机的8080端口
run -d -P –name nginx zhaoxunyong/mycentos nginx -g “daemon off;”
-P:表示将Dockerfile中的EXPOSE端口对外分布

查看映射的端口:

1
docker port nginx 80

导入或导出

镜像导出

1
docker save -o centos.tar centos:latest

导入到images repo

1
docker load -i centos.tar

容器导出

1
2
3
4
#找到容器id
docker ps
#导出:
docker export 19cb419ceb15 > mycentos.tar

注意:
导出的为运行中的容器内容,包括已经在容器中安装的软件都会一并导出。

导入到images repo

1
docker import mycentos.tar mycentos

注意:
import命令是将tar导入到images中,而不是创建一个运行的容器。可以通过docker images查看。

数据卷容器

如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。
首先,创建一个名为 dbdata 的数据卷容器:

1
docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres

然后,在其他容器中使用 –volumes-from 来挂载 dbdata 容器中的数据卷。

1
2
docker run -d --volumes-from dbdata --name db1 training/postgres
docker run -d --volumes-from dbdata --name db2 training/postgres

可以使用超过一个的 –volumes-from 参数来指定从多个容器挂载不同的数据卷。 也可以从其他已经挂载了数据卷的容器来级联挂载数据卷。

1
docker run -d --name db3 --volumes-from db1 training/postgres

注意:
使用 –volumes-from 参数所挂载数据卷的容器自己并不需要保持在运行状态。
如果删除了挂载的容器(包括 dbdata、db1 和 db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 docker rm -v 命令来指定同时删除关联的容器。 这可以让用户在容器之间升级和移动数据卷。

Dockerfile

基本指令

RUN

exec形式:RUN [“executable”, “param1”, “param2”]
shell形式:RUN command param1 param2
在Dockerfile构建镜像的过程(Build)中运行,最终被commit的到镜像。

CMD

exec形式:CMD [“executable”, “param1”, “param2”]
shell形式:CMD command param1 param2
注意:CMD只能指定一条。如果docker run有传cmd的话,Dockerfile中的CMD无效

ENTRYPOINT

exec形式:ENTRYPOINT [“executable”, “param1”, “param2”]
shell形式:ENTRYPOINT command param1 param2
不会被外面的参数覆盖,同时CMD或者外面传的参数会作为ENTRYPOINT的参数
也可以在外面:docker run –entrypoint覆盖ENTRYPOINT指令
ENTRYPOINT和CMD在容器运行(run、start)时运行。

exec与shell的区别:
shell形式和exec的形式的本质区别在于shell形式提供了默认的指令/bin/sh -c,所以其指定的command将在shell的环境下运行。因此指定command的pid将不会是1,因为pid为1的是shell,command进程是shell的子进程。
由于shell的pid不为1,因此我们无法直接向其发送信号,敲Ctrl+C是没有任何反应的。通过docker stop强制退出,退出状态为137,137=128 + 9,表明最后是被kill -9杀掉的。
shell形式还有一个严重的问题:由于其默认使用/bin/sh来运行命令,如果镜像中不包含/bin/sh,容器会无法启动。
exec形式则不然,其直接运行指定的指令,由于exec指定的命令不由shell启动,因此也就无法使用shell中的环境变量,如$HOME。如果希望能够使用环境变量,可以指定命令为sh:CMD [ “sh”, “-c”, “echo”, “$HOME” ]。
注意:
CMD与ENTRYPOINT要使用env变量的话,都要使用”sh”, “-c”,并且命令要在一个引号中,如:

1
2
CMD ["sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -jar /app/${APPNAME}-${VERSION}.jar"]
ENTRYPOINT ["sh", "-c", "java -Djava.security.egd=file:/dev/./urandom -jar /app/${APPNAME}-${VERSION}.jar --spring.profiles.active=docker"]

WORKDIR

脚本运行的工作目录,目录会自动创建。
也可以在外面: -w覆盖WORKDIR指令

ENV

设置环境变更:
ENV WORK_HOME /zxy
WORKDIR $WORK_HOME
进入容器可以通过env查看
也可以通过外面:-e “WORK_HOME=/zxy”指定

USER

USER nginx
指定运行的用户,不指定默认root

VOLUME

VOLUME [“/data”]
创建一个可以从本地主机或其他容器挂载的挂载点

LABEL

LABEL location=”New York” type=”Data Center” role=”Web Server”

COPY/ADD

添加文件,ADD与COPY不同之处在于如果文件是压缩文件,ADD到容器中会自动解压。
支持http方式。

ARG

构建时,传递参数给构建:
ARG build
ARG webapp_user=user(user为默认值)
传递参数:–build-arg build=1234
如:docker build –build-arg build=1234 -t zhaoxunyong/mycentos ./

ONBUILD

触发器:在另外有构建基于这个构建时触发,只能继承一次
如:ONBUILD ADD test.sh /software/

构建

1
docker build --no-cache -t="zhaoxunyong/mycentos:latest" .

–no-ache表示每次都会从头到尾构建,通过docker images就可以看到已经构建的镜像。
还可以查看历史记录:docker history zhaoxunyong/mycentos

网络连接

Networking

版本>=1.9推荐使用:

1
2
3
docker network create app
docker network inspect app
docker network ls

创建:

1
2
docker run -d --net=app --name db docker.io/redis
docker run -it --net=app --name centos docker.io/centos /bin/bash

测试:

1
2
3
4
#ping db就可以ping通
进入docker exec -it centos /bin/bash
#ping centos也可以ping通
进入docker exec -it db /bin/bash

加入到app网络:

1
2
docker run -d -p 8088:80 --name nginx docker.io/nginx
docker network connect app nginx

进入docker exec -it nginx /bin/bash,ping db或centos就能ping通

断开:

1
docker network disconnect app nginx

link:1.9之前版本使用:
–link 原containername:别名
只支持在相同的宿主机中。
可以多次使用–link:

1
2
docker run -d --name db docker.io/redis 
docker run -d -p 8088:80 --name nginx --link db:redis_db docker.io/nginx

进入docker exec -it nginx /bin/bash,ping redis_db就能ping通, /etc/hosts可以看到对应的记录。
可以在容器中通过env查看环境变量
–icc=false:关闭所有没有链接的容器间的通信

Docker compose

参考:
http://debugo.com/docker-compose/
http://www.cnblogs.com/freefei/p/5311294.html

在开发环境、临时服务器、CI中使用Compose是非常合适的。但是,我们目前不建议你在生产环境中使用。

安装pip

1
2
yum install epel-release
yum install python2-pip

安装compose

1
2
pip install -U docker-compose
docker-compose version

Demo

编写Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vim redis/Dockerfile
# Version: 1.0.0
FROM centos
MAINTAINER zhaoxunyong@qq.com

RUN ["yum", "-y", "install", "epel-release"]
RUN yum -y install redis

VOLUME [ "/var/lib/redis", "/var/log/redis" ]

#ENTRYPOINT [ "redis-server", "--protected-mode", "no", "--logfile", "/var/log/redis/redis-server.log" ]
ENTRYPOINT [ "redis-server" ]
CMD ["--protected-mode", "no", "--logfile", "/var/log/redis/redis-server.log"]

EXPOSE 6379

编译:

1
docker build -t zhaoxunyong/redis ./

1
2
3
4
5
6
7
8
9
10
11
12
vim nginx/Dockerfile
# Version: 1.0.0
FROM docker.io/centos

RUN ["yum", "-y", "install", "epel-release"]
RUN yum -y install nginx

EXPOSE 80

#CMD [ "nginx", "-g", "daemon off;"]

docker build -t zhaoxunyong/nginx ./

编译:

1
docker build -t zhaoxunyong/nginx ./

compose:
vim docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
web:
#container_name: web
#image: zhaoxunyong/nginx
build: ./nginx
command: nginx -g 'daemon off;'
ports:
- "8081:80"
volumes:
- $PWD:/pwd
- /webapp:/webapp
links:
- redis:db
#net: app
#hostname: web
#dns:
# - 8.8.8.8
# - 9.9.9.9
#dns_search:
# - domain1.example.com
#mem_limit: 1000000000
#privileged: true
#restart: always
#volumes_from:
# - service_name
# - container_name
#expose:
# - "3000"
# - "8000"
#environment:
# - DEBUG=false
# - SEND_EMAILS=false
#env_file:
# - ./common.env
# - ./apps/web.env
# - /opt/secrets.env

redis:
#container_name: redis
#image: zhaoxunyong/redis
build: ./redis
ports:
- "6379:6379"

启动:

1
2
3
4
5
6
7
8
#docker run --name redis --rm -p 6379:6379 --rm zhaoxunyong/redis --protected-mode no --logfile /var/log/redis/redis-server.log
#docker run --name nginx -p 8081:80 --rm --link redis:db zhaoxunyong/nginx nginx -g "daemon off;"
docker-compose up
docker-compose up -d
docker-compose ps
docker-compose logs
docker-compose logs -f
docker-compose stop

使用-f指定代替的compose文件。
使用-p指定代替compose文件所在的目录。

查看已存在images的Dockfile

参考:https://github.com/lukapeschke/dockerfile-from-image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[root@k8s-node1 ~]# git clone https://github.com/lukapeschke/dockerfile-from-image.git
cd dockerfile-from-image
docker build -t lukapeschke/dfa .

[root@k8s-node1 ~]# docker run --rm -v '/var/run/docker.sock:/var/run/docker.sock' lukapeschke/dfa <IMAGE_ID>

[root@k8s-node1 ~]# docker run --rm -v '/var/run/docker.sock:/var/run/docker.sock' lukapeschke/dfa 405a0b586f7e
FROM kubeguide/redis-master:latest
RUN
ADD file:62400a49cced0d7521560b501f6c52227c60f5e2fecd0fef20e4d0e1558f7301 in /
RUN /bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-rc.d \
&& echo 'exit 101' >> /usr/sbin/policy-rc.d \
&& chmod +x /usr/sbin/policy-rc.d \
&& dpkg-divert --local --rename --add /sbin/initctl \
&& cp -a /usr/sbin/policy-rc.d /sbin/initctl \
&& sed -i 's/^exit.*/exit 0/' /sbin/initctl \
&& echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \
&& echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \
&& echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \
&& echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \
&& echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \
&& echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes
RUN /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list
CMD [/bin/bash]
RUN /bin/sh -c sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list \
&& apt-get update \
&& apt-get -y upgrade \
&& apt-get install -y build-essential \
&& apt-get install -y software-properties-common \
&& apt-get install -y byobu curl git htop man unzip vim wget \
&& rm -rf /var/lib/apt/lists/*
ADD file:1b7d66a2e6558a749e3bb8462c04292d941ca6456e4a0d27575774591c677768 in /root/.bashrc
ADD file:f21c0663779541419bb4a70154751df046dc27d6bfb93362b1d42ea1e4dceb37 in /root/.gitconfig
ADD dir:217b39958cc7efb346372d54c10f32da1230945a6041e9ca98ebb4fe18eb3c07 in /root/.scripts
ENV HOME=/root
WORKDIR /root
CMD [bash]
RUN /bin/sh -c cd /tmp \
&& wget http://download.redis.io/redis-stable.tar.gz \
&& tar xvzf redis-stable.tar.gz \
&& cd redis-stable \
&& make \
&& make install \
&& cp -f src/redis-sentinel /usr/local/bin \
&& mkdir -p /etc/redis \
&& cp -f *.conf /etc/redis \
&& rm -rf /tmp/redis-stable* \
&& sed -i 's/^\(bind .*\)$/# \1/' /etc/redis/redis.conf \
&& sed -i 's/^\(daemonize .*\)$/# \1/' /etc/redis/redis.conf \
&& sed -i 's/^\(dir .*\)$/# \1\ndir \/data/' /etc/redis/redis.conf \
&& sed -i 's/^\(logfile .*\)$/# \1/' /etc/redis/redis.conf
VOLUME [/data]
WORKDIR /data
ADD file:eb94b1ca7cdb7ea1553bfd01686f66b9e5dd9893a4749ce291a8071e40113465 in /etc/redis/redis.conf
EXPOSE map[6379/tcp:{}]
ADD file:58911657b64982dea712ca78ee8811c96e522d06585d29d40a79b2d4f6e935c6 in /etc/redis/redis.conf
CMD [redis-server /etc/redis/redis.conf]
EXPOSE map[6379/tcp:{}]
MAINTAINER kubeguide
ADD multi:0a8d9f4785c98c51ae6f30026e81df4b38fcbda87d73fe189656bdedfe016d32 in /data/

参考

http://c.isme.pub/2016/11/21/learn-docker-install/