目录
  1. 1. 安装Docker
  2. 2. 基础概念
    1. 2.1. 镜像(image)
    2. 2.2. 容器(container)
    3. 2.3. 仓库(repository)
    4. 2.4. Namespace
    5. 2.5. CGroups
    6. 2.6. AUFS
    7. 2.7. DeviceMapper
      1. 2.7.1. Thin Provisioning
  3. 3. Docker 镜像(images)
    1. 3.1. 获取镜像
    2. 3.2. 删除镜像
    3. 3.3. 修改tag
    4. 3.4. 修改/更新镜像
    5. 3.5. 导出镜像
    6. 3.6. 导入镜像
    7. 3.7. Dockerfile 创建镜像
  4. 4. Docker 容器(container)
    1. 4.1. 创建并启动容器
    2. 4.2. 启动已停止容器
    3. 4.3. 导出容器
    4. 4.4. 导入容器
    5. 4.5. 删除容器
  5. 5. Docker 数据管理
    1. 5.1. 数据卷(Data Volume)
      1. 5.1.1. 创建数据卷(Data Volume)
      2. 5.1.2. 挂载宿主目录作为数据卷(Data Volume)
    2. 5.2. 数据卷容器(Data Volume Container)
      1. 5.2.1. 创建数据卷容器
      2. 5.2.2. 共享数据卷容器的数据卷
      3. 5.2.3. 备份、恢复数据卷
      4. 5.2.4. 删除数据卷
  6. 6. Docker 网络配置
    1. 6.1. 容器互联
    2. 6.2. Docker 网络模式
      1. 6.2.1. host 模式
      2. 6.2.2. container 模式
      3. 6.2.3. none 模式
      4. 6.2.4. bridge 模式
    3. 6.3. 端口映射
      1. 6.3.1. 随机端口映射
      2. 6.3.2. 指定端口映射

安装Docker

  • 系统版本:CentOS 7 64bit
  • 内核版本:3.10.0-229.el7.x86_64
  • Docker版本:docker-1.8.2-10.el7.centos.x86_64

 安装Docker

1
2
3
4
$> yum install docker

$> docker -v
Docker version 1.8.2-el7.centos, build a01dc02/1.8.2

基础概念

镜像(image)

  • 镜像(image)是容器(container)运行时的只读模板,一个镜像(image)由多个只读层(read-only layer)组成。(可借用Photoshop的图层概念方便理解)
  • Docker使用统一文件系统(union file system)将多个只读层(read-only layer)整合成一个独立的文件系统。
  • 镜像(image)是Docker的构造部分。
    镜像只读图
    图片来源

容器(container)

  • Docker利用容器(container)来运行应用,容器(container)包含应用运行时所需的所有环境。
  • 容器(container)是在镜像(image)的基础上创建而来,不同容器(container)间是相互隔离的。
  • 容器(container) = 镜像(image) + 可读写层(read-write layer)
    可读写层位于镜像的上层,是Docker的最上层
  • 容器(container)中应用的进程对文件进行的创建、修改和删除等操作都是作用于可读写层(read-write layer)
  • 容器(container)可运行开始停止移动删除
  • 容器(container)是Docker的运行部分。

仓库(repository)

  • 仓库(repository)为存放镜像(image)的地方。
  • 仓库(repository)分公有仓库私有仓库。目前最大的公有仓库为Docker Hub
  • 仓库(repository)是Docker的分发部分。

Namespace

 Namespace是Linux Kernel提供的一种内核级别的资源隔离机制。Linux的地址空间分为user spacekernel space,每个进程在user space中独立拥有自己的地址空间且进程间互相隔离不可知。当进程需要使用到kernel相关的资源时都是通过调用kernel api进入kernel space使用kernel提供的服务(从用户态切换到内核态)。进程在user space中是相互独立隔离的,但在kernel space则是共享内核资源的,内核中有许多全局共享使用的资源,如IP、路由表、hostname、init进程、PID和GID等等。为了在kernel space中对内核全局资源(IP、PID等)实现隔离,Linux Kernel提供了Namespace机制。
mount namespace是最早出现的namespace,于2002年开始产生,用于隔离文件系统相关资源。随着container的产生与发展,截止kernel 3.8已存在6个不同类型的namespace,用于隔离不同的内核全局资源。

  • UTS Namespace
     UTS Namespace(UNIX Time-sharing System),用于隔离hostname和domain name。Docker容器拥有独立的UTS Namespace,默认使用CONTAINER ID作为hostname。
  • Mount Namespace
     Mount Namespace通过隔离文件系统挂载点实现隔离文件系统,不同Mount Namespace中的文件结构发生变化互不影响。在创建Mount Namespace时会将当前文件结构复制给新的Mount Namespace,新的Mount Namespace中的所有mount操作仅对此Mount Namespace起作用。
  • IPC Namespace
     IPC Namespace(Inter-Process Communication),IPC是Linux进程间通信的一种方式,IPC有共享内存、命名管道等方法实现进程间的相互通信。隔离IPC后,只有在同一个IPC Namespace下的进程才能直接通信。
  • PID Namespace
     PID Namespace,主要就用于隔离PID。每个PID Namespace的第一个进程为PID=1,功能和init进程一样,比如接管孤儿进程等。
     Namespace允许嵌套,每个Namespace只能影响自身Namespace和子Namespace。
  • Network Namespace
     Network Namespace,用于网络资源的隔离,如:网络设备、IP、路由表、iptables和端口(socket)等等。
  • User Namespace
     User Namespace,用于隔离UID、GID和秘钥等资源。

CGroups

 CGroups是Linux Kernel提供的一种限制、记录资源的机制,所限制的资源包括CPU、Memory、IO等等。
 CGroups通过VFS和上层进行交互,CGroups自定义伪文件系统并定义用于限制各资源的文件。CGroups通过挂载伪文件系统,设置、读取用于限制各资源的文件来限制任务对资源的使用。
 CGroups提供4个主要功能:

  • Resource Limitation(资源限制):例如限制某程序最多能使用的内存空间、只能使用CPU的哪些核心等等。
  • Prioritization(优先级分配):设置优先级,优先级越高能获得越多的资源。
  • Accounting(资源统计):统计资源使用量,主要目的用于计费。
  • Control(进程控制):能对进程组执行挂起、恢复等操作。

 CGroups基础概念:

  • task(任务):表示一个系统进程。每个子系统目录下会有tasks文件(例如memory子系统:/sys/fs/cgroup/memory/tasks),文件内容为限制的进程PID。
  • control group(控制组):CGroups对资源的限制以control group(控制组)为单位进行。一个任务加入某control group,表示任务需要按照此control group的限制规则来使用资源。
  • subsystem(子系统):subsystem(子系统)既资源控制器。不同subsystem(子系统)对不同资源进行限制,目前CGroups有以下subsystem(子系统)/sys/fs/cgroup/
    • blkio:限制块设备(磁盘、SSD、光盘)的IO。
    • cpu:控制task(任务)对CPU的使用。
    • cpuacct:自动生成task(任务)使用cpu的报告。
    • cpuset:为task(任务)分配独立cpu(多核)和内存。
    • devices:控制task(任务)是否允许访问设备。
    • memory:控制task(任务)能使用多少内存并自动生成使用报告。
    • freezer:挂起或恢复task(任务)
    • net_cls:使用classid标记网络数据包
    • hugetlb:对HugeTLB系统进行限制
    • perf_event:运行task(任务)进行统一性能测试
  • hierarchy(层级树):hierarchy由control group以树状目录结构,每个hierarchy通过绑定对应的subsystem进行资源调度。一个系统可存在多个hierarchy。

 关系图如下
  整个灰色框是一个hierarchy
  /cpu_mem_cg包含cpumemory的两个subsystem(表明一个hierarchy可包含多个subsystem)
  /cg1/cg2是不同的control group
  /cg1/cg2目录下会有一个tasks文件,里面存放属于此control grouptask(tasks文件内容为PID)


CGroups-relationships
图片来源

AUFS

 上面在镜像(image)中提到Docker使用统一文件系统(union file system)将多个只读层(read-only layer)整合成独立的文件系统。更加具体来说Docker是使用一种名为AUFS(Advance union file system)的union file system。UFS有很多种,比如:aufs、btrfs、vfs和devicemapper等等。简单而言,UFS就是将不同路径的目录联合挂载到同一个目录下。
AUFS特性:

  • 联合
    可将多个目录联合挂载到同一个目录下。只显示联合目录内容并不改变源目录。
    mount挂载时,越写在前面的目录优先级越高(若多目录中存在相同名称的文件则挂载优先级高目录下的文件)。默认第一个目录权限为rw,之后的目录权限都为ro
  • branch
    各个需要被联合(union)的子目录,Docker中也可理解为层(layer)。
  • copy on write
    若需要对联合目录下的内容做修改时,查找已union的branch中是否存在此文件,若存在则选择可写(rw)且优先级最高的branch并将文件copy到此branch后再修改。
  • whiteout
    用于隐藏下层branch文件。在上层目录创建.wh.,可隐藏下层的文件。

 通过具体实例了解AUFS
 由于CentOS 7默认并不支持AUFS而且要安装也比较麻烦(CentOS系列实现分层镜像用的是DeviceMapper技术,Ubuntu使用AUFS实现),所以实验环境在Ubuntu 14.04上进行,Ubuntu默认没安装AUFS,需要先安装

1
$> sudo apt-get install aufs-tools

 先创建4个目录:ro_aro_brw_cunion。创建2个文件:ro_a/a.txtro_b/b.txt

1
2
3
4
5
6
7
8
9
$> tree
.
├── ro_a
│   └── a.txt
├── ro_b
│   └── b.txt
├── rw_c
└── union
4 directories, 2 files

 将目录rw_cro_aro_b union mount到union目录。第一个branch为rw_c(可读写),第二、三分别为ro_aro_b(只读)
 成功union mount后在union目录可看到其余目录的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
$> sudo mount -t aufs -o br=rw_c=rw:ro_a=ro:ro_b=ro none union

$> tree
.
├── ro_a
│   └── a.txt
├── ro_b
│   └── b.txt
├── rw_c
└── union
├── a.txt
└── b.txt
4 directories, 4 files

 对union mount后的文件union/b.txt进行修改。AUFS会查找优先级高且可读写的branch进行操作(rw_c),而且由于copy on write特性会将源文件ro_b/b.txt文件copy到rw_c目录下再做修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$> echo 'aufs test' >> union/b.txt

$> tree
.
├── ro_a
│   └── a.txt
├── ro_b
│   └── b.txt
├── rw_c
│   └── b.txt
└── union
├── a.txt
└── b.txt
4 directories, 5 files

#源branch保持不变
$> cat ro_b/b.txt
ro_b b.txt

#复制ro_b/b.txt到rw_c/b.txt并修改
$> cat rw_c/b.txt
ro_b b.txt
aufs test

 在rw_c目录创建.wh.a.txt文件用于屏蔽ro_a/a.txt
 源目录文件ro_a/a.txt并不会受到任何影响,但在union mount的目录union下会无法看见union/a.txt文件

1
2
3
4
5
6
7
8
9
10
11
12
$> touch rw_c/.wh.a.txt
$> tree
.
├── ro_a
│   └── a.txt
├── ro_b
│   └── b.txt
├── rw_c
│   └── b.txt
└── union
└── b.txt
4 directories, 4 files

DeviceMapper

 Docker最开始是使用AUFS实现分层镜像,但由于AUFS并没有被接纳入Linux内核主干(被linus拒绝接纳多次),仅有Ubuntu对AUFS支持导致兼容性差。对于非Ubuntu的系统为了解决此问题,使用了DeviceMapper代替AUFS实现分层镜像。
 DeviceMapper有三个重要的基础概念:Mapped Device——>Mapping Table——>Target Device

  • Mapped Device
    映射出的逻辑设备。Mapped Device通过Mapping Table中的映射关系和Target Device建立映射。
  • Mapping Table
    保存Mapped Device逻辑地址的起始及范围、Target Device物理设备的地址偏移量及类型等信息。
  • Target Device
    底层设备。Target Device可以是实际的物理块设备,也可以是映射后的Mapped Device设备。
    DeviceMapper在内核中通过模块化的 Target Driver 插件实现对 IO 请求的过滤或者重新定向等工作,当前已经实现的插件包括软Raid、加密、多路径、镜像、快照等。其中Thin Provisioning Snapshot是Docker使用的重要模块。

Thin Provisioning

 Docker使用Thin ProvisioningSnapshot技术实现分层镜像,从而解决非Ubuntu系列Linux不原生支持AUFS的问题。
 由于DeviceMapperThin Provisioning Snapshot挺复杂且还处于实验阶段,待我再研究清楚后补上。可参考此篇文章做详细了解。

Docker 镜像(images)

 镜像(image)是Docker的重要构成部分,Docker运行容器(container)时需要本地存在相应的镜像(image)。镜像(image)可自己制作,也可从仓库(repository)中下载。

获取镜像

 从Docker Hub上获取CentOS 7的镜像

1
2
3
4
5
6
7
8
9
# 启动Docker进程
$> systemctl start docker.service / service docker start

# 查看公有仓库中的镜像
$> docker search centos / docker search ubuntu

# 下载镜像
$> docker pull docker.io/centos
$> docker pull ubuntu

删除镜像

1
2
3
4
5
6
7
8
# 查看镜像
$> docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker.io/ubuntu latest af88597ec24b 3 days ago 187.9 MB
docker.io/centos latest 60e65a8e4030 2 weeks ago 196.6 MB

# 根据镜像ID删除镜像
$> docker rmi af88597ec24b

修改tag

1
2
3
4
5
6
7
$> docker tag af88597ec24b ubuntu:14.04

$> docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker.io/ubuntu latest af88597ec24b 3 days ago 187.9 MB
docker.io/centos latest 60e65a8e4030 2 weeks ago 196.6 MB
ubuntu 14.04 af88597ec24b 3 days ago 187.9 MB

修改/更新镜像

 在ubuntu14.04镜像上安装vim

  • 启动容器(container)

    1
    $> docker run -ti ubuntu:14.04
  • 安装vim
    48febfe7fbd7容器(container)ID,之后commit更新需要用到

    1
    root@48febfe7fbd7:/# apt-get install vim
  • 使用commit更新镜像

    1
    2
    $> docker commit -m 'install vim' -a 'mogl' 48febfe7fbd7 ubuntu:14.04.vim
    eb39a2d496eda77331a6f6efb041473125d40d3f7f51077b100604be3e3cdf39
    • -m:提交信息
    • -a:更新的用户信息
    • 48febfe7fbd7:容器(container)ID。ID为容器(container)ID而并非镜像(image)ID
    • ubuntu:14.04.vim:tag名称
  • 查看修改结果

    1
    2
    3
    4
    5
    $> docker images
    REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
    ubuntu 14.04.vim eb39a2d496ed 30 seconds ago 231 MB
    docker.io/ubuntu latest af88597ec24b 3 days ago 187.9 MB
    ubuntu 14.04 af88597ec24b 3 days ago 187.9 MB
  • 使用新镜像

    1
    $> docker run -it ubuntu:14.04.vim

导出镜像

 将已有的镜像导出到本地

1
$> docker save -o ubuntu14.04.vim.tar ubuntu:14.04.vim

导入镜像

 导入使用docker save导出的镜像

1
$> docker load < ubuntu14.04.vim.tar

Dockerfile 创建镜像

 使用Dockerfile创建镜像
Dockerfile一般包含四部分:

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

Dockerfile指令:

  • FROM
    指定基础镜像,若本地缺少镜像则自动从公有库下载镜像
    FROM指定必须是Dockerfile的非注释第一个指令
    FROM没有指定tag,默认使用last
  • MAINTAINER
    维护者信息
  • RUN
    RUN会在FROM指定的镜像中执行命令,执行完后提交(commit)。docker run image——>RUN command——>docker commit container_id
    后续RUN都在之前RUN已提交(commit)的镜像基础上进行。
    RUN的书写格式分两种:
    • RUN command (此方式运行在/bin/sh -c的shell中)
    • RUN ["command", "param1", "param2"]
  • CMD
    在容器(container)启动时添加一个默认命令。
    一个Dockerfile只能有一个CMD,若出现多个CMD则只有最后一个生效。
    若用户启动容器(container)时指定了运行的命令,则会覆盖掉 CMD 指定的命令。
    CMD 和 RUN 区别:
    CMD只在容器(container)启动时执行,在使用docker build创建镜像时并不会执行。
    RUN只在docker build创建镜像时执行,一旦创建完镜像,一切与RUN无关。
  • EXPOSE
    对外映射端口
  • ENV
    设置环境变量
  • ADD
    ADD src dest
    复制src文件到容器destsrc可指定远程文件URLS。
  • COPY
    ADD作用相同,但src不能指定远程文件。
  • ENTRYPOINT
    指定容器(container)启动后执行的命令,并且不可被docker run提供的参数覆盖(CMD可被覆盖)
  • VOLUME
    创建挂载点
  • USER
    指定容器(container)运行时的用户/UID(CMDRUNENTRYPOINT使用USER指定的用户运行)
  • WORKDIR
    指定CMDRUNENTRYPOINT的工作目录
  • ONBUILD
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
$> mkdir centos7_nginx && cd centos7_nginx
$> vim Dockerfile

############################################################
# Dockerfile to build Nginx Installed Containers
# Based on CentOS 7
############################################################
# Set the base image to Ubuntu
FROM centos:7
# File Author / Maintainer
MAINTAINER mogl <fatesai@gmail.com>
# EPEL
#RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN mkdir -p /home/work/software/ && cd /home/work/software/
RUN wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm && rpm -ivh epel-release-7-5.noarch.rpm
# Copy script
ADD Sysinit7.sh /home/work/software/
# Install Nginx
RUN echo "C"|bash /home/work/software/Sysinit7.sh &>> /tmp/nginx_install.log
# Expose ports
EXPOSE 80
# Set the default command to execute
# when starting a new container
ENTRYPOINT /usr/local/nginx/sbin/nginx -t &> /dev/null && /usr/local/nginx/sbin/nginx

$> docker build -t="centos7:nginx" /root/centos7.nginx

Docker 容器(container)

 容器(container)是应用及应用运行时所需的环境。

创建并启动容器

 使用docker run创建并启动容器。

1
2
$> docker run -ti  ubuntu:14.04 /bin/bash
root@f4bbade713e0:/#

 创建并启动容器(container),启动Bash终端并运行用户进行交互

  • -t:分配伪终端
  • -i:容器标准输入保持打开
  • f4bbade713e0:容器ID

docker run其实是docker createdocker start的组合,即docker run = docker create + docker start。这一点类似与Gitgit pullgit fetchgit merge的关系。
docker run内部流程:

  • 检查指定的镜像(images)是否存在本地,不存在则docker pull从公有库中下载镜像(images)
  • docker create使用镜像(images)创建容器(container),在镜像(images)的只读层(read-only layer)上(镜像栈顶部)添加一层可读写层(read-write layer)
  • 从宿主机接口桥接虚拟接口到容器(container)中并从地址池分配IP给容器(container)
  • docker start启动应用进程

启动已停止容器

 当用docker run创建并启动容器(container)后,退出容器(container)则容器处于Existed状态。可用docker start来启动此容器。

  • 查看退出容器(container)
     注意STATUS,此时为Existed状态

    1
    2
    3
    $> docker ps -l
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    f4bbade713e0 ubuntu:14.04.vim "/bin/bash" 46 seconds ago Exited (0) 2 seconds ago high_brattain
  • 启动已停止容器(container)

    1
    2
    3
    4
    5
    6
    $> docker start f4bbade713e0
    f4bbade713e0

    $> docker ps -l
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    f4bbade713e0 ubuntu:14.04.vim "/bin/bash" 23 minutes ago Up 24 seconds high_brattain
  • 进入启动后的容器(container)

    • docker attach
       使用docker attach命令进入容器(container),若直接Ctrl + d退出时容器(container)会自动停止(UP——>Existed)。若要退出容器并保持容器运行则需要按Ctrl + p + q

      1
      2
      $> docker attach f4bbade713e0
      root@f4bbade713e0:/#
    • docker exec
      docker exec命令也可进入容器(container)且直接Ctrl + d退出后容器不会停止

      1
      2
      $> docker exec -it f4bbade713e0 /bin/bash
      root@f4bbade713e0:/#

导出容器

docker export

1
2
3
4
5
6
$> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4bbade713e0 ubuntu:14.04.vim "/bin/bash" 47 minutes ago Exited (0) 17 minutes ago high_brattain
dfc9ce350449 centos:nginx "/bin/bash" 7 hours ago Exited (0) 49 minutes ago cocky_colden

$> docker export f4bbade713e0 > ubuntu14.04.vim.tar

导入容器

docker import

1
$> cat ubuntu14.04.vim.tar | docker import - ubuntu:14.04.vim.import

删除容器

docker rm(删除镜像是docker rmi)

1
2
3
4
5
6
7
8
9
10
11
$> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4bbade713e0 ubuntu:14.04.vim "/bin/bash" 47 minutes ago Exited (0) 17 minutes ago high_brattain
dfc9ce350449 centos:nginx "/bin/bash" 7 hours ago Exited (0) 49 minutes ago cocky_colden

$> docker rm f4bbade713e0
f4bbade713e0

$> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dfc9ce350449 centos:nginx "/bin/bash" 7 hours ago Exited (0) 54 minutes ago cocky_colden

Docker 数据管理

 Docker管理数据主要有两种方式:

  • 数据卷(Data volume)
  • 数据卷容器(Data volume container)

数据卷(Data Volume)

 为了能保存和共享容器(container)间的数据,Docker提出数据卷(Data Volume)的概念。

  • 可绕过统一文件系统(union file system),数据以文件或目录形式保存在宿主机文件系统上,供多个容器(container)之间共享与重用数据。
  • 对数据卷(Data Volume)的修改立即生效
  • 更新数据卷(Data Volume)不影响镜像(images)
  • 数据卷(Data Volume)只要有容器(container)使用就会一直存在

创建数据卷(Data Volume)

 创建数据卷(Data Volume)有两种方式:

  • 在Dockerfile中使用VOLUME指定

    1
    VOLUME /path/to/dir
  • docker run执行时使用-v参数指定

    • 创建数据卷

      1
      2
      $> docker run -it -v /data/docker_volume/ ubuntu:14.04 /bin/bash
      root@24eb5121c1e4:/#
    • 获取数据卷在宿主机上对于的路径

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      $> docker inspect 24eb5121c1e4
      ... ...
      "Mounts": [
      {
      "Name": "ec85ea5ebcf1317001d251030c15d666917862757272fa2998c0b111141917b8",
      "Source": "/var/lib/docker/volumes/ec85ea5ebcf1317001d251030c15d666917862757272fa2998c0b111141917b8/_data",
      "Destination": "/data/docker_volume",
      "Driver": "local",
      "Mode": "",
      "RW": true
      }
      ],
      ... ...

挂载宿主目录作为数据卷(Data Volume)

 创建数据卷(Data Volume)后还需要用docker inspect查找对于的宿主目录比较麻烦,直接挂载宿主目录到容器(container)中能方便数据的管理。

1
$> docker run -it -v /data/docker_volume:/www ubuntu:14.04 /bin/bash

 将宿主机上的/data/docker_volume目录挂载到容器(container)的/www目录。

  • 宿主目录必须为绝对路径
  • 挂载到容器(container)中的目录(/www)默认为rw。可设置挂载为只读-v /data/docker_volume:/www:ro

数据卷容器(Data Volume Container)

 数据卷容器(Data Volume Container),即容器(container)创建了数据卷(Data Volume),此数据卷(Data Volume)专提供给其他容器(container)进行挂载,数据卷容器常用于容器(container)间共享持续更新数据。

创建数据卷容器

 创建一个数据卷容器(Data Volume Container)并命名为dbdata。(数据卷容器完全可不运行,避免浪费资源)

1
$> docker run -v /data/dbdata --name dbdata ubuntu:14.04 echo "Data-only container"

  • -v /data/dbdata:创建数据卷(Data Volume)
  • --name dbdata:命名此容器(container)为dbdata
  • ubuntu:14.04:指定镜像(image)。一般如果用作数据库的话并不会使用系统镜像或最小化镜像(busybox/scratch),而是直接使用数据库镜像
  • echo "Data-only container":指定容器执行的命令。作用有二:其一是容器执行完命令后自动退出,数据卷容器不运行;其二是当使用docker ps -a命令查看容器时方便指定容器的用途

共享数据卷容器的数据卷

 使用--volumes-from挂载容器(container)中的数据卷(Data Volume)到自身容器(container)中。

1
2
3
4
$> docker run -it -d --volumes-from dbdata --name db1 centos:7 /bin/bash
[root@a29120ba32fa /]# ll /data/
total 0
drwxr-xr-x. 2 root root 36 Jan 12 07:26 dbdata

备份、恢复数据卷

  • 备份数据卷

    1
    $> docker run --rm --volumes-from dbdata -v $(pwd):/data/backup ubuntu:14.04 tar zcf /data/backup/backup.tar.gz /data/dbdata
    • docker run --rm:创建并运行一个新容器(container),--rm表示执行完命令后自动删除该容器
    • --volumes-from dbdata:从名为dbdata的数据卷容器中挂载其数据卷到到新容器上(dbdata数据卷容器上的数据卷为/data/dbdata,就是备份此数据卷)
    • -v $(pwd):/data/backup:将宿主机上的当前目录$(pwd)挂载到新容器的/data/backup目录
    • ubuntu:14.04:新容器是基于ubuntu:14.04镜像创建的
    • tar zcf /data/backup/backup.tar.gz /data/dbdata:将新容器中/data/dbdata数据卷目录进行打包压缩备份成/data/backup/backup.tar.gz
  • 恢复数据卷
     创建一个带数据卷的新容器,并将备份的数据卷数据恢复

    1
    2
    $> docker run -it -d -v /data/dbdata --name recover_db ubuntu:14.04 /bin/bash
    $> docker run --rm --volumes-from recover_db -v $(pwd):/data/backup ubuntu:14.04 tar zxf /data/backup/backup.tar.gz -C /

删除数据卷

 数据卷只要有容器使用便会一直存在,而且在将用到某数据卷的所有容器删除后数据卷并不会自动被删除。若要彻底删除数据卷必须在删除最后一个还挂载着它的容器时使用docker rm -v命令来指定同时删除关联的容器。
docker run --rm在执行完命令后会自动删除容器,另外也会取消该容器和数据卷的关系。

Docker 网络配置

容器互联

 Docker允许容器(container)间相互连接以交换信息。容器互联需要用到容器名称,所以在启动容器时需要使用–name参数为容器自定义容器名。
 容器互联使用--link参数建立连接。

  • 创建数据库容器
     使用数据库镜像创建数据库容器,将新容器命名为db

    1
    $> docker run -d --name db docker.io/mysql
  • 创建web应用容器并建立连接
    --link参数的格式为 --link name:aliasname是要连接容器的名称,alias是此连接的别名。

    1
    $> docker run -d -P --name web --link db:web_to_db ubuntu:14.04

Docker 网络模式

 容器(container)有4种网络模式,可在启动容器时通过--net参数指定:docker run --net=network_mode

  • host模式docker run --net=host
  • container模式docker run --net=container:container_name/container_id
  • bridge模式docker rundocker run --net=bridge,bridge模式为默认模式
  • none模式docker run --net=none

host 模式

 host模式,在容器启动时并不会独立创建Network Namespace给容器而是和宿主机共用一个Network Namespace。简单来说就是容器并没有一个隔离的网络环境而是使用宿主机的网络环境。host模式中除了网络外其余的资源都是实现隔离的。

container 模式

 container模式,指定新建的容器和已存在的容器共享一个Network Namespace,新建的容器没有自身的网卡和IP而是和指定的容器共享IP和端口范围。container模式中除了网络外其余的资源也是隔离的,两个容器间的进程可通过lo设备通信。

none 模式

 none模式,容器拥有独立的Network Namespace但没有进行任何的网络设置,容器内只有lookback设备,没有网卡、IP和路由等信息。用户可根据需求进行添加和配置。

bridge 模式

 bridge模式,此模式为容器的默认模式。
 当Docker启动时,Docker会在宿主机上创建docker0虚拟接口,并会随机分配一个本地未被占用的私有IP地址(常见地址172.17.42.1/16)。
 当容器(container)启动时,会创建一个veth pair设备,veth pair一对虚拟接口。从一个veth接口发出的数据必会直接到达此接口的peer veth。由于此特性,veth pair常用于连接两个网络接口,两个接口设备之间会形成虚拟链路用于完成数据的进出。Docker创建的veth pair,一端为容器(container)内的网络接口,通常是eth0eth0的IP与docker0的IP属于同一网段确保通信正常;另一端则在宿主机上并被挂载到docker0设备上,通常为vethxxxxxxx
 Docker网络设备关系如下图所示,图片来源
docker_network_interface.png

 启动两个容器(container)后宿主机上网络设备情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$> ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.42.1 netmask 255.255.0.0 broadcast 0.0.0.0
... ...
enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.2.222 netmask 255.255.255.0 broadcast 10.0.2.255
... ...
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
... ...
veth273d670: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::d81b:1aff:fe8c:2850 prefixlen 64 scopeid 0x20<link>
... ...
veth490482d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::f880:ebff:fe8c:e5bc prefixlen 64 scopeid 0x20<link>
... ...

 通过brctl show命令查看挂载在docker0上的veth的设备情况

1
2
3
4
$> brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242809a1ff9 no veth273d670
veth490482d

端口映射

 端口映射用在bridge模式

随机端口映射

 为了使外部能访问到容器(container)内,需要在宿主机和容器中做端口映射。
 可在启动容器(container)时使用-P参数进行端口映射,-P参数能让Docker随机映射宿主机的49000~49900的某个端口到容器(container)内部开放的端口。

1
$> docker run -d -P ubuntu:14.04 python app.py

指定端口映射

-p参数默认映射TCP,若想映射UDP则需指定-p 80:5225/udp
 格式:-p hostPort:containerPort-p ip:hostPort:containerPort

1
2
3
4
$> docker run --name nginx -it -d -p 80:5225 centos:nginx
$> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5107099c0d1a centos:nginx "/bin/bash" 49 minutes ago Up 1 seconds 80/tcp, 0.0.0.0:80->5225/tcp nginx

Powered: Hexo, Theme: Nadya remastered from NadyMain