Docker

  1. 1. Docker简介
    1. 1.1. 什么是容器
      1. 1.1.1. Docker依赖的Linux内核特性
        1. 1.1.1.1. Docker容器的能力
      2. 1.1.2. 什么是Docker
      3. 1.1.3. Docker的目标
      4. 1.1.4. Docker的使用场景
    2. 1.2. Docker的基本组成
  2. 2. Docker的安装和配置
    1. 2.1. Docker在Ubuntu中的安装
    2. 2.2. Docker在Windows中的安装
    3. 2.3. Docker在OS X中的安装
  3. 3. Docker容器
    1. 3.1. 容器的基本操作
    2. 3.2. 守护式容器
    3. 3.3. 在容器中部署静态网站
      1. 3.3.1. 1. 设置容器的端口映射
      2. 3.3.2. 2. Nginx部署流程
  4. 4. Docker镜像
    1. 4.1. 查看和删除镜像
      1. 4.1.1. 镜像的存储地址
      2. 4.1.2. 列出镜像
      3. 4.1.3. 镜像标签和仓库
      4. 4.1.4. 查看镜像
      5. 4.1.5. 删除镜像
    2. 4.2. 获取和推送镜像
      1. 4.2.1. 查找镜像
      2. 4.2.2. 拉取镜像
      3. 4.2.3. 推送镜像
    3. 4.3. 构建镜像
      1. 4.3.1. 使用commit构建镜像
      2. 4.3.2. 使用dockerfile构建镜像
  5. 5. Docker的CS模式
    1. 5.1. Remote API
    2. 5.2. 连接方式
  6. 6. Docker守护进程的配置和操作
    1. 6.1. 查看docker守护进程的运行状态
    2. 6.2. 启动,停止,重启docker守护进程
    3. 6.3. docker的启动选项
    4. 6.4. 修改docker守护进程的启动配置
  7. 7. Dockerfile
    1. 7.1. FROM指令
    2. 7.2. MAINTAINER指令
    3. 7.3. RUN指令
    4. 7.4. EXPOSE指令
    5. 7.5. CMD指令
    6. 7.6. ENTRYPOINT指令
    7. 7.7. ADD指令
    8. 7.8. COPY指令
    9. 7.9. VOLUME指令
    10. 7.10. WORKDIR指令
    11. 7.11. ENV指令
    12. 7.12. USER指令
    13. 7.13. ONBUILD指令
    14. 7.14. Dockerfile构建过程
  8. 8. Docker容器的网络连接
    1. 8.1. Docker容器的网络基础
      1. 8.1.1. docker0
      2. 8.1.2. 自定义docker0
      3. 8.1.3. 自定义虚拟网桥
    2. 8.2. Docker容器的互联
    3. 8.3. Docker容器与外部网络的连接
      1. 8.3.1. ip_forward
      2. 8.3.2. iptables
  9. 9. Docker容器的数据管理简介
    1. 9.1. Docker容器的数据卷
    2. 9.2. Docker的数据卷容器
    3. 9.3. Docker数据卷的备份与还原
  10. 10. Docker容器跨主机网络访问
    1. 10.1. 使用网桥实现跨主机容器连接
    2. 10.2. 使用Open vSwitch实现跨主机容器连接
    3. 10.3. 使用weave实现跨主机容器连接
  11. 11. Docker Compose
    1. 11.1. docker-compose安装
    2. 11.2. docker-compose命令
    3. 11.3. 网桥

Docker provides a way to run applications securely isolated in a container, packaged with all its dependencies and libraries.

Docker简介

什么是容器

  • 一种虚拟化的方案
  • 操作系统级别的虚拟化
  • 只能运行相同或相似内核的操作系统
  • 依赖于Linux内核特性: Namespace和Cgroups(Control Group)

Docker依赖的Linux内核特性

  • Namespace 命名空间
    • 编程语言
      • 封装 \rightarrow 代码隔离
    • 操作系统
      • 系统资源的隔离
      • 进程, 网络, 文件系统
  • Control groups 控制组
    • 用来分配资源
Docker容器的能力
  • 文件系统隔离: 每个容器都有自己的root文件系统
  • 进程的隔离: 每个容器都运行在自己的进程环境
  • 网络的隔离: 容器间的虚拟网络接口和IP地址都是分开的
  • 资源隔离和分组: 使用cgroups将CPU和内存之类的资源独立分配给每个Docker容器

什么是Docker

  • 将应用程序自动部署到容器的开源引擎

Docker的目标

  • 提供简单轻量的建模方式
  • 指责的逻辑分离
  • 快速高效的开发生命周期
  • 鼓励使用面向服务的架构

Docker的使用场景

  1. 使用Docker容器开发, 测试, 部署服务
  2. 创建隔离的运行环境
  3. 搭建测试环境
  4. 构建多用户的平台即服务(PaaS)基础设施
  5. 提供软件即服务(SaaS)应用程序
  6. 高性能, 超大规模的宿主机部署

Docker的基本组成

  • Docker Client 客户端
  • Docker Daemon 守护进程
  • Docker Image 镜像
  • Docker Container 容器
  • Docker Registry 仓库

Docker的安装和配置

Docker在Ubuntu中的安装

安装前检查:

  1. 内核版本
1
uname -a
  1. 检查Device Mapper
1
ls -l /sys/class/misc/device-mapper

Ubuntu中安装Docker的方式

  1. 安装Ubuntu维护的版本
1
2
sudo apt-get install docker.io
source /etc/bash_completion.d/docker.io
  1. 安装Docker维护的版本
1
2
sudo apt-get install -y curl
curl -sSL http://get.docker.com/ubuntu/ | sudo sh

使用非root用户:

1
2
3
sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo service docker restart

Docker在Windows中的安装

Docker在OS X中的安装

Docker容器

容器的基本操作

  • 启动容器:
1
docker run IMAGE [COMMAND] [ARG...]

run 在新容器中执行命令 eg.docker run ubuntu echo ‘Hello World’

  • 启动交互式容器
1
2
3
4
5
docker run -i -t IMAGE /bin/bash

-i --interactive=true | false 默认是false 用来告诉守护进程为容器始终打开标准输入
-t --tty=true | false 默认是false 告诉docker要为创建的容器分配一个为tty终端,这样新创建的容器才能提供一个交互式的shell
-d 后台运行容器,并返回容器ID;
  • 查看容器:
1
2
docker ps [-a] [-l]
docker inspect [CONTAINER ID]
  • 自定义容器名:
1
docker run --name=自定义名 -i -t IMAGE /bin/bash
  • 重新启动停止的容器:
1
docker start [-i] 容器名
  • 删除停止的容器:
1
docker rm 容器名

守护式容器

  • 什么是守护式容器

    • 能够长期运行
    • 没有交互式会话
    • 适合运行应用程序和服务
  • 以守护形式运行容器:(将一个交互式的容器转到后台)

1
2
docker run -i -t IMAGE /bin/bash
Ctrl+P Ctrl+Q
  • 附加到运行中的容器:
1
docker attach 容器名
  • 启动守护式容器:
1
docker run -d 镜像名 [COMMAND] [ARG...]

eg. docker run --name dc1 -d ubuntu /bin/sh -c “while true; do echo hello world; sleep 1; done”

  • 查看容器日志:
1
2
3
4
5
docker logs [-f] [-t] [--tail] 容器名

-f --follow=true | false 默认为false 一直跟踪日志的变化,并返回结果
-t --timestamps=true | false 默认为false 返回的结果上加上时间戳
--tail "all" 选择返回结尾处多少数量的日志
  • 查看容器内进程:
1
docker top 容器名
  • 在运行中的容器内启动新进程:
1
docker exec [-d] [-i] [-t] 容器名 [COMMAND] [ARG...]

eg. docker exec -i -t dc1 /bin/bash

  • 停止守护式容器:
1
2
docker stop 容器名
docker kill 容器名

stop: 发送一个信号给容器,等待容器的停止
kill: 直接停止容器

在容器中部署静态网站

由于网站服务通常是通过80端口服务的, 为了访问容器的80端口, 需要在运行容器时设置容器的端口映射

1. 设置容器的端口映射

1
2
3
4
5
6
7
8
9
10
11
12
13
run [-P] [-p]

# containerPort
docker run -p 80 -i -t ubuntu /bin/bash

# hostPort:containerPort
docker run -p 8080:80 -i -t ubuntu /bin/bash

# ip:containerPort
docker run -p 0.0.0.0:80 -i -t ubuntu /bin/bash

# ip:hostPort:containerPort
docker run -p 0.0.0.0:8080:80 -i -t ubuntu /bin/bash

2. Nginx部署流程

  • 创建映射80端口交互式容器
  • 安装Nginx
  • 安装文本编辑器vim
  • 创建静态页面
  • 修改Nginx配置文件
  • 运行Nginx
  • 验证网站访问
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
# 运行带端口映射的容器
docker run -p 80 --name web -i -t ubuntu /bin/bash

# 进入容器中后安装Nginx
apt-get install -y nginx

# 安装vim
apt-get install -y vim

# 创建运行在Nginx中的网站
# 创建一个存放网站的目录
mkdir -p /var/www/html

# 创建静态页面
cd /var/www/html
vim index.html

# 修改配置文件
vim /etc/nginx/sites-enabled/default
# 将root后面改为刚才创建的静态网站的位置 /var/www/html 保存并退出

# 切换至根目录 运行Nginx
cd /
nginx

# 可以在容器中查看当前进程
ps -ef

# Crtl P+Q退出 这样可以使容器一直在后台运行

# 可以使用docker的port命令查看端口映射情况
docker port web

# 可以使用docker的top命令查看容器中进程情况
docker top web

# 验证网站是否可以访问
# 使用curl命令 这里要使用刚才查到的端口(eg.49167) 成功的话会返回刚才编辑的html页面
curl http://127.0.0.1:49167
# 也可以使用容器的ip地址访问
# 使用docker inspect命令查看
docker inspect web

# 这里就不需要特别指定端口号了,因为默认的80端口就可以访问
curl http://172.17.0.32

# 注意:当我们停止(docker stop web)并重新启动(docker start -i web)时原来分配的ip地址和端口映射都会改变

Docker镜像

Docker镜像是一种使用联合加载(union mount)技术实现的层叠的只读文件系统,它是容器构建的基石。

查看和删除镜像

镜像的存储地址

docker info指令查看

1
2
3
4
5
6
sudo ls -l /var/snap/docker/common/var-lib-docker/aufs

total 12
drwx------ 23 root root 4096 Jan 16 20:06 diff
drwx------ 2 root root 4096 Jan 16 20:06 layers
drwx------ 23 root root 4096 Jan 16 20:06 mnt

列出镜像

1
2
3
4
5
6
7
8
9
docker images [OPTIONS] [REPOSITORY]

REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine a624d888d69f 4 months ago 21.5MB
dperson/samba latest 7be9f2690bc1 4 months ago 49.7MB
leonismoe/frpc latest 4fd07209a346 7 months ago 10.7MB
nginx latest 5a3221f0137b 7 months ago 126MB
ubuntu latest a2a15febcdf3 7 months ago 64.2MB
portainer/portainer latest 2b4ddf654e1c 8 months ago 77.7MB
  • -a
  • -f
  • -no-trunc
  • -q 只返回id

镜像标签和仓库

  • REPOSITORY 仓库
    • 是一系列镜像的集合
  • REGISTRY 仓库
    • 这个是之前提到过的docker组建中的仓库,它是提供的docker镜像的存储服务,从这里看出REGISTRY仓库包含了很多REPOSITORY的仓库,而REPOSITORY的仓库中包含了一个个独立的镜像
  • TAG 镜像的标签
    • REPOSITORY + TAG 构成一个完整的镜像名,这个镜像名对应一个完整的ID
    • ubuntu:14.04
    • ubuntu:latest

同一个仓库的不同标签可能对应相同的ID,也就是根据我们的需求打上不同的标签

1
2
3
4
5
# 显示完整的镜像ID
docker images --no-trunc

# 显示所有的镜像
docker images -a

查看镜像

docker inspect : 获取容器/镜像的元数据

1
2
3
4
5
docker inspect [OPTIONS] NAME|ID [NAME|ID...]

-f :指定返回值的模板文件。
-s :显示总的文件大小。
--type :为指定类型返回JSON。

删除镜像

1
2
3
4
docker rmi [OPTIONS] IMAGE [IMAGE...]

-f :强制删除;
--no-prune :不移除该镜像的过程镜像,默认移除;

获取和推送镜像

查找镜像

  • Docker Hub

  • docker search [OPTION] TERM

    • -=automated=flase
    • –no-trunc=false
    • -s
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
▶ docker search ubuntu

NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 10699 [OK]
dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface … 410 [OK]
rastasheep/ubuntu-sshd Dockerized SSH service, built on top of offi… 245 [OK]
consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC session… 212 [OK]
ubuntu-upstart Upstart is an event-based replacement for th… 107 [OK]
neurodebian NeuroDebian provides neuroscience research s… 67 [OK]
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5 ubuntu-16-nginx-php-phpmyadmin-mysql-5 50 [OK]
ubuntu-debootstrap debootstrap --variant=minbase --components=m… 43 [OK]
nuagebec/ubuntu Simple always updated Ubuntu docker images w… 24 [OK]
i386/ubuntu Ubuntu is a Debian-based Linux operating sys… 19
1and1internet/ubuntu-16-apache-php-5.6 ubuntu-16-apache-php-5.6 14 [OK]
1and1internet/ubuntu-16-apache-php-7.0 ubuntu-16-apache-php-7.0 13 [OK]
ppc64le/ubuntu Ubuntu is a Debian-based Linux operating sys… 13
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mariadb-10 ubuntu-16-nginx-php-phpmyadmin-mariadb-10 11 [OK]
1and1internet/ubuntu-16-nginx-php-5.6 ubuntu-16-nginx-php-5.6 8 [OK]
1and1internet/ubuntu-16-nginx-php-5.6-wordpress-4 ubuntu-16-nginx-php-5.6-wordpress-4 7 [OK]
1and1internet/ubuntu-16-apache-php-7.1 ubuntu-16-apache-php-7.1 6 [OK]
darksheer/ubuntu Base Ubuntu Image -- Updated hourly 5 [OK]
pivotaldata/ubuntu A quick freshening-up of the base Ubuntu doc… 4
1and1internet/ubuntu-16-nginx-php-7.0 ubuntu-16-nginx-php-7.0 4 [OK]
pivotaldata/ubuntu16.04-build Ubuntu 16.04 image for GPDB compilation 2
smartentry/ubuntu ubuntu with smartentry 1 [OK]
1and1internet/ubuntu-16-php-7.1 ubuntu-16-php-7.1 1 [OK]
pivotaldata/ubuntu-gpdb-dev Ubuntu images for GPDB development 1
1and1internet/ubuntu-16-sshd ubuntu-16-sshd 1 [OK]

拉取镜像

  • docker pull [OPTIONS] NAME [:TAG]
1
docker pull ubuntu:14.04

推送镜像

  • docker push NAME[:TAG]

可在docker hub上访问上传的镜像

构建镜像

  • 保存对容器的修改,并再次修改
  • 自定义镜像的能力
  • 以软件的形式打包并分发服务及其运行环境

也就是说,我们可以通过自定义的镜像,将服务与运行的系统及其软件运行环境通过镜像打包在一起,那么在运行其他docker守护进程的主机上都可以以这个镜像运行容器从而提供服务。

  • docker commit 通过容器构建
  • docker build 通过dockerfile文件构建

使用commit构建镜像

  • docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
    • -a 作者
    • -m 作者的信息
    • -p 由于执行commit命令时会将正在执行的容器暂停,-p可以指示不暂停正在执行的容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 启动容器
docker run -it -p 80 --name commit_test ubuntu /bin/bash

# 对容器做出修改
apt-get update
apt-get nginx
exit

# 提交为镜像 docker commit -a '作者信息' -m '镜像信息' 容器名 仓库名/镜像名
docker commit -a 'tyokyo320' -m 'nginx' commit_test tyokyo320/commit_test1

# 返回的id即为镜像的id

# 使用这个镜像来运行容器,在容器启动时运行nginx命令
# 这里给了参数来告诉nginx以前台模式运行,否则运行结束后那么容器也会停止
docker run -d --name nginx_web1 -p 80 tyokyo320/commit_test1 nginx -g "daemon off;"

使用dockerfile构建镜像

  1. 创建dockerfile
  2. 使用docker build命令

eg.dockerfile

1
2
3
4
5
6
7
# First Dockerfile

FROM ubuntu:14.04
MAINTAINER xxx "xxxx@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
EXPOSE 80
  • docker build [OPTIONS] PATH | URL | -
    • -f :指定要使用的Dockerfile路径
    • –tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签
1
2
3
4
5
# docker build -t='镜像名字' dockerfile地址(这里就是当前目录)
docker build -t='tyokyo320/df_test1' .

# 运行这个镜像
docker run -d --name nginx_web1 -p 80 tyokyo320/df_test1 nginx -g "daemon off;"

Docker的CS模式

前面提到过,docker是以客户端和守护进程的方式运行,在客户端中运行各种命令,这些命令会传递给在docker的宿主机上运行的docker的守护进程,而docker的守护进程是负责实现docker的各种功能

上面这幅图显示,docker的客户端运行在宿主机上,也就是C/S架构的server端,守护进程会在启动后在后台运行,负责实现docker的各种功能,而docker的使用者并不会直接与守护进程进行交互,而是通过docker的客户端。

docker的命令行接口是docker最主要的客户端接口,docker也提供了另外的与守护进程通信的方式,这就是remote API

Remote API

  • RESTful 风格API
  • STDIN,STDOUT,STDERR

这幅图可以看出,通过Remote API的形式来实现docker的C/S架构模式,用户通过与自定义的程序交互,这个程序通过调用Remote API与docker守护进程协作

连接方式

docker的客户端与守护进程的连接:socket

  • unix://var/run/docker.sock
  • tcp://host:post
  • fd://socketfd

docker的客户端与docker的服务器端通过socket进行连接,这种连接本身也就意味着docker的客户端与服务端既可以在同一台机器上运行也可以在不同的机器上运行,也就是docker的客户端可以通过远程的方式来访问docker的服务端

Docker守护进程的配置和操作

查看docker守护进程的运行状态

1
2
3
ps -ef | grep docker

sudo status docker

启动,停止,重启docker守护进程

使用service命令管理

1
2
3
4
5
sudo service docker start

sudo service docker stop

sudo service docker restart

docker的启动选项

  • docker -d [OPTIONS]

OPTIONS中,有运行相关的,有docker服务器连接相关的,有RemoteAPI相关的,有存储相关的,有Registry相关的,有网络设置相关的(DNS服务器配置以及容器ip的配置)

修改docker守护进程的启动配置

这里必须要说的是docker的启动配置文件:/etc/default/docker,在这个配置文件中,可以设置docker启动时运行的各种选项

Dockerfile

Dockerfile其内部包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建.

Dockerfile结构大致分为四个部分:

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时执行指令

CMD和ENTRYPOINT指令用来指定容器启动时执行的命令,ADD,COPY,VOLUME指令用来设定镜像的目录和文件,WORKDIR,ENV,USER指令用来指定镜像构建及容器运行时的环境设置,还有ONBUILD指令这里一个类似触发器的指令

FROM指令

  • FROM < image >
  • FROM < image >:< tag >
  • 已经存在的镜像
  • 基础镜像
  • 必须是第一条非注释指令

MAINTAINER指令

  • MAINTAINER < name >
  • 指定镜像的作者信息,包含镜像的所有者和联系信息

RUN指令

  • 指定当前镜像中运行的命令
  • RUN < command > (shell模式)
    • /bin/sh -c command
    • eg. RUN echo hello
  • RUN [ “executable”, “param1”, “param2” ] (exec模式)

EXPOSE指令

  • EXPOSE < port > [ < port > … ]
  • 指定运行该容器镜像的容器使用的端口

CMD指令

  • CMD [ “executable”, “param1”, “param2” ] (exec模式)
  • CMD command param1 param2 (shell模式)
  • CMD [ “param1”, “param2” ] (作为ENTRYPOINT指令的默认参数)
  • 用来提供容器运行的默认命令,与RUN类似都是执行一个命令,但是RUN指定的命令是在镜像构建中执行的,而CMD指定的命令是在容器运行时运行的,且当使用docker run命令启动一个容器时,如果指定了容器运行时的命令,那么CMD中指定的指令会被覆盖,也就是说CMD指令用来指定容器的默认行为

ENTRYPOINT指令

  • ENTRYPOINT[ “executable”, “param1”, “param2” ] (exec模式)
  • ENTRYPOINT command param1 param2 (shell模式)
  • 可以使用docker run -entrypoint覆盖(这也是CMD与ENTRYPOINT指令的不同之处)

CMD指令与ENTRYPOINT指令组合使用时,用ENTRYPOINT指定命令,用CMD指定参数即可

1
2
3
4
5
6
7
8
9
# First Dockerfile

FROM ubuntu:14.04
MAINTAINER xxx "xxxx@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["g"]

ADD指令

  • ADD < src >…< dest >
  • ADD “< src >”…“< dest >”
  • ADD和COPY指令非常相似,都是将文件和目录复制到使用dockerfile构建稍微镜像中,都支持2种参数:来源地址和目标地址,文件和目录的来源可以是本地地址,也可以是远程的url,如果是本地地址必须是构建目录中的相对地址,对于远程url,docker不推荐使用,建议使用wget获取文件,而目标路径需要指定镜像中的绝对路径

COPY指令

  • COPY < src >…< dest >
  • COPY “< src >”…“< dest >”
  • ADD和COPY指令不同之处:ADD包含类似tar的解压功能,如果单纯复制文件,docker推荐使用COPY
1
2
3
4
5
6
7
8
9
# First Dockerfile

FROM ubuntu:14.04
MAINTAINER xxx "xxxx@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
COPY index.html /usr/share/nginx/html/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx", "g", "daemon off;"]

VOLUME指令

  • VOLUME [“/data”]
  • VOLUME指令基于镜像创建的容器添加卷

WORKDIR指令

  • WORKDIR /path/to/workdir
  • WORKDIR指令用来从镜像创建一个新容器时,在容器内部设置工作目录,CMD与ENTRYPOINT指定的目录都会在这个目录下执行,也可为后续指令指定工作目录
  • WORKDIR通常会使用绝对路径,如果使用了相对路径,那么工作路径会一直传递下去

ENV指令

  • ENV < key > < value >
  • ENV < key >=< value >…
  • 用来设置环境变量,与WORKDIR指令类似
  • 环境变量的指令也可以作用于构建过程中以及运行过程中同样有效

USER指令

  • USER daemon
  • USER指令用来指定镜像为什么样的用户去运行 eg. USER nginx
  • 也可使用:
    • USER user
    • USER user:group
    • USER user:gid
    • USER uid
    • USER uid:gid
    • USER uid:group
    • 不指定默认root用户

ONBUILD指令

  • ONBUILD [INSTRUCTION]
  • ONBUILD指令为镜像添加触发器,当一个镜像被用于其他镜像的基础镜像时,这个触发器会被执行,当子镜像在构建时会插入触发的指令

Dockerfile构建过程

  • 从基础镜像运行一个容器
  • 执行一条指令,对容器做出修改
  • 执行类似docker commit的操作,提交一个新的镜像层
  • 在基于刚提交的镜像运行一个新容器
  • 执行dockerfile中的下一条指令,直至所有指令执行完毕

docker build命令会删除中间层创建的容器,但是没有删除中间层创建的镜像,也就是说,可以使用docker run命令使用中间层镜像运行一个容器,从而查看每一步构建后镜像的实际状态,使用中间层镜像进行调试的好处就是查找错误

接下来学习构建过程中另一个重要概念:构建缓存

由于每一步的构建过程都会将结果提交成一个镜像,所以docker构建镜像会将之前的镜像看作缓存

但是有些情况下不想使用缓存,比如构建过程中包含apt-get update命令时,我们希望每一次docker都刷新apt-get包的缓存,这样就能得到最新的版本

跳过缓存的指令:

1
docker build --no-cache

查看镜像构建的过程:

1
docker history [image]

Docker容器的网络连接

Docker容器的网络基础

docker0

开始前先用ifconfig指令看一下运行docker守护进程机器上的网络设备:

1
2
3
4
5
6
7
8
9
10
ifconfig

docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:83ff:febd:999f prefixlen 64 scopeid 0x20<link>
ether 02:42:83:bd:99:9f txqueuelen 0 (Ethernet)
RX packets 686194 bytes 270125835 (270.1 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 682000 bytes 280807300 (280.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

系统中存在一个docker0的网络设备,docker守护进程就是通过docker0为docker的容器提供网络连接的各种服务。

docker0实际上就是Linux的虚拟网桥,那什么是网桥呢?

根据OSI七层模型,网桥是数据链路层的一种设备,它用来通过MAC地址来对网络进行划分,并且在不同的网络直接传递数据。

Linux的虚拟网桥有一些不同的特点:

  • 可以设置IP地址
  • 相当于拥有一个隐藏的虚拟网卡

当Linux的虚拟网桥拥有IP后,Linux就可以通过路由表或IP表规则在网络层定位网桥,这相当于拥有一个隐藏的虚拟网卡,而这个网卡的名字就是这个虚拟网桥的名字,也就是刚才看到的docker0

docker0的地址划分:

  • IP:172.17.0.1 子网掩码:255.255.0.0
  • MAC:02:42:ac:11:00:00 到 02:42:ac:11:ff:ff
  • 总共提供了65534个地址

docker守护进程在一个容器启动时,实际上它要创建网络连接的两端:一端是在容器中的网络设备,而另一端是在运行docker守护进程的主机上,打开一个名为veth*的接口,用来实现docker0这个网桥与容器的网络通信

在ubuntu上,首先要安装网桥管理工具:

1
sudo apt-get install bridge-utils

然后查看网桥设备:

1
2
3
4
5
6
sudo brctl show

bridge name bridge id STP enabled interfaces
br-d554e75eb1a1 8000.02426ed768f5 no vethb097592
docker0 8000.024283bd999f no veth9b5deed
vethd8b13a2

这里可以看到有一个docker0的网络设备,interfaces里面的接口就是docker在容器创建时,为容器连接docker0所创建的一个网络接口,同样的ifconfig命令也可以查看这个网络接口:

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
ifconfig

br-d554e75eb1a1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.19.0.1 netmask 255.255.0.0 broadcast 172.19.255.255
inet6 fe80::42:6eff:fed7:68f5 prefixlen 64 scopeid 0x20<link>
ether 02:42:6e:d7:68:f5 txqueuelen 0 (Ethernet)
RX packets 20118 bytes 221557652 (221.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 19556 bytes 2710388 (2.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:83ff:febd:999f prefixlen 64 scopeid 0x20<link>
ether 02:42:83:bd:99:9f txqueuelen 0 (Ethernet)
RX packets 687186 bytes 270181171 (270.1 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 682943 bytes 280874509 (280.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

enp3s0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 1c:69:7a:03:5b:73 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 14642 bytes 1214608 (1.2 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14642 bytes 1214608 (1.2 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

veth9b5deed: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::484a:afff:fe23:d0ba prefixlen 64 scopeid 0x20<link>
ether 4a:4a:af:23:d0:ba txqueuelen 0 (Ethernet)
RX packets 686521 bytes 275482725 (275.4 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 682417 bytes 280606797 (280.6 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

vethb097592: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::5010:75ff:fea9:271f prefixlen 64 scopeid 0x20<link>
ether 52:10:75:a9:27:1f txqueuelen 0 (Ethernet)
RX packets 20118 bytes 221839304 (221.8 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 19944 bytes 2737644 (2.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

vethd8b13a2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::4c43:dbff:fe79:55a8 prefixlen 64 scopeid 0x20<link>
ether 4e:43:db:79:55:a8 txqueuelen 0 (Ethernet)
RX packets 665 bytes 4319050 (4.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5543 bytes 1378560 (1.3 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

wlp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.10.106 netmask 255.255.255.0 broadcast 192.168.10.255
inet6 fe80::d63b:4ff:fee3:2bb4 prefixlen 64 scopeid 0x20<link>
ether d4:3b:04:e3:2b:b4 txqueuelen 1000 (Ethernet)
RX packets 960862 bytes 306802931 (306.8 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 963408 bytes 546365355 (546.3 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

自定义docker0

当docker0所提供的默认ip地址范围不能满足我们期望为容器分配的ip地址时,可以通过修改docker0地址,将它改为我们期望使用的网段:

1
2
3
4
5
6
7
8
# 假设新地址为192.168.200.1
sudo ifconfig docker0 192.168.200.1 netmask 255.255.255.0

# 修改后重启docker服务
docker service docker restart

# 重启后再运行一个容器
docker run -it ubuntu /bin/bash

再查看新容器的ip地址后会看到已经修改为所期望的地址

自定义虚拟网桥

在有些情况下,我们不希望docker默认提供的docker0这个虚拟网桥,我们希望自己建立新的虚拟网桥来给docker使用,这样也是可以实现的,需要以下两个步骤:在系统中建立一个虚拟网桥,然后在docker守护进程的启动配置中添加对新的虚拟网桥使用的定义

添加虚拟网桥:

1
2
sudo brctl addbr br0
sudo ifconfig br0 192.168.100.1 netmask 255.255.255.0

更改docker守护进程的启动配置:

  • /etc/default/docker 中添加DOCKER_OPS值
  • -b=br0
  • 保存退出后重启docker守护进程

最后查看是否成功配置:

1
2
3
4
5
ps -ef | grep docker

# 运行新容器并查看ifconfig
docker run -it ubuntu /bin/bash
ifconfig

Docker容器的互联

  • 允许所有容器互联
  • 拒绝容器间互联
  • 允许特定容器间的连接

Docker容器与外部网络的连接

  • ip_forward
  • iptables
  • 允许端口映射访问
  • 限制ip访问容器

ip_forward

1
2
3
4
--ip-forward=true

# 查看ip_forward的值
sudo sysctl net.ipv4.conf.all.forwarding

ip_forward默认值为true,当使用这个默认值时,docker会在守护进程启动时将系统的ip_forward设置为1,也就是允许流量转发

iptables

iptables是与linux内核集成的包过滤防火墙系统,几乎所有的linux发行版本都会包含iptables的功能

  • 表(table)
  • 链(chain)
  • 规则(rule)
    • ACCEPT, REJECT, DROP

filter表中包含的链:

  • INPUT
  • FORWARD
  • OUTPUT
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
# 查看filter表
sudo iptables -t filter -L -n


Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-USER all -- 0.0.0.0/0 0.0.0.0/0
DOCKER-ISOLATION-STAGE-1 all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
DOCKER all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
DOCKER all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 172.19.0.2 tcp dpt:443
ACCEPT tcp -- 0.0.0.0/0 172.19.0.2 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 172.17.0.3 tcp dpt:9000

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target prot opt source destination
DOCKER-ISOLATION-STAGE-2 all -- 0.0.0.0/0 0.0.0.0/0
DOCKER-ISOLATION-STAGE-2 all -- 0.0.0.0/0 0.0.0.0/0
RETURN all -- 0.0.0.0/0 0.0.0.0/0

Chain DOCKER-ISOLATION-STAGE-2 (2 references)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
DROP all -- 0.0.0.0/0 0.0.0.0/0
RETURN all -- 0.0.0.0/0 0.0.0.0/0

Chain DOCKER-USER (1 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0

Docker容器的数据管理简介

Docker容器的数据卷

Docker的数据卷容器

Docker数据卷的备份与还原

Docker容器跨主机网络访问

使用网桥实现跨主机容器连接

使用Open vSwitch实现跨主机容器连接

使用weave实现跨主机容器连接

Docker Compose

前面我们使用 Docker 的时候,定义 Dockerfile 文件,然后使用 docker build、docker run 等命令操作容器。然而微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而知
使用 Docker Compose 可以轻松、高效的管理容器,它是一个用于定义和运行多容器 Docker 的应用程序工具

docker-compose安装

1
pip3 install docker-compose -U

查看安装是否成功

1
2
3
4
5
6
docker-compose version

docker-compose version 1.25.0, build b42d419
docker-py version: 4.1.0
CPython version: 3.6.9
OpenSSL version: OpenSSL 1.1.1 11 Sep 2018

docker-compose命令

Docker compose的使用非常类似于docker命令的使用,但是需要注意的是大部分的compose命令都需要到docker-compose.yml文件所在的目录下才能执行

  • compose以守护进程模式运行加-d选项
1
docker-compose up -d
  • compose自定义命名运行
1
2
# eg.
docker-compose -p samba -f docker-compose-samba.yml up -d
  • 查看有哪些服务,使用docker-compose ps命令,非常类似于docker的ps命令
1
docker-compose ps
  • 查看compose日志
1
docker-compose logs web
  • 停止compose服务
1
2
docker-compose stop
docker-compose ps

看到服务的状态为Exit退出状态

  • 重启compose服务
1
2
docker-compose restart
docker-compose ps
  • kill compose服务
1
2
docker-compose kill
docker-compose ps
  • 删除compose服务
1
docker-compose rm
  • 停止和删除容器、网络、卷、镜像
1
docker-compose down [options]

选项包括:

1
2
3
–rmi type,删除镜像,类型必须是:all,删除compose文件中定义的所有镜像;local,删除镜像名为空的镜像
-v, –volumes,删除已经在compose文件中定义的和匿名的附在容器上的数据卷
–remove-orphans,删除服务中没有在compose中定义的容器
  • 构建(重新构建)项目中的服务容器
1
docker-compose build [options] [--build-arg key=val...] [SERVICE...]

选项包括:

1
2
3
4
5
6
–compress 通过gzip压缩构建上下环境
–force-rm 删除构建过程中的临时容器
–no-cache 构建镜像过程中不使用缓存
–pull 始终尝试通过拉取操作来获取更新版本的镜像
-m, –memory MEM为构建的容器设置内存大小
–build-arg key=val为服务设置build-time变量

网桥

使用docker-compose会创建一个stack,可以管理多个容器,一个stack下的多个容器互相之间是通过默认网桥连接的,但是如果想跟其他stack中容器连接需要自己新建网桥

1
docker network create name

如图中两个网桥连接下面各个容器