Docker_v2
一、Docker资源配额
(一)、概述
- Docker通过cgroup来控制容器使用的资源限制,可以对docker限制的资源包括CPU、内存、磁盘,来实现一个安全策略,防止业务容器被黑而影响到服务器
(二)、具体操作
## 指定docker容器可以使用的cpu份额
docker run -it --cpu-shares 512 centos /bin/bash
· --cpu-shares:cpu配额
· 注意:设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。通过 cpu share 可以设置容器使用 CPU 的优先级。
## CPU core核心控制
docker run -itd --name docker1 --cpuset-cpus 0,1 centos /bin/bash
· --cpuset-cpus 0,1 # 绑定cpu到第一个和第二个核上
· --cpuset-mems 0,1,3 # 使用节点0、1、3上的内存,但只对具有NUMA拓扑(具有多CPU、多内存节点)的服务器上作用比较大
## stress压测工具,需要用到epol源安装
# 参数解释
-? 显示帮助信息
-v 显示版本号
-q 不显示运行信息
-n 显示已完成的指令情况
-t --timeout N 指定运行N秒后停止
--backoff N 等待N微妙后开始运行
-c 产生n个进程 :每个进程都反复不停的计算随机数的平方根,测试cpu
-i 产生n个进程 :每个进程反复调用sync(),sync()用于将内存上的内容写到硬盘上,测试磁盘io
-m --vm n 产生n个进程,每个进程不断调用内存分配malloc()和内存释放free()函数 ,测试内存
--vm-bytes B 指定malloc时内存的字节数 (默认256MB)
--vm-hang N 指定在free栈的秒数
-d --hadd n 产生n个执行write和unlink函数的进程
-hadd-bytes B 指定写的字节数
--hadd-noclean 不unlink
注:时间单位可以为秒s,分m,小时h,天d,年y,文件大小单位可以为K,M,G
# 例:产生2个cpu进程,2个io进程,20秒后停止运行
stress -c 2 -i 2 --verbose --timeout 20s
## docker容器控制内存
docker run -it -m 128m centos
· -m(--memory) # 允许容器使用的内存上限为128M
## docker容器控制IO
docker run -it -v /var/www/html/:/var/www/html --device /dev/sda:/dev/sda --device-write-bps /dev/sda:2mb centos /bin/bash
· --device 参数 # 将主机设备添加到容器
· --device-read-bps 设备名:速率 # 限制容器磁盘 IO
## docker容器运行结束自动释放资源
docker run -it --rm --name test centos sleep 6
· --rm # 运行完毕后自动删除容器
· sleep # sleep命令可以用来将目前动作延迟一段时间
二、Dockerfile
(一)、介绍
-
Dockerfile是用来构建 docker 镜像的构建文件,定义了一切的步骤,源代码。
-
构建步骤
- 编写一个dockerfile文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像(DockerHub 、阿里云仓库)
(二)、DockerFile的编写
1、构建指令
docker build -t . image:tag
· -t:构建镜像
· . :当前目录下的dockerfile文件
· -f:指定具体的dockerfile文件
2、DockerFile指令
# 基础镜像
FROM
· 例:FROM nginx
# 作者信息,没必要写
MAINTAINER
· 例:MAINTAINER zzz
# 指定在当前镜像构建过程中要运行的命令,可以一个RUN接多个命令,中间用 ; 隔开
RUN
· RUN <command> (shell模式)
· 例:RUN echo hello
· RUN [“executable”,“param1”,“param2”](exec模式)
· 等价于/bin/bash -c echo hello
· 例:RUN [“/bin/bash”,”-c”,”echo hello”]
# ADD 指令和 COPY 的使用格式一致。在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>,根据是否需要自动解压来决定。如果单纯复制文件,推荐使用COPY
ADD
· ADD [--chown=<user>:<group>] <源路径1>... <目标路径>
· 例:ADD --chown=nginx:nginx /data/test.tar.gz /test
· ADD [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
· 例:ADD --chown=nginx:nginx ["/data/test.tar.gz","/test"]
· [--chown=<user>:<group>]:可选参数,改变复制到容器内文件的拥有者和属组。
· <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
· <源路径>:源文件或者源目录,这里可以是通配符表达式。
· 例:ADD hom* /test
· 例:ADD hom?.tar.gz /test
# 把dockerfile当前目录下的文件拷贝到容器中(不解压tar包)
COPY
· COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
· 例:COPY --chown=nginx:nginx /data1 /data2
· COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
· 例: COPY --chown=nginx:nginx ["/data1","/data2"]
· [--chown=<user>:<group>]:可选参数,改变复制到容器内文件的拥有者和属组。
· <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
· <源路径>:源文件或者源目录,这里可以是通配符表达式。
· 例:COPY hom* /test
· 例:COPY hom?.txt /test
# 指定容器的默认工作目录(填写绝对路径)
WORKDIR
· WORKDIR <工作目录路径>
· 例:WORKDIR /etc/nginx
# 定义匿名数据卷,在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
VOLUME
· VOLUME /sys/fs/cgroup可以提高权限
· VOLUME ["<路径1>", "<路径2>"...]
· 例:VOLUME ["/data1","/data2"]
· VOLUME <路径>
· 例:VOLUME /data
# 声明端口,方便使用者配置映射。在运行时使用随机端口映射 -P 时,会自动映射到 EXPOSE 的端口。可以是一个或者多个端口,也可以指定多个EXPOSE。
EXPOSE
· EXPOSE <端口1> [<端口2>...]
· 例:EXPOSE 80 8080 8888
# 容器启动的时候执行的初始命令,会被docker run 命令行中指定的命令替换
CMD
· CMD[“executable”,“param1”,“param2”](exec模式)
· 例:CMD ["/usr/sbin/nginx","-g","daemon off;"]
· CMD command (shell模式)
· 例:CMD /usr/sbin/nginx -g daemon off;
· CMD [“param1”,”param2”](作为ENTRYPOINT指令的默认参数)
# 容器启动的时候执行的初始命令,不能被替换,如果同时使用CMD和ENTRYPOINT,CMD命令将作为ENTRYPOINT命令的参数。如果存在多个 ENTRYPOINT 指令,仅最后一个生效。但如果运行 docker run 时使用了 --entrypoint 选项,y覆盖 entrypoint指令指定的程序
ENTRYPOINT
· ENTERYPOINT [“executable”,“param1”,“param2”](exec模式)
· 例:ENTERYPOINT["nginx", "-c","/etc/nginx/nginx.conf"]
· ENTERYPOINT command (shell模式)
· 例:ENTERYPOINT nginx -c /etc/nginx/nginx.conf
# 类似于触发器,当构建一个被继承DockerFile 这个时候就会运行ONBUILD的指令。触发指令
ONBUILD
· ONBUILD <其它指令>
· 例:ONBUILD rm -rf /* 😏
# 构建的时候设置环境变量,跟 -e 一样
ENV
· ENV <key> <value>
· 例:ENV a b
· ENV <key>=<value>...
· 例:ENV a=b
# LABEL 可以为生成的镜像添加元数据标签信息(metadata),以键值对的形式,尽可能地把多个labels合并到一个LABEL指令
LABEL
· LABEL <key>=<value> <key>=<value> <key>=<value> ...
# 与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
ARG
· ARG <参数名>[=<默认值>]
· 例:ARG a=b
· 在构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖
# 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
USER
· USER <用户名>[:<用户组>]
· 例:
· USER user
· USER uid
· USER user:group
· USER uid:gid
· USER user:gid
· USER uid:group
# 用于指定某个程序或者指令来监控 docker 容器服务的运行状态,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态。Docker 默认只能通过容器进程的返回码判断容器的状态,HEALTHCHECK则能够从业务角度判断应用是否有异常,当一个容器设置了HEALTHCHECK之后,除了正常的up状态,它多了一个healthy状态,这个状态初始为starting。当健康检查通过后,它变成了healthy(不管之前是什么状态)。当连续出现几次失败后,就变成unhealthy。
HEALTHCHECK
· HEALTHCHECK NONE # 如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
· HEALTHCHECK [选项] CMD <命令>
· --interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
· --timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
· --retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3 次
· 例:HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1 # 如果返回 1 则退出(curl -f 连接失败时不显示http错误,-s静默模式)
3、例:
## 基于alpine镜像构建nginx
FROM alpine
COPY init.sh /
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk update && \
apk add curl bash vim libxml2-dev openssl-dev libjpeg-turbo-dev binutils && \
apk add libpng-dev libxpm-dev freetype-dev gd-dev gettext-dev libmcrypt-dev && \
addgroup nginx && \
adduser -G nginx -D -s /sbin/nologin nginx && \
apk add nginx && \
chmod +x /init.sh && \
mkdir -p /code/kod && \
chmod -R 777 /code && \
chown -R nginx.nginx /code
ADD ./kodbox.1.26.tar /code/kod
ADD ./default.conf /etc/nginx/http.d
EXPOSE 80
ENTRYPOINT ["/init.sh"]
(三)、编写注意事项及优化方案
-
注意事项
- 构建docker时必须在该目录中命名一个dockerfile文件
- 同一个目录中不能有两个dockerfile文件
-
优化方案
- 尽可能选择简单的基础镜像,例如alpine、scratch、busybox
- 尽可能减少dockerfile构建过程中的层级
- 针对dockerfile内容进行修改的操作尽可能放在后面,让它走缓存,而不是重新再次生成缓存
- 借助于.dockerignore文件将不需要推送的文件排除掉,因为在镜像构建过程中会将dockerfile文件所在的目录中的所有文件进行推送,但是这个隐藏文件不存在,需要自行创建,在其中添加不需要推送的文件名即可
三、容器互联
(一)、docker 0
-
docker0是docker管理容器网络的虚拟逻辑网卡,起到桥接网络的功能,每启动一个容器,docker都会给容器分配一个ip。
-
桥接模式使用的是 veth-pair 技术,veth-pair是成对的虚拟设备接口,一端连着协议,一端彼此相连。
正因为有这个特性,veth-pair可以充当一个桥梁,用来连接各种虚拟网络设备。
[root@docker ~]# ip a
......
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:7b:c9:f3:6b brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:7bff:fec9:f36b/64 scope link
valid_lft forever preferred_lft forever
## 网桥管理工具,需要yum安装
yum -y install bridge-utils
brctl show # 可以查看到有一个docker0的网桥设备
(二)、----link
- ----link是用于将某容器的名字和IP关系解析到运行的容器中,从而保证容器之间直接通过名称进行通信,注意,是单向通信,局限性较大。
- 具体的操作就是将指向的容器名的IP添加到了/etc/hosts解析文件中,当作一个域名来解析。
例: 基于centos镜像创建test1和test2容器,并让test2能ping通test1
docker run -d -P --name test1 centos
docker run -d -P --name test2 --link test1 centos
(三)、自定义网络
1、网络模式
- bridge:桥接模式,也是docker 0默认的网络模式
- none:不配置网络
- host:共用宿主机网络,容器使用宿主机的网卡,传输速率高,但是容易出现端口冲突和IP地址冲突
- container:两个容器共享同一网络,ip,mac地址完全相同,传输高效,彼此不依赖
2、自定义网络命令
## 创建自定义网络
docker network create -d bridge --subnet 172.18.0.0/24 --gateway 172.18.0.1 zzz
· -d bridge # 定义网络模式,-d是 --driver 的缩写
· --subnet 172.18.0.0/24 # 定义网段
· --gateway 172.18.0.1 # 定义网段网关
· zzz # 自定义网络名称
## 查看网络模式
docker network ls
## 删除自定义网络
docekr network rm xxx
## 查看自定义网络元数据信息
docker network inspect xxx
## 创建容器时指定网络模式
docker run --name xxx -d -P --net xxx XXX
· --net # 指定网络模式,在容器启动时默认指定网络为 --net bridge,也就是docker 0
(四)、跨主机通信
1、macvlan
- 通过docker 0 构建一个桥接网卡,实现容器通过桥接网络到宿主机网络上,但是容易导致网段ip不足
## 所有节点创建一个相同的macvlan网络,来实现本机容器桥接到宿主机网络
docker network create -d macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.254 -o parent=eth0 macvlan_1
· -d macvlan # 定义网络模式,-d是 --driver 的缩写
· --subnet 10.0.0.0/24 # 定义子网 范围
· --gateway 10.0.0.254 # 定义子网网关
· -o parent=xxx # 指定宿主机可以上网的网卡
## 运行容器并指定macvlan网络即可
docker run -d --network macvlan_1 --ip 10.0.0.110 --name mac_1 alpine:latest tail -f /etc/hosts
· --ip 指定容器的固定ip地址
2、overlay
- 通过隧道统一注册地址信息到数据库中,从而通过隧道实现网络通信
## 安装consul容器,consul存储ip地址的分配
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
## 在需要通讯的docker主机配置consul接口
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://gk0lnxyj.mirror.aliyuncs.com"],
"cluster-store": ["consul://10.0.0.201:8500"], # 指定consul配置存储节点
"cluster-advertise": ["10.0.0.199:2376"] # 每台机器各自需要被发现的接口地址
}
## 重启docker
systemctl restart docker
## 创建overlay网络,配置的网段要与docker主机的网端不冲突,只需在一个节点创建即可
docker network create -d overlay --subnet 172.16.2.0/24 --gateway 172.16.2.254 overlay_1
## 最后创建容器使用即可
docker run -d --network overlay_1 --name over_1 alpine:latest tail -f /etc/hosts