Docker基础学习笔记

各平台安装

Mac brew 安装 docker

1
2
3
4
## 先卸载
brew uninstall docker
## 安装
brew install --cask --appdir=/Applications docker

Liunx CentOS7 环境安装Docker

Linux设置

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
## 配置主机名
hostnamectl set-hostname centos && bash

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

## 关闭 iptables 防火墙
#安装 iptables
yum install iptables-services -y
## 禁用 iptables
service iptables stop && systemctl disable iptables
## 清空防火墙规则
iptables -F

# 关闭 selinux
setenforce 0
# 注意:修改 selinux 配置文件之后,重启机器,selinux 才能永久生效
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
# 显示 Disabled 表示 selinux 关闭成功
getenforce

#配置时间同步
yum install -y ntp ntpdate
ntpdate cn.pool.ntp.org
#编写计划任务
crontab -e
* */1 * * * /usr/sbin/ntpdate cn.pool.ntp.org
# 重启 crond 服务使配置生效
systemctl restart crond

Docker及其依赖安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## 安装基础软件包
yum install -y wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo ntp libaio-devel wget vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack

## yum-config-manager 命令在utils里
yum -y install yum-utils

#安装 docker-ce
配置 docker-ce 国内 yum 源(阿里云)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 安装 docker 依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2

## 安装 docker-ce
yum install docker-ce -y

启动docker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#启动 docker 服务
systemctl start docker && systemctl enable docker

systemctl status docker
看到 running,表示 docker 正常运行
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset:
disabled)
Active: active (running) since Thu 2021-07-01 21:29:18 CST; 30s ago
Docs: https://docs.docker.com


#查看 Docker 版本信息
docker 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
# 内核参数修改:br_netfilter 模块用于将桥接流量转发至 iptables 链,br_netfilter 内核参数需要开
启转发。
modprobe br_netfilter

cat > /etc/sysctl.d/docker.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

#使参数生效
sysctl -p /etc/sysctl.d/docker.conf

# 重启后模块失效,下面是开机自动加载模块的脚本 ,在/etc/新建 rc.sysinit 文件
vi /etc/rc.sysinit
#!/bin/bash
for file in /etc/sysconfig/modules/*.modules ; do
[ -x $file ] && $file
done

# 在/etc/sysconfig/modules/目录下新建文件如下
vi /etc/sysconfig/modules/br_netfilter.modules
modprobe br_netfilter

# 增加权限
chmod 755 /etc/sysconfig/modules/br_netfilter.modules

# 重启机器模块也会自动加载
lsmod |grep br_netfilter

br_netfilter 22209 0
bridge 136173 1 br_netfilter

注:
Docker 安装后出现:WARNING: bridge-nf-call-iptables is disabled 的解决办法:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1:
将 Linux 系统作为路由或者 VPN 服务就必须要开启 IP 转发功能。当 linux 主机有多个网卡时一个网卡收
到的信息是否能够传递给其他的网卡 ,如果设置成 1 的话 可以进行数据包转发,可以实现 VxLAN 等功
能。不开启会导致 docker 部署应用无法访问。

#重启 docker
systemctl restart docker

配置docker镜像加速器ß
登陆阿里云镜像仓库
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
如果没有开通,可开通阿里云的镜像服务
找到加速器地址,执行如下命令

1
2
3
4
5
6
7
8
9
10
11
12
sudo mkdir -p /etc/docker

## 写入加速的镜像地址
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors":["https://mcmje5nr.mirror.aliyuncs.com","https://registry.dockercn.com","https://docker.mirrors.ustc.edu.cn","https://dockerhub.azk8s.cn","http://hubmirror.c.163.com"]
}
EOF

## 让配置文件生效
sudo systemctl daemon-reload
sudo systemctl restart 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
## dockerhub查找镜像
docker search centos
## ---------
##解释说明:
##NAME: 镜像仓库源的名称
##DESCRIPTION: 镜像的描述
##OFFICIAL: 是否 docker 官方发布
##stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。
##AUTOMATED: 自动构建。
## ----------

## 下载镜像
docker pull centos

## 查看本地镜像
docker images

## 把镜像做成离线压缩包
docker save -o centos.tar.gz centos

## 解压离线镜像包
docker load -i centos.tar.gz

## 删除镜像
docker rmi -f centos:latest

容器操作

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
## 以交互方式启动并进入容器,输入 exit,退出容器,退出之后容器也会停止,不会再前台运行
docker run --name=hello -it centos /bin/bash
## ------
## docker run 运行并创建容器
## --name 容器的名字
## -i 交互式
## -t 分配伪终端
## centos: 启动 docker 需要的镜像
## /bin/bash 说明你的 shell 类型为 bash,bash shell 是最常用的一种 shell,
## 是大多数 Linux 发行版默认的 shell。 此外还有 C shell 等其它 shell。
## -------


## 以守护进程的方式启动容器,-d 在后台运行 docker
docker run --name=hello-d -td centos

## 查看正在运行的容器
docker ps | grep hello-d
## 查看所有运行中的容器
docker ps
## 查看所有容器,运行中和历史运行过已经停止的
docker ps -a

## 停止容器
docker stop hello-d

## 启动已经停止的容器
docker start hello-d

## 进入正在运行的容器
docker exec -it hello-d /bin/bash

## 删除容器
## 强制删除
docker rm -f hello-d
## 停止后删除
docker rm hello-d

## 帮助命令
docker --help

## 进入容器修改了内部文件,如何保存成新的镜像
docker commit -a "作者" -m "提交信息描述" 需保存的容器id 新镜像名称

Dockerfile

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。基于 Dockerfile 构建镜像可以使用 docker build 命令。docker build 命令中使用-f 可以指定具体的dockerfile 文件

Dockerfile例子

1
2
3
4
5
6
7
FROM centos
MAINTAINER lessismore
RUN yum install wget -y
RUN yum install nginx -y
COPY index.html /usr/share/nginx/html/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]

指令介绍

FROM

基础镜像,必须是可以下载下来的,定制的镜像都是基于 FROM 的镜像,这里的 centos 就是定制需要的基础镜像。后续的操作都是基于 centos 镜像。

MAINTAINER

指定镜像的作者信息

RUN

指定在当前镜像构建过程中运行的命令, 包含两种模式:

  1. shell模式 RUN (shell 模式,这个是最常用的,需要记住) eg: RUN echo hello
  2. exec模式 RUN [“executable”,“param1”,“param2”] (exec 模式)
    1
    RUN [“/bin/bash”,”-c”,”echo hello”] 等价于/bin/bash -c echo hello

EXPOSE

仅仅只是声明端口。作用:

  1. 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射
  2. 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
  3. 可以是一个或者多个端口,也可以指定多个 EXPOSE
    1
    格式:EXPOSE <端口 1> [<端口 2>...]

CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  1. CMD 在 docker run 时运行
  2. RUN 是在 docker build 构建镜像时运行的
    作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 启动命令行参数中指定要运行的程序所覆盖。
    1
    2
    3
    CMD[“executable”,“param1”,“param2”]   (exec 模式)
    CMD command (shell 模式)
    CMD [“param1”,”param2”] 作为 ENTRYPOINT 指令的默认参数

ENTERYPOINT

类似于 CMD 指令,但其不会被 docker run 启动命令行参数指定的指令所覆盖,而且这些命令行参数会被 当作参数送给 ENTRYPOINT 指令指定的程序。但是, 如果运行 docker run 时使用了 –entrypoint 选项,将覆盖 entrypoint 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令仅最后一个生效。格式:

1
2
ENTERYPOINT [“executable”,“param1”,“param2”]   (exec 模式)   
ENTERYPOINT command (shell 模式)

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,示例说明:

1
2
3
4
假设已通过 Dockerfile 构建了 nginx-cmd:v1 镜像:
FROM nginx-cmd:v1
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参

不传参运行:

1
2
3
docker run nginx-cmd:v1
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf

传参运行:

1
2
3
docker run nginx-cmd:v1 -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf

COPY

1
2
COPY<src>..<dest>
COPY[“<src>”...“<dest>”]

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
格式:

1
2
3
4
COPY [--chown=<user>:<group>] <源路径 1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径 1>",... "<目标路径>"]

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

1
2
COPY hom* /mydir/
COPY hom?.txt /mydir/

<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建

ADD

1
2
ADD <src>...<dest>
ADD [“<src>”...“<dest>”]

ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

  1. ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下, 会自动复制并解压到 <目标路径>。
  2. ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像 构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

    ADD vs COPY ADD 包含类似 tar 的解压功能 如果单纯复制文件,dockerfile 推荐使用 COPY

示例演示:拷贝本地的index.html替换容器内部的index.html

1
2
3
4
5
6
7
8
9
## 替换/usr/share/nginx 下的 index.html
vi dockerfile
FROM centos
MAINTAINER xianchao
RUN yum install wget -y
RUN yum install nginx -y
COPY index.html /usr/share/nginx/html/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]

VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:

  1. 避免重要的数据,因容器重启而丢失,这是非常致命的。
  2. 避免容器不断变大。

格式:

1
2
VOLUME ["<路径 1>", "<路径 2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

1
VOLUME [“/data”]

WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作 目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才 会一直存在。
格式:

1
2
WORKDIR <工作目录路径> 
WORKDIR /path/to/workdir (填写绝对路径)

ENV

设置环境变量

1
2
ENV <key> <value>
ENV <key>=<value>...

以下示例设置 NODE_VERSION =6.6.6, 在后续的指令中可以通过 $NODE_VERSION 引用:

1
2
3
4
ENV NODE_VERSION 6.6.6

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已 经存在)。

1
2
3
4
5
6
7
8
9
10
USER <用户名>[:<用户组>]

USER daemon
USER nginx
USER user
USER uid
USER user:group
USER uid:gid
USER user:gid
USER uid:group

ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜 像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
格式:

1
ONBUILD <其它指令>

用途:为镜像添加触发器 当一个镜像被其他镜像作为基础镜像时需要写上 OBNBUILD 会在构建时插入触发器指令

演示示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
## 第一个镜像,执行dockerfile时不会执行index.html的拷贝 ,生成的镜像名假设为onbuild-nginx:v1
vim dockerfile
FROM centos
MAINTAINER lessismore
RUN yum install wget -y
RUN yum install nginx -y
ONBUILD COPY index.html /usr/share/nginx/html/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]

## 第二个镜像FROM引用的是第一个镜像时 onbuild-nginx:v1,则会执行index.html文件的拷贝
vim dockerfile
FROM onbuild-nginx:v1
MAINTAINER lessismore
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
EXPOSE 80

LABEL

LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:

1
LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如我们可以添加镜像的作者:

1
LABEL org.opencontainers.image.authors="lessismore"

HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:

1
2
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

ARG

构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就 是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 –build-arg <参数名>=<值> 来覆盖。 格式:

1
ARG <参数名>[=<默认值>]

数据卷

Docker 容器的数据管理

什么是Docker容器的数据卷?

数据卷是经过特殊设计的目录,可以绕过联合文件系统(UFS),为一个或者多个容器提供访问,数据卷设计的目的,在于数据的永久存储,它完全独立于容器的生存周期,因此,docker 不会在容器删除时删 除其挂载的数据卷,也不会存在类似的垃圾收集机制,对容器引用的数据卷进行处理,同一个数据卷可以支持多个容器的访问。

数据卷的特点

  1. 数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,这些数据会被拷贝到新初始 化的数据卷中
  2. 数据卷可以在容器之间共享和重用
  3. 可以对数据卷里的内容直接进行修改
  4. 数据卷的变化不会影像镜像的更新
  5. 卷会一直存在,即使挂载数据卷的容器已经被删除

数据卷的使用

  1. 为容器添加数据卷

创建一个数据卷,数据存储在宿主机默认docker目录

1
2
3
4
5
docker run --name data -v /opt/data -t -i centos /bin/bash
## 查看数据存储的目录
docker inspect data|grep /var/lib/docker/volumes

"Source": "/var/lib/docker/volumes/89d6562b9c1fe10dd21707cb697a5d481b3c1b000a69b762f540fa826a16972a/_data",

创建一个数据卷,数据存储在宿主机指定的映射目录 ~/datavolume

1
2
3
docker run -v /datavolume:/data -it centos /bin/bash
## 示例
docker run --name volume -v ~/datavolume:/data -itd centos /bin/bash

注:~/datavolume 为宿主机目录,/data 为 docker 启动的 volume 容器的里的目录 这样在宿主机的/datavolume 目录下创建的数据就会同步到容器的/data 目录下
为数据卷添加访问权限

1
docker run --name volume1 -v ~/datavolume1:/data:ro -itd centos /bin/bash

添加只读权限之后在 docker 容器的/data 目录下就不能在创建文件了,为只读权限;在宿主机下的 /datavolume1 下可以创建东西

  1. 使用 dockerfile 构建包含数据卷的镜像

Docker数据卷容器

什么是数据卷容器?

命名的容器挂载数据卷,其他容器通过挂载这个容器实现数据共享,挂载数据卷的容器,就叫做数据卷 容器。
挂载数据卷容器的方法

1
docker run --volumes-from [container name]

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## (volume 这个镜像是上面创建的带两个数据卷/datavolume3 和/ddatavolume6 的镜像)
docker run --name data-volume -itd volume
## (进入到容器中)
docker exec -it data-volume /bin/bash
## 创建文件
touch /datavolume6/lucky.txt
退出容器 exit

## 创建一个新容器挂载刚才 data-volume 这个容器创建的数据卷
docker run --name data-volume2 --volumes-from data-volume -itd centos /bin/bash
## 进入到新创建的容器
docker exec -it data-volume2 /bin/bash
## 查看容器的/datavolume6 目录下是否新创建了 lucky.txt 文件
cd /datavolume6
## 可以看见有刚才在上一个容器创建的文件 lucky.txt

docker 数据卷的备份和还原

数据备份方法

1
2
3
docker run --volumes-from [container name] -v $(pwd):/backup centos tar czvf /backup/backup.tar [container data volume] 
## 示例
docker run --volumes-from data-volume2 -v /root/backup:/backup --name datavolume-copy centos tar zcvf /backup/data-volume2.tar.gz /datavolume6

数据还原方法

1
2
3
4
5
6
7
8
9
10
11
docker run --volumes-from [container name] -v $(pwd):/backup centos tar xzvf /backup/backup.tar.gz [container data volume] 
## 示例
docker exec -it data-volume2 /bin/bash
cd /datavolume6
rm -rf lucky.txt

docker run --volumes-from data-volume2 -v /root/backup/:/backup centos tar zxvf /backup/data-volume2.tar.gz -C /datavolume6

docker exec -it data-volum2 /bin/bash
cd /datavolum6
## 可以看到还原后的数据

容器网路互联

docker0 : 安装 docker 的时候,会生成一个 docker0 的虚拟网桥

Linux虚拟网桥: 可以设置 ip 地址 相当于拥有一个隐藏的虚拟网卡;每运行一个 docker 容器都会生成一个 veth 设备对,这个 veth一个接口在容器里,一个接口在物理机上。

安装网桥管理工具

1
2
3
yum install bridge-utils -y 
## 如果无法安装,尝试在线下载
rpm -ivh http://mirror.centos.org/centos/7/os/x86_64/Packages/bridge-utils-1.5-9.el7.x86_64.rpm

brctl show 可以查看到有一个 docker0 的网桥设备,下面有很多接口,每个接口都表示一个启动的 docker 容器,因为我在 docker 上启动了很多容器,所以 interfaces 较多,如下所示:

1
2
3
4
5
[root@centos _data]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242b0124965 no veth2d2a35d
veth883ebd5
veth990689c

实验用例准备(由于centos 镜像被docker官方标记为deprecated,很多依赖拉取失败,可以制作一个基础镜像备用,节省环境准备时间):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
### 准备测试镜像
FROM centos
### begin bugfix
RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum update -y
### end
RUN yum clean all
RUN yum install wget -y
RUN yum install nginx -y
RUN sed -i "7s/^/#/g" /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD /bin/bash

### 构建
docker build -t="inter-image" .

允许所有容器间互联

  1. 同一台机器的容器启动后默认是互联的,但是容器重启后IP被重新分配。
  2. docker --link设置网络别名,给容器起一个代号,这样可以直接以代号访问,避免了容器重启 ip 变化带来的问题
    1
    2
    3
    4
    5
    6
    7
    ## 语法
    docker run --link=[CONTAINER_NAME]:[ALIAS] [IMAGE][COMMAND]
    ## 先启动一个容器 network01
    docker run --name network01 -itd inter-image /bin/bash
    ## 然后启动第二个容器 network02
    docker run --name network02 -itd --link=network01:webnet inter-image /bin/bash
    ## 在network02上访问network01容器只需要,ping webnet即可。我们重启network01容器,ip变化了也没问题。

容器的网络模式

docker run 创建 Docker 容器时,可以用–net 选项指定容器的网络模式,Docker 有以下 4 种网络模式:

  1. bridge 模式:使–net =bridge 指定,默认设置;
  2. host 模式:使–net =host 指定;
  3. none 模式:使–net =none 指定;
  4. container 模式:使用–net =container:NAME orID 指定。

brigde 模式

Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show命令查看。

bridge模式是 docker 的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker 实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

1
docker run --name bridge -it --privileged=true centos bash

host 模式

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

1
docker run --name host -it --net=host --privileged=true centos bash

none 模式

使用none模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

1
2
3
4
5
6
7
## 示例
docker run -itd --name none --net=none --privileged=true centos
## 只有本地lo 地址
lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever

container 模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

1
docker run --name container2 --net=container:none -it --privileged=true centos

资源限制

Docker资源配额

Docker 通过 cgroup 来控制容器使用的资源限制,可以对 docker 限制的资源包括 CPU、内存、磁盘

控制CPU

CPU份额

1
2
3
#查看配置份额的帮助命令:
docker run --help | grep cpu-shares
-c, --cpu-shares int CPU shares (relative weight)

CPU shares (relative weight) 在创建容器时指定容器所使用的 CPU 份额值。cpu-shares 的值不能保证可以获得 1 个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个弹性的加权值。
默认每个 docker 容器的 cpu 份额值都是 1024。在同一个 CPU 核心上,同时运行多个容器时,容器的 cpu 加权的效果才能体现出来。

两个容器 A、B 的 cpu 份额分别为 1000 和 500,结果会怎么样?

情况 1:A 和 B 正常运行,占用同一个 CPU,在 cpu 进行时间片分配的时候,容器 A 比容器 B 多一倍 的机会获得 CPU 的时间片
情况 2:分配的结果取决于当时其他容器的运行状态。比如容器 A 的进程一直是空闲的,那么容器 B 是可以获取比容器 A 更多的 CPU 时间片的; 比如主机上只运行了一个容器,即使它的 cpu 份额只有 50,它也可以独占整个主机的 cpu 资源。
cgroups 只在多个容器同时争抢同一个 cpu 资源时,cpu 配额才会生效。因此,无法单纯根据某个容 器的 cpu 份额来确定有多少 cpu 资源分配给它,资源分配结果取决于同时运行的其他容器的cpu分配和容器中进程运行情况
示例:给容器实例分配 512 权重的 cpu 使用份额

1
2
3
4
## 参数: --cpu-shares 512
docker run -it --cpu-shares 512 centos /bin/bash
#查看结果:
cat /sys/fs/cgroup/cpu/cpu.shares

注:稍后,我们启动多个容器,测试一下是不是只能使用 512 份额的 cpu 资源。单独一个容器,看 不出来使用的 cpu 的比例。 因没有 其他docker 实例同此 docker 实例竞争

通过-c 设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能 分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。通过 cpu share 可以设置容器使用 CPU 的优先级
比如在 host 中启动了两个容器:

1
2
docker run --name "container_A" -c 1024 ubuntu
docker run --name "container_B" -c 512 ubuntu

container_A 的 cpu share 1024,是 container_B 的两倍。当两个容器都需要 CPU 资源时, container_A 可以得到的 CPU 是 container_B 的两倍。
需要注意的是,这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下。如果 container_A 处于空 闲状态,为了充分利用 CPU 资源,container_B 也可以分配到全部可用的 CPU。

CPU core核心控制

参数:–cpuset 可以绑定 CPU
对多核 CPU 的服务器,docker 还可以控制容器运行限定使用哪些 cpu 内核和内存节点,即使用-- cpuset-cpus--cpuset-mems 参数。对具有 NUMA 拓扑(具有多 CPU、多内存节点)的服务器尤其有 用,可以对需要高性能计算的容器进行性能最优的配置。如果服务器只有一个内存节点,则– cpuset-mems 的配置基本上不会有明显效果。

CPU控制参数混合使用

在上面这些参数中,cpu-shares 控制只发生在容器竞争同一个 cpu 的时间片时有效。 如果通过 cpuset-cpus 指定容器 A 使用 cpu 0,容器 B 只是用 cpu1,在主机上只有这两个容器使用 对应内核的情况,它们各自占用全部的内核资源,cpu-shares 没有明显效果。

如何才能有效果?

容器 A 和容器 B 配置上 cpuset-cpus 值并都绑定到同一个 cpu 上,然后同时抢占 cpu 资源,就可以 看出效果了。
测试 cpu-shares 和 cpuset-cpus 混合使用运行效果,就需要一个压缩力测试工具 stress 来让 容器实例把 cpu 跑满。

如何把 cpu 跑满?

如何把 4 核心的 cpu 中第一和第三核心跑满?可以运行 stress,然后使用 taskset 绑定一下 cpu。

stress工具

linux 系统压力测试软件 stress

1
2
yum install -y epel-release
yum install stress -y

stress的使用点这里了解

控制内存

Docker 提供参数-m, –memory=””限制容器的内存使用量。
例 1:允许容器使用的内存上限为 128M:

1
2
3
docker run -it -m 128m centos
## 进入容器查看内存设定值
cat /sys/fs/cgroup/memory/memory.limit_in_bytes

例 2:创建一个 docker,只使用 2 个 cpu 核心,只能使用 128M 内存

1
docker run -it --cpuset-cpus 0,1 -m 128m centos

控制IO

1
2
docker run --help | grep write-b 
--device-write-bps list Limit write rate (bytes per second) to a device (default [])

–device-read-bps value 限制此设备上的写速度(bytes per second),单位可以是 kb、mb 或者 gb。

防止某个 Docker 容器吃光你的磁盘 I / O 资源
例 1:限制容器实例对硬盘的最高写入速度设定为 2MB/s。

1
2
3
4
5
6
7
8
9
10
11
12
mkdir -p /var/www/html/
## --device 参数:将主机设备添加到容器
docker run -it -v /var/www/html/:/var/www/html --device /dev/sda:/dev/sda --device-write-bps /dev/sda:2mb centos /bin/bash

time dd if=/dev/sda of=/var/www/html/test.out bs=2M count=50 oflag=direct,nonblock

## 注:dd 参数说明
direct:读写数据采用直接 IO 方式,不走缓存。直接从内存写硬盘上。
nonblock:读写数据采用非阻塞 IO 方式,优先写 dd 命令的数据
50+0 records in
50+0 records out
52428800 bytes (52 MB) copied, 50.1831 s, 2.0 MB/s

容器结束自动释放资源

1
2
docker run --help | grep rm
--rm 参数: Automatically remove the container when it exits

作用:当容器命令运行结束后,自动删除容器,自动释放资源

1
2
3
docker run -it --rm --name auto-rm-test centos sleep 6
## 6秒后自动销毁
docker ps -a | grep auto-rm-test

镜像仓库harbor

Docker 容器应用的开发和运行离不开可靠的镜像管理,虽然 Docker 官方也提供了公共的镜像仓库, 但是从安全和效率等方面考虑,部署我们私有环境内的 Registry 也是非常必要的。Harbor 是由 VMware 公司开源的企业级的 Docker Registry 管理项目,它包括权限管理(RBAC)、LDAP、日志审核、管理界面、 自我注册、镜像复制和中文支持等功能。
官网地址:https://github.com/goharbor/harbor