docker安装学习记录

摘要

本文部分内容来源于网络,个人收集整理,请勿传播

这篇文章的内容是我在学习docker的过程中记录的,仅供参考

本文后面大部分实例都是取自《第一本docker书》,内容已经很老了,比较陈旧,参考一下就行了,不需要去自己试验了,后面会有一篇文章记录日常试验的过程。

本文主要docker环境为 ubuntu 16.04.1。

docker 安装

1
2
3
4
5
6
7
8

使用docker官方脚本安装
curl -sSL https://get.docker.com | sh -
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun


使用阿里云源脚本安装
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -

ubuntu 安装

安装启动项管理工具

1
apt-get install sysv-rc-conf
1
2
apt update && apt upgrade -y
apt install -y curl

手动安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2: 安装GPG证书
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# Step 3: 写入软件源信息
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# Step 4: 更新并安装 Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce

# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# apt-cache madison docker-ce
# docker-ce | 17.03.1~ce-0~ubuntu-xenial | http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# docker-ce | 17.03.0~ce-0~ubuntu-xenial | http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# Step 2: 安装指定版本的Docker-CE: (VERSION 例如上面的 17.03.1~ce-0~ubuntu-xenial)
# sudo apt-get -y install docker-ce=[VERSION]

centos7 安装

干净的 CentOS 7(Kernel > 3.10)环境

1
2
yum -y update
yum -y install lvm2

Kernel 需要使用 3.10.0-514.6.1.el7.x86_64 以上 当前稳定版本 1.13.0

1
2
3
4
5
6
7
8
9
10
11
12
13
export YUM_URL="http://mirrors.aliyun.com/docker-engine/yum"

cat > /etc/yum.repos.d/docker-main.repo <<-EOF
[docker-main-repo]
name=Docker main Repository
baseurl=${YUM_URL}/repo/main/centos/7
enabled=1
gpgcheck=1
gpgkey=${YUM_URL}/gpg
EOF

yum install docker-engine-1.13.0
# yum downgrade docker-engine-1.13.0

手动安装(old)

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
# step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加软件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新并安装 Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
# Step 4: 开启Docker服务
sudo service docker start

# 注意:
# 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,你可以通过以下方式开启。同理可以开启各种测试版本等。
# vim /etc/yum.repos.d/docker-ce.repo
# 将 [docker-ce-test] 下方的 enabled=0 修改为 enabled=1
#
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# yum list docker-ce.x86_64 --showduplicates | sort -r
# Loading mirror speeds from cached hostfile
# Loaded plugins: branch, fastestmirror, langpacks
# docker-ce.x86_64 17.03.1.ce-1.el7.centos docker-ce-stable
# docker-ce.x86_64 17.03.1.ce-1.el7.centos @docker-ce-stable
# docker-ce.x86_64 17.03.0.ce-1.el7.centos docker-ce-stable
# Available Packages
# Step2 : 安装指定版本的Docker-CE: (VERSION 例如上面的 17.03.0.ce.1-1.el7.centos)
# sudo yum -y install docker-ce-[VERSION]

二进制安装

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/bin/sh

usage(){
echo "Usage: $0 FILE_NAME_DOCKER_CE_TAR_GZ"
echo " $0 docker-18.03.0--ce.tgz"
echo "Get docker-ce binary from: https://download.docker.com/linux/static/stable/x86_64/"
echo "eg: wget https://download.docker.com/linux/static/stable/x86_64/docker-18.03.0--ce.tgz"
echo ""
}
SYSTEMDDIR=/usr/lib/systemd/system
SERVICEFILE=docker.service
DOCKERDIR=/usr/bin
DOCKERBIN=docker
SERVICENAME=docker

if [ $# -ne 1 ]; then
usage
exit 1
else
FILETARGZ="$1"
fi

if [ ! -f ${FILETARGZ} ]; then
echo "Docker binary tgz files does not exist, please check it"
echo "Get docker-ce binary from: https://download.docker.com/linux/static/stable/x86_64/"
echo "eg: wget https://download.docker.com/linux/static/stable/x86_64/docker-18.03.0--ce.tgz"
exit 1
fi

echo "##unzip : tar xvpf ${FILETARGZ}"
tar xvpf ${FILETARGZ}
echo

echo "##binary : ${DOCKERBIN} copy to ${DOCKERDIR}"
cp -p ${DOCKERBIN}/* ${DOCKERDIR} >/dev/null 2>&1
which ${DOCKERBIN}

echo "##systemd service: ${SERVICEFILE}"
echo "##docker.service: create docker systemd file"
cat >${SYSTEMDDIR}/${SERVICEFILE} <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target docker.socket
[Service]
Type=notify
EnvironmentFile=-/run/flannel/docker
WorkingDirectory=/usr/local/bin
ExecStart=/usr/bin/dockerd \
-H tcp://0.0.0.0:4243 \
-H unix:///var/run/docker.sock \
--selinux-enabled=false \
--log-opt max-size=1g
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF

echo ""

systemctl daemon-reload
echo "##Service status: ${SERVICENAME}"
systemctl status ${SERVICENAME}
echo "##Service restart: ${SERVICENAME}"
systemctl restart ${SERVICENAME}
echo "##Service status: ${SERVICENAME}"
systemctl status ${SERVICENAME}

echo "##Service enabled: ${SERVICENAME}"
systemctl enable ${SERVICENAME}

echo "## docker version"
docker version

Docker 配置

配置 firewalld4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 关闭 Docker
service docker stop

# 关闭 NetworkManager
service NetworkManager stop

# 检查 docker0
firewall-cmd --permanent --zone=trusted --change-interface=docker0

# 启动 NetworkManager
service NetworkManager start

# 设置 docker0 trusted
nmcli connection modify docker0 connection.zone trusted

# 启动 Docker
service docker start

配置 LVM

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
Docker Storage Driver 23
export DEVICE_NAME=/dev/xvdb
export VG_NAME=docker

mkfs.ext4 ${DEVICE_NAME}

pvcreate ${DEVICE_NAME}
vgcreate ${VG_NAME} ${DEVICE_NAME}

echo "activation {
thin_pool_autoextend_threshold=80
thin_pool_autoextend_percent=20
}" > /etc/lvm/profile/docker-thinpool.profile

lvcreate -y --wipesignatures y -n thinpool ${VG_NAME} -l 38%VG
lvcreate -y --wipesignatures y -n thinpoolmeta ${VG_NAME} -l 1%VG

lvconvert -y --zero n -c 512K --thinpool ${VG_NAME}/thinpool --poolmetadata ${VG_NAME}/thinpoolmeta

lvchange -y --metadataprofile docker-thinpool ${VG_NAME}/thinpool

lvcreate -y --wipesignatures y -n bootstrap ${VG_NAME} -l 40%VG
lvcreate -y --wipesignatures y -n data ${VG_NAME} -l 20%VG

mkfs.ext4 /dev/mapper/docker-data
mount /dev/mapper/docker-data /data

mkfs.ext4 /dev/mapper/docker-bootstrap
mount /dev/mapper/docker-bootstrap /var/lib/docker

echo -e "/dev/mapper/docker-data /data ext4 defaults 0 0" >> /etc/fstab
echo -e "/dev/mapper/docker-bootstrap /var/lib/docker ext4 defaults 0 0" >> /etc/fstab
注意,如果需要为 /var/lib/docker 创建 data 逻辑卷,需要重置 Docker,且,重新生成 thinpool,一个 thinpool 只能被一个 docker daemon 使用。

国内镜像仓库

国内镜像仓库

配置 Docker

dockerd参数列表

设备选择

devicemapper

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
创建 /etc/docker/daemon.json

{
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 3,
"disable-legacy-registry": true,
"insecure-registries": [
"http://r.isme.pub"
],
"registry-mirrors": [
"https://uss7pbj4.mirror.aliyuncs.com"
],
"log-driver": "json-file",
"log-opts": {
"labels": "io.cass.isme.pub,log.ignore",
"max-size": "1g",
"max-file": "100"
},
"graph": "/data/docker",
"storage-driver": "overlay2",
# 使用lvm后配置
"storage-opts": [
"dm.thinpooldev=/dev/mapper/docker-thinpool",
"dm.use_deferred_removal=true",
"dm.use_deferred_deletion=true"
],
"bip": "192.168.1.1/16"
}

完整配置

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
{
"authorization-plugins": [],
"data-root": "",
"dns": [],
"dns-opts": [],
"dns-search": [],
"exec-opts": [],
"exec-root": "",
"experimental": false,
"features": {},
"storage-driver": "",
"storage-opts": [],
"labels": [],
"live-restore": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-files":"5",
"labels": "somelabel",
"env": "os,customer"
},
"mtu": 0,
"pidfile": "",
"cluster-store": "",
"cluster-store-opts": {},
"cluster-advertise": "",
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"default-shm-size": "64M",
"shutdown-timeout": 15,
"debug": true,
"hosts": [],
"log-level": "",
"tls": true,
"tlsverify": true,
"tlscacert": "",
"tlscert": "",
"tlskey": "",
"swarm-default-advertise-addr": "",
"api-cors-header": "",
"selinux-enabled": false,
"userns-remap": "",
"group": "",
"cgroup-parent": "",
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
},
"init": false,
"init-path": "/usr/libexec/docker-init",
"ipv6": false,
"iptables": false,
"ip-forward": false,
"ip-masq": false,
"userland-proxy": false,
"userland-proxy-path": "/usr/libexec/docker-proxy",
"ip": "0.0.0.0",
"bridge": "",
"bip": "",
"fixed-cidr": "",
"fixed-cidr-v6": "",
"default-gateway": "",
"default-gateway-v6": "",
"icc": false,
"raw-logs": false,
"allow-nondistributable-artifacts": [],
"registry-mirrors": [],
"seccomp-profile": "",
"insecure-registries": [],
"no-new-privileges": false,
"default-runtime": "runc",
"oom-score-adjust": -500,
"node-generic-resources": ["NVIDIA-GPU=UUID1", "NVIDIA-GPU=UUID2"],
"runtimes": {
"cc-runtime": {
"path": "/usr/bin/cc-runtime"
},
"custom": {
"path": "/usr/local/bin/my-runc-replacement",
"runtimeArgs": [
"--debug"
]
}
},
"default-address-pools":[{"base":"172.80.0.0/16","size":24},
{"base":"172.90.0.0/16","size":24}]
}

Docker 管理

1
2
3
4
5
6
7
8
systemctl enable docker
systemctl disable docker

systemctl daemon-reload

systemctl start docker
systemctl stop docker
systemctl restart docker

配置(old)

修改ufw

1
2
3
4
vim /etc/default/ufw
#DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_FORWARD_POLICY="ACCEPT"
ufw reload

修改启动参数(old)

1
2
3
4
5
6
7
8
9
10
11
12
13
vim /etc/default/docker

DOCKER_OPTS="--graph=/data/docker --insecure-registry r.isme.pub -H tcp://0.0.0.0:4273 -H unix:///var/run/docker.sock"

--graph=/data/docker 修改docker默认存储路径
--insecure-registry r.isme.pub 添加docker信任registry
-H tcp://0.0.0.0:4273 守护进程监听地址
-H unix:///var/run/docker.sock 守护进程监听地址(默认)

# 取消docker daemon日志打到系统日志
vim /etc/systemd/journald.conf
#ForwardToSyslog=yes
ForwardToSyslog=no

systemd配置

如果是init管理进程则不用执行以下步骤

如果是systemd管理进程要做以下修改

1
2
3
4
5
6
7
8
9
10
11
vim /lib/systemd/system/docker.service
# 添加下面
EnvironmentFile=-/etc/default/docker

#然后,修改:
ExecStart=/usr/bin/docker -d -H fd://
改成:
ExecStart=/usr/bin/docker -d -H fd:// $DOCKER_OPTS

systemctl daemon-reload
/etc/init.d/docker restart

docker 守护进程

docker的守护进程会监听/var/run/docker.sock
运行docker守护进程的时候可以用-H指定绑定的端口信息

1
docker -d -H tcp://0.0.0.0:2375

如果修改了服务端的监听端口,客户端不会自行变更,需要

1
docker -H :2375

或者可以修改DOCKER_HOST参数

1
export DOCKER_HOST="tcp://0.0.0.0:2375"

也可以绑定多个监听地址

1
docker -d -H tcp://0.0.0.0:2375 -H unix://home/docker/docker.sock

也可以修改/etc/default/docker的配置文件来配置

docker的基本操作

查看基本信息

1
docker info

出现这个 WARNING: No swap limit support
解决办法

1
2
3
4
vim /etc/default/grub 
GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
update-grub
reboot
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
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 1.12.4
Storage Driver: aufs
Root Dir: /data/docker/aufs
Backing Filesystem: extfs
Dirs: 0
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: host null overlay bridge
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-53-generic
Operating System: Ubuntu 16.04.1 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 974.9 MiB
Name: cass-u
ID: LT5P:B6FE:VARB:NNSJ:HYGP:3AQZ:GWDT:YOHL:6WW3:TJED:JYR6:G2GT
Docker Root Dir: /data/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Insecure Registries:
r.isme.pub
127.0.0.0/8

运行第一个容器

1
docker run -it ubuntu /bin/bash

ubuntu是镜像,如果本地没有会自行下载

1
2
3
4
docker ps 可以看到正在运行的容器
-l 上次运行的
-a 所有的
docker iamges 可以看到所有的景象

给启动的容器命名

1
2
3
4
docker run --name my -it ubuntu /bin/bash

-i 表示容器的STDIN是开启的
-t 表示分配一个伪tty终端

临时启动的容器退出会自动关闭

1
2
docker start my
docker attach my

创建守护容器

1
2
3
docker run --name daemon_my -d ubuntu /bin/sh -c "while true;do echo hello world;sleep 1;done"

-d 表示后台运行

一些查看容器信息的命令

查看容器日志

1
2
3
4
docker logs -ft daemon_my

-f 表示持续输出 类似 tail -f
-t 表示加上时间戳

实时查看容器资源使用情况

1
docker stats daemon_my

查看容器内的进程

1
docker top daemon_my

查看镜像构建历史

1
docker history imageid

查看镜像开放的端口

1
docker port sinaapp

启动时设定主机名

1
docker run -h|--hostname xxx

docker镜像迁移

1
2
docker save -o ooppwwqq0.sinatra.tar ooppwwqq0/sinatra
docker load -i ooppwwqq0.sinatra.tar

在容器内运行进程

exec命令可以在运行的容器内运行新进程
运行的进程分为两种:后台任务和交互任务

1
2
后台任务
docker exec -d daemon_my touch /root/my_file
1
2
交互任务
docker exec -it daemon_my /bin/bash

停止守护式容器

1
docker stop daemon_my

可以用stop向容器发出SIGTERM信号
也可以用kill向容器发出SIGKILL信号

自动重启容器

1
2
3
4
5
6
7
8
docker run --restart=always --name daemon_my -d ubuntu /bin/sh -c "while true;do echo hello world;sleep 1;done"

--restart 的参数设置成always,只要容器退出了就会重启
还可以设置成on-failure的参数,这个参数只有退出代码为非0才会重启,也可以设置重启次数

--restart=unless-stopped

--restart=on-failure:5

深入容器

docker ps只能获取容器的基础信息,还可以用inspect来获取容器的 更多信息。

1
docker inspect daemon_my

也可以使用-f或者–format 来获取指定结果,这个参数支持Go语言的模板

1
docker inspect --format='{{ .State.Running }}' daemon_my

还可以去/var/lib/docker查看docker的文件,镜像,容器都保存在这里目录下

删除容器

1
2
3
4
docker rm `docker ps -aq`

-a 显示所有容器
-q 只返回容器ID

docker镜像和仓库

docker镜像简介

docker镜像是由文件系统叠加而成的。最底端的是一个引导文件系统bootfs。

一个容器启动时,它会移动到内存中,而引导文件系统就会被卸载,留出更多的内存给initrd磁盘镜像使用。

实际上,docker镜像的第二层是root文件系统rootfs,它可以是一种或者多种操作系统。
传统的linux系统:引导启动时,rootfs先以只读的方式加载,引导结束并且完成完整性检查后才会切换成读写模式。
而docker的rootfs一直是只读的,并且docker利用联合加载技术在rootfs上加载更多只读文件系统。联合加载指的是一次同时加载多个文件系统,但是在外面看只有一个,它会把各层文件系统叠加在一起,这样最终的文件系统会包含所有底层的文件和目录。这就是docker的镜像。

docker的镜像可以放在另一个镜像的顶部,下面的叫父镜像,最底部的称为基础镜像,从一个镜像启动的时候,docker会在该镜像的最顶层加载一个读写文件系统,我们运行的程序就是在这个读写层执行的。

docker使用的是写时复制机制。

基本操作

1
2
3
4
5
6
7
8
9
10
列出镜像
docker images
docker images ubuntu

拉取镜像
docker pull ubuntu:16.04
冒号后面写版本号,可以不加

查找镜像
docker search ubuntu

构建镜像

1
docker commit -m="xxx" --author="cass"  xxxxxx xx/xx:tag

Dockerfile 和 docker build

1
2
3
mkdir static_web && cd static_web && touch Dockerfile

用static_web目录来存放Dockerfile,static_web作为构建环境,Docker称此环境为构建上下文
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
编写Dockerfile 
vim Dockerfile
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
RUN apt update
#RUN apt installedl nginx -y
RUN ["apt", "install", "-y", "nginx"]
RUN echo "Hi, I am in your container" \
> /usr/share/nginx/html/index.html
EXPOSE 80

# Version: 0.0.1
FROM centos:6.7
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-07
RUN ["yum","install","-y","httpd"]
RUN echo "Hi, I am in your container" \
> /var/www/html/index.html
EXPOSE 80

构建镜像
docker build -t="ooppwwqq0/sw:v1" .

使用新镜像启动容器
docker run -d -p 8080:80 --name myweb ooppwwqq0/sa:v2 nginx -g "daemon off;"

-p选项可以指定容器开放端口映射到宿主机,-P可以开放容器所有要开放的端口

删除镜像

1
docker rmi

Dockerfile指令

CMD

1
2
3
4
5
构建镜像后,情动容器默认执行的命令,如初始化环境,可以在run的时候被覆盖
CMD只能存在一个,如果多个,会运行最后一个
CMD ["/bin/ps"]

docker run -it ooppwwqq0/sa:v2 /bin/bash

ENTRYPOINT

1
2
3
4
5
6
与CMD命令有些像,但是默认不能被覆盖一般与CMD配合使用,可以配合docker run 传递参数
ENTRYPOINT ["/usr/sbin/nginx"]

CMD ["-h"]

如果想覆盖可以使用--entrypoint来覆盖

WORKDIR

1
2
3
4
5
6
7
8
9
可以用来切换目录,限定一些指令在目录下执行,也可以为最终的镜像设置工作目录

WORKDIR /opt/webapp/db
RUN touch filename
WORKDIR /opt/webapp
ENTRYPOINT ["pwd"]

可以使用-w选项覆盖
docker run -it -w /data/logs ubuntu pwd

ENV

1
2
3
4
可以在镜像构建过程中设置环境变量,可以延续到以此镜像为基础的容器中,也可以用-e选项来传递环境变量

ENV WEB_PATH /home/web
WORKDIR $WEB_PATH

USER

1
2
3
4
指定启动的镜像使用的用户,默认是root
USER user:group
USER uid:gid
USER user:gid

VOLUME

1
2
3
4
5
指定容器启动的时候添加卷,一个卷可以存在一个或多个容器内的特定目录里面,可以实现将数据或者代码添加到镜像中而不是提交到镜像中,并且允许多个容器共享

VOLUME ["/opt/project", "/data"]
前面的宿主机地址挂载到后面容器的地址,后面不写会自动创建和前面一样的路径并挂载
-v选项在run的时候可以自己指定

ADD

1
2
3
4
5
6
用来将构建上下文中的文件或目录复制到镜像中

ADD conf.php /opt/app/conf/conf.php
源文件的路径可以是一个url,不能对构建上下文外的文件进行操作.
Docker通过目标地址的结尾字符判断文件源是文件还是目录,“/”结尾则源是目录,否则认为是文件。
如果源文件在本地是压缩包,如gzip、bzip2、xz,ADD可以解压到指定目录

COPY

1
2
3
4
COPY与ADD比较像,但是COPY不会做解压工作,只是单纯的拷贝。原路径要在构建上下文中,目标路径必须是一个绝对路径,如果目标目录不存在,会自动创建mkdir -p

COPY conf.d/ /etc/apache/
如果原路径是目录,那个整个目录都会拷贝到目的目录中。

ONBUILD

1
2
3
4
5
ONBUILD指令能为镜像添加触发器,当一个镜像被其他镜像用作基础镜像时,该镜像的触发器会被执行(如你的镜像需要从未准备好的位置添加代码,或者你需要执行特定于构建镜像的环境的构建脚本)
触发器会在构建过程插入新指令,我们可以认为这些指令是紧跟在FROM之后的,触发器可以是任意指令。

ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make

在测试中使用docker

构建简单可修改的web

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
wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/global.conf

wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/nginx.conf

cat Dockerfile.bak
# Version: 0.0.1
FROM centos:6.7
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-21
RUN yum install -y epel*
RUN ["yum","install","-y","nginx"]
RUN mkdir -p /var/www/html
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80


cat Dockerfile
# Version: 0.0.1
FROM ooppwwqq0/sa:v2
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-21
RUN mkdir -p /var/www/html
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80

cat Dockerfile
# Version: 0.0.1
FROM ooppwwqq0/usa:v1
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-22
RUN mkdir -p /var/www/html
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
1
2
3
4
5
6
7
docker build -t ooppwwqq0/nginx .

可以查看构建镜像的所有过程,追溯到最开始的镜像
docker history ooppwwqq0/nginx

docker run -d -p 8080:8081 --name website -v $PWD/website:/var/www/html/website ooppwwqq0/unginx nginx
-v 将本地卷挂载到容器中

构建sinatra应用

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
cat Dockerfile 
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-21
RUN apt-get -y update
RUN apt-get -y install ruby ruby-dev build-essential redis-tools
RUN gem source -r https://rubygems.org/
RUN gem source -a https://ruby.taobao.org/
RUN gem install --no-rdoc --no-ri sinatra json redis

RUN mkdir -p /opt/webapp
EXPOSE 4567
CMD ["/opt/webapp/bin/webapp"]

wget --cut-dirs=3 -nH -r --no-parent http://dockerbook.com/code/5/sinatra/webapp

docker run -d -p 4567:4567 --name sinaapp -v $PWD/webapp:/opt/webapp ooppwwqq0/sinatra

curl -i -H 'Accept: application/json' "http://127.0.0.1:4567/jsons/?name=Foo&status=Bar"
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 29
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
Date: Thu, 23 Jun 2016 05:23:04 GMT
Connection: Keep-Alive

{"name":"Foo","status":"Bar"}

构建redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat Dockerfile 
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-21
RUN apt-get -y update
RUN apt-get -y install redis-server redis-tools

EXPOSE 6379

ENTRYPOINT ["/usr/bin/redis-server"]
CMD []

docker run -d -p 6379:6379 --name uredis ooppwwqq0/uredis
apt install redis-tools
redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379>

连接到redis容器

1
2
3
4
5
6
7
ip a show docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ad:ff:f8:e1 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:adff:feff:f8e1/64 scope link
valid_lft forever preferred_lft forever
1
docker inspect -f '{{ .andSettings.IPAddress }}' uredis

以前docker的容器每次重启ip都会改变,现在好像不变了,不过使用ip来连接还是挺low的,幸运的是,docker提供了一种叫做link的功能。可以使用link的方式连接docker容器

1
2
3
docker run -d --name uredis ooppwwqq0/uredis

docker run -p 4567 --name webapp --link uredis:db -it -v $PWD/webapp:/opt/webapp ooppwwqq0/sinatra /bin/bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat /etc/hosts
172.17.0.4 db afd4353f7aaa uredis
172.17.0.5 71de6997261c


curl -i -H 'Accept: application/json' -d 'name=Foo&statu/json/ http://127.0.0.1:32769/
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 29
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
Date: Fri, 24 Jun 2016 03:55:43 GMT
Connection: Keep-Alive

{"name":"Foo","status":"Bar"}

持续集成

构建jenkins

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
cat Dockerfile 
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-24
RUN apt-get -y update
RUN apt-get install -qqy curl apt-transport-https
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
RUN echo deb https://apt.dockerproject.org/repo ubuntu-trusty main > /etc/apt/sources.list.d/docker.list
RUN apt-get -y update
RUN apt-get install -qqy iptables ca-certificates default-jdk git-core docker
#RUN apt-get install -qqy iptables ca-certificates openjdk-7-jdk git-core docker-engine

ENV JENKINS_HOME /opt/jenkins/data
ENV JENKINS_MIRROR http://mirrors.jenkins-ci.org

RUN mkdir -p $JENKINS_HOME/plugins
RUN curl -sf -o /opt/jenkins/jenkins.war -L $JENKINS_MIRROR/war-stable/latest/jenkins.war

RUN for plugin in chucknorris greenballs scm-api git-client git ws-cleanup ;\
do curl -sf -o $JENKINS_HOME/plugins/${plugin}.hpi \
-L $JENKINS_MIRROR/plugins/${plugin}/latest/${plugin}.hpi ; done

ADD ./dockerjenkins.sh /usr/local/bin/dockerjenkins.sh
RUN chmod +x /usr/local/bin/dockerjenkins.sh

VOLUME /var/lib/docker

EXPOSE 8080

ENTRYPOINT [ "/usr/local/bin/dockerjenkins.sh" ]
1
2
3
4
5
6
docker run -p 8080:8080 --name jenkins --privileged -d ooppwwqq0/udockerjenkins

--privileged 用这个标志启动容器,可以启动docker的特权模式,这种模式允许我们以其宿主机具有的(几乎)所有能力来运行容器,包括一些内核和设备访问,我们就是用这种方式来在docker里面运行docker


--cidfile=/tmp/c.txt 启动的时候加这个参数,会将docker返回的容器id保存在文件中

构建jekyll博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat Dockerfile 
# Version: 0.0.1
FROM ooppwwqq0/sinatra
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-27
RUN apt-get -y update
RUN apt-get -y install make nodejs ruby ruby-dev gcc
RUN gem source -r https://rubygems.org/
RUN gem source -a https://ruby.taobao.org/
RUN gem install --no-rdoc --no-ri jekyll

VOLUME /data/
VOLUME /var/www/html
WORKDIR /data

ENTRYPOINT ["jekyll", "build", "--destination=/var/www/html"]


docker build -t ooppwwqq0/ujekyll .
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
 cat Dockerfile 
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-27
RUN apt-get -y update
RUN apt-get -y install apache2

VOLUME ["/var/www/html"]
WORKDIR /var/www/html

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /data/logs/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2

RUN mkdir -p $APACHE_RUN_DIR $APACHE_LOCK_DIR $ APACHE_LOG_DIR

EXPOSE 80

ENTRYPOINT ["/usr/sbin/apache2"]
CMD ["-D", "FOREGROUND"]

docker build -t ooppwwqq0/uapache2 .
1
2
3
4
5
6
7
8
9
git clone https://github.com/jamtur01/james_blog.git

docker run -v $PWD/james_blog:/data --name james_blog ooppwwqq0/ujekyll

docker run -d -P --volumes-from james_blog ooppwwqq0/uapache2

我们首先使用jekyll镜像编译好了需要的网站源代码,并且放在了/var/www/html下,然后apache2 容器启动时直接使用--volumes-from选项把jekyll启动的容器中所有的卷加入到新的容器中,这样,即使jekyll容器并没有启动,apache容器也可以访问到这些卷,但是使用rm删除容器,会把卷同时删掉,那么这个卷就不存在了。

每次更新文件之后,start一下jekyll镜像就可以更新代码

备份jekyll卷

1
docker run --rm --volumes-from james_blog -v $PWD:/backup ubuntu tar cvf /backup/james_blog_backup.tar /var/www/html

使用docker构建一个java应用

  • 一个镜像用来通过制定url获取war包,并且放在指定卷中
  • 另一个镜像运行tomcat运行下载的war文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cat Dockerfile 
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-27
RUN apt-get -y update
RUN apt-get -y install wget

VOLUME ["/var/lib/tomcat7/webapps/"]
WORKDIR /var/lib/tomcat7/webapps/

ENTRYPOINT ["wget"]
CMD ["-?"]

docker build -t ooppwwqq0/ufetcher .


docker run -it --name sample ooppwwqq0/ufetcher https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat Dockerfile 
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER ooppwwqq0 "emo_ooppwwqq0@163.com"
ENV REFRESHED_AT 2016-06-27
RUN apt-get -y update
RUN apt-get -y install tomcat7 default-jdk

ENV CATALINA_HOME /usr/share/tomcat7
ENV CATALINA_BASE /var/lib/tomcat7
ENV CATALINA_PID /var/run/tomcat7.pid
ENV CATALINA_SH /usr/share/tomcat7/bin/catalina.sh
ENV CATALINA_TMPDIR /tmp/tomcat7-tomcat7-tmp

RUN mkdir -p $CATALINA_TMPDIR

VOLUME ["/var/lib/tomcat7/webapps/"]

EXPOSE 8080

ENTRYPOINT ["/usr/share/tomcat7/bin/catalina.sh", "run"]

docker build -t ooppwwqq0/utomcat7 .

多容器的应用栈

  • 一个nodejs容器,用来运行node应用;
  • 一个redis主容器,用来保存和集群化应用状态;
  • 两个redis备份容器;
  • 一个日志容器,用来捕捉应用日志。