安装Docker
安装最新版Docker
在 CentOS |安装码头发动机码头文件 (docker.com)
安装最新版docker-compose
Install Docker Compose | Docker Documentation
使用加速器
1、使用阿里云Docker镜像加速,提升pull的速度:
进入https://cr.console.aliyun.com的控制台,使用你的支付宝帐号登录,左侧的加速器帮助页面就会显示为你独立分配的加速地址。
#修改Docker配置文件
[root@xuegod63 ~]# cat >> /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://e9yneuy4.mirror.aliyuncs.com"]
}
EOF
#daeman重新加载配置,重启docker
systemctl daemon-reload
systemctl restart docker
docker info #再次查看会多一个注册镜像源
……
Registry Mirrors:
https://3dv9rasy.mirror.aliyuncs.com
……
Docker部署应用
安装cAdvisor
安装CentOS
docker run -itd -p 2222:22 --restart=always --privileged --name centos centos /usr/sbin/init
安装MySQL
docker run -d -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 --privileged=true --name mysql mysql
安装Redis
docker run -itd --name redis -p 6379:6379 redis
Docker基本命令
①查看某容器挂载的目录
[root@api-public-02 data]# docker inspect -f “{{.Mounts}}” live-main-api
①查看Docker整体空间使用情况
[root@api-public-02 docker]# docker system df
②查看Docker详细空间使用情况
[root@api-public-02 docker]# docker system df -v
①解决方法-自动清理
可以通过 Docker 内置的 CLI 指令 docker system prune 来进行自动空间清理
②docker system prune自动清理说明
1)该指令默认会清除所有如下资源:
已停止的容器(container)
未被任何容器所使用的卷(volume)
未被任何容器所关联的网络(network)
所有悬空镜像(image)。
2)该指令默认只会清除悬空镜像,未被使用的镜像不会被删除。
3)添加 -a 或 --all 参数后,可以一并清除所有未使用的镜像和悬空镜像。
4)可以添加 -f 或 --force 参数用以忽略相关告警确认信息。
5)指令结尾处会显示总计清理释放的空间大小。
以下命令可以现实所有的未挂载数据卷:
docker volume ls -f dangling=true
组合使用以下命令可以删除所有未挂载卷:
docker volume rm $(docker volume ls -qf dangling=true)
Dockerfile多阶段构建
多个 FROM 指令时,最后生成的镜像,仍以最后一条 FROM 为准,之前的 FROM 会被抛弃。最大的使用场景是将编译环境和运行环境分离。COPY 指令的`–from=builder 参数,从前边的阶段中拷贝文件到当前阶段中,多个FROM语句时,builder代表第一个阶段。
FROM golang:1.16 as builder
MAINTAINER hushuai
WORKDIR /usr/local/services/vlink_data
COPY . ./
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64
RUN go mod tidy
RUN go build -o bin/monitorServer ./main.go
FROM centos:7
WORKDIR /opt/vlink_data/server/
COPY --from=builder /usr/local/services/vlink_data/bin/monitorServer ./
EXPOSE 31654
CMD ./monitorServer -c prod.yaml
Dockerfile部署
创建容器APP
1、定义一个容器Dockerfile
①Dockerfile类似于Ansible的一键部署剧本
[root@kuang-76 ~]# mkdir test_dockerfile && cd test_dockerfile
[root@kuang-76 test_dockerfile]# vim Dockerfile
# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
2、创建APP内容
①创建APP本身
[root@kuang-76 test_dockerfile]# vim app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "<i>cannot connect to Redis, counter disabled</i>"
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>" \
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
②创建安装依赖的文件
[root@kuang-76 test_dockerfile]# vim requirements.txt
Flask
Redis
3、构建APP镜像
①构建APP镜像
[root@kuang-75 test_dockerfile]# docker build --tag=friendlyhello ./
②查看构建的镜像
[root@kuang-76 ~]# docker image ls
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
4、运行构建的APP
①映射端口运行APP
[root@kuang-76 ~]# docker run -p 4000:80 friendlyhello #使用CTRL+C退出
[root@kuang-76 ~]# docker run -d -p 4000:80 friendlyhello #后台运行
②访问APP服务
[root@kuang-76 ~]# curl 127.0.0.1:4000 #即可访问服务器的4000端口
<h3>Hello World!</h3><b>Hostname:</b> 8fc990912a14<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>
③查看运行的容器
[root@kuang-76 ~]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED
1fa4ab2cf395 friendlyhello “python app.py” 28 seconds ago
④关闭容器
[root@kuang-76 ~]# docker container stop 1fa4ab2cf395
docker-compose使用
1、YAML文件定义容器如何运行
①控制APP的该服务在容器内使用多少计算机资源
[root@kuang-76 ~]# vim docker-compose.yml
version: "3"
services:
web:
image: kuangzhilu/get-started:part2
deploy:
replicas: 5
resources:
limits:
cpus: "0.1"
memory: 50M
restart_policy:
condition: on-failure
ports:
- "4000:80"
networks:
- webnet
networks:
webnet:
②配置说明
起5个副本;限制每个实例最多能用0.1个CPU(如果1.5则是1.5个CPU);50M内存;
2、运行负载均衡APP
①初始化
[root@kuang-76 ~]# docker swarm init #设置为swarm管理节点
②部署服务
[root@kuang-76 ~]# docker stack deploy -c docker-compose.yml getstartedlab #起个名字为getstartedlab
③查看服务运行
[root@kuang-76 ~]# docker service ls #获取服务ID
[root@kuang-76 ~]# docker stack services getstartedlab #和上条命令效果一样
ID NAME MODE REPLICAS IMAGE PORTS
y0dztwq34ztd getstartedlab_web replicated 5/5 kuangzhilu/get-started:part2 *:4000->80/tcp
④查看某服务的所有进程(每个进程即一个任务task)
[root@kuang-75 ~]# docker service ps getstartedlab_web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
qnkf6smmro6e getstartedlab_web.1 kuangzhilu/get-started:part2 kuang-75 Running Running about a minute ago
upowki1lgwha getstartedlab_web.2 kuangzhilu/get-started:part2 kuang-75 Running Running about a minute ago
hbgnuvxzpkd4 getstartedlab_web.3 kuangzhilu/get-started:part2 kuang-75 Running Running about a minute ago
zqvr5vko32pb getstartedlab_web.4 kuangzhilu/get-started:part2 kuang-75 Running Running about a minute ago
hhe3c21kbl3c getstartedlab_web.5 kuangzhilu/get-started:part2 kuang-75 Running Running about a minute ago
⑤查看所有进程也可以查看服务进程(只是没有单独过滤服务进程,包含了其他进程)
[root@kuang-76 ~]# docker container ls -q #只能查看所有进程的ID
⑥验证负载均衡
[root@kuang-76 ~]# curl -4 http://localhost:4000 #不停使用该命令访问服务可看到效果
3、扩大APP规模
①修改YAML配置文件
[root@kuang-76 ~]# vim docker-compose.yml #编辑该文件,修改replicas副本即可
②重新YAML文件部署服务
[root@kuang-76 ~]# docker stack deploy -c docker-compose.yml getstartedlab #重新运行一次该命令即可
4、卸下APP和Swarm
[root@kuang-76 ~]# docker stack rm getstartedlab
[root@kuang-76 ~]# docker swarm leave --force
镜像操作
导入镜像
方法一通过本地加载方式导入镜像
[root@node1 ~]# docker load -i docker.io-nginx.tar
[root@node1 ~]# docker load -i docker.io-tianyebj-pod-infrastructure.tar
方法二直接通过pull方式下载
[root@node1 ~]# docker pull nginx
[root@node1 ~]# docker pull tianyebj/pod-infrastructure #众所周知的原因,不能从rhel官网上下载基础设施镜像,需要先登录DockerHub账号再去下载
修改pod-infrastructure的标签和kubelet中指定的一致
[root@node1 ~]# docker tag docker.io/tianyebj/pod-infrastructure registry.access.redhat.com/rhel7/pod-infrastructure:latest #修改镜像tag名称,需要和配置文件中保持一致,然后把原tag给删除
[root@node1 ~]# vim /etc/kubernetes/kubelet #在此配置文件当中指定了镜像名
KUBELET_POD_INFRA_CONTAINER=“–pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest”
推送镜像
①推送前需要登录Docker官网账号
[root@kuang-76 ~]# docker login
②给镜像打上标签
[root@kuang-76 ~]# docker tag friendlyhello kuangzhilu/get-started:part2 #格式为命名空间/repository:tag,推送时会自动推送到该命名空间里(这里你的用户名即命名空间)
③发布本地镜像
[root@kuang-76 ~]# docker push kuangzhilu/get-started:part2 #如果用户kuangzhilu中未创建get-started仓库,则该命令会自动创建,推送完就可以在自己的用户空间看到了
④拓展直接拉取并启动远程仓库
[root@kuang-76 ~]# docker run -p 4000:80 kuangzhilu/get-started:part2 #本地没找到该镜像,则会自动到Docker官网去拉取
buildx插件
使用buildx构建多架构的镜像
https://cloud.tencent.com/developer/article/2021645
网络
永久启动网络转发功能
需要开启转发功能,否则容器不通外网
[root@xuegod63 ~]# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
[root@xuegod63 ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@xuegod63 ~]# cat /proc/sys/net/ipv4/ip_forward
1
网桥操作
-
建立一个bridge模式的新网桥
docker network create --driver bridge --subnet=172.18.0.0/16 --gateway=172.18.0.1 new_bridge -
为容器添加某网卡并加入到某网桥中
docker network connect new_bridge test2
为test2 容器添加一块 new_bridge的 虚拟网卡,这样test2 上会 创建一个新的虚拟网卡,网段就是 新网桥设置的。如此就能互相ping通。
1、使用默认的桥接网络
①查看当前所有的网络
[root@kuang-76 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
c11cb1977079 bridge bridge local
48c78038e899 host host local
cf427a1da23c none null local
②启动两个alpine容器(即轻型linux)
[root@kuang-76 ~]# docker run -dit --name alpine1 alpine ash #默认也是运行ash,而不是bash
[root@kuang-76 ~]# docker run -dit --name alpine2 alpine ash
[root@kuang-76 ~]# docker container ls #确认容器都运行
③查看某个网络都有哪些容器连接进来
[root@kuang-76 ~]# docker network inspect bridge #没指定–network,默认连接到bridge
④连接并进入到一个容器
[root@kuang-76 ~]# docker attach alpine1 #使用exit退出时,会自动将容器关闭
# ip addr show
# ping -c 2 www.baidu.com #可以ping通
# ping -c 2 172.17.0.3 #可以ping通
⑤移除这两个容器
[root@kuang-76 ~]# docker container stop alpine1 alpine2
[root@kuang-76 ~]# docker container rm alpine1 alpine2
2、使用用户定义网桥
①创建自定义网桥
[root@kuang-76 ~]# docker network create --driver bridge alpine-net
[root@kuang-76 ~]# docker network ls #查看创建的网桥
②查看自定义网桥信息
[root@kuang-76 ~]# docker network inspect alpine-net #网桥相当于VM中的NAT模式,所以可以有多个
③创建相应容器
[root@kuang-76 ~]# docker run -dit --name alpine1 --network alpine-net alpine ash
[root@kuang-76 ~]# docker run -dit --name alpine2 --network alpine-net alpine ash
[root@kuang-76 ~]# docker run -dit --name alpine3 alpine ash
[root@kuang-76 ~]# docker run -dit --name alpine4 --network alpine-net alpine ash
[root@kuang-76 ~]# docker network connect bridge alpine4
[root@kuang-76 ~]# docker container ls #确认所有容器运行
④检查网络
[root@kuang-76 ~]# docker network inspect bridge
[root@kuang-76 ~]# docker network inspect alpine-net #目前1、2和4同在alpine-net网内,可以互相ping通,但只有4可以和3互通,1和2不能和3互通
⑤测试网络连通性
[root@kuang-76 ~]# docker container attach alpine1
[root@kuang-76 ~]# ping -c 2 alpine2 #像host主机一样,容器名字可以被解析
⑦alpine4是连接了两个网络,他的网络情况如何
alpine4去ping1和2可以直接使用容器名或者IP地址,而ping alpine3则必须使用IP地址
3、管理用户定义的桥
①创建和删除自定义桥
[root@kuang-76 ~]# docker network create my-net #创建
[root@kuang-76 ~]# docker network rm my-net #删除
②容器连接到用户定义的桥
[root@kuang-76 ~]# docker create --name my-nginx \
> --network my-net \
> --publish 8080:80 \
> nginx:latest
③启动该容器
[root@node1 ~]# docker container start 4a6e400f2509
容器网络和宿主机网络
找 docker 和 宿主机上 veth 设备的关系
但是可以查看 container 里的 eth0 网卡的 iflink 找到对应关系。
# 宿主机上
$ ip link
......
9: veth0e9cd8d@if8: mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 6a:fb:59:e5:7e:da brd ff:ff:ff:ff:ff:ff link-netnsid 1
# 容器内
$ sudo docker exec -it e151 bash
root@e1517e9d9e1a:/# cat /sys/class/net/eth0/iflink
9
这样就可以确定 container e1517e9d9e1a 在物理机上对应的 veth pair 是 veth0e9cd8d 了。
这种方式需要登录到 docker 里执行命令,不是所有的容器都能这么做,不过 github 上有人专门做了个脚本来用实现这个功能,可以参考一下:https://github.com/micahculpepper/dockerveth
容器启动资源分配
资源限制说明
内存限制相关的参数
执行docker run命令时能使用的和内存限制相关的所有选项如下。
选项 | 描述 |
---|---|
-m,–memory | 内存限制,格式是数字加单位,单位可以为 b,k,m,g。最小为 4M |
–memory-swap | 内存+交换分区大小总限制。格式同上。必须必-m设置的大 |
–memory-reservation | 内存的软性限制。格式同上 |
–oom-kill-disable | 是否阻止 OOM killer 杀死容器,默认没设置 |
–oom-score-adj | 容器被 OOM killer 杀死的优先级,范围是[-1000, 1000],默认为 0 |
–memory-swappiness | 用于设置容器的虚拟内存控制行为。值为 0~100 之间的整数 |
–kernel-memory | 核心内存限制。格式同上,最小为 4M |
CPU限制相关的参数
docker run命令和 CPU 限制相关的所有选项如下:
选项 | 描述 |
---|---|
–cpuset-cpus=“” | 允许使用的 CPU 集,值可以为 0-3,0,1 |
-c,–cpu-shares=0 | CPU 共享权值(相对权重) |
cpu-period=0 | 限制 CPU CFS 的周期,范围从 100ms~1s,即[1000, 1000000] |
–cpu-quota=0 | 限制 CPU CFS 配额,必须不小于1ms,即 >= 1000 |
–cpuset-mems=“” | 允许在上执行的内存节点(MEMs),只对 NUMA 系统有效 |
资源限制实例
1、容器启动基础配置
①给容器赋予host主机名
[root@kuang-75 ~]# docker run -it --name docker3 --hostname docker_kuang.cn centos bash
[root@docker_kuang /]# cat /etc/hostname
docker_kuang.cn
②给容器设置开机自启动
#注意:这里指的开机是Docker服务启动,只要Docker服务是运行的,该容器就运行
[root@kuang-73 ~]# docker run --restart=always -itd --name test666 centos bash
③测试开机自启动
[root@kuang-75 ~]# systemctl restart docker #重启Docker,其他容器都关闭了,就test666容器依然运行
④拓展Docker容器的重启策略
no,默认策略,在容器退出时不重启容器
on-failure,在容器非正常退出时(退出状态非0),才会重启
on-failure,在容器非正常退出时重启容器,最多重启3次(怕容器坏了,一直起不来,浪费资源)
always,在容器退出时总是重启容器
unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
⑤更新Docker容器的重启策略
[root@kuang-73 ~]# docker update --restart=unless-stopped test666 #还可以更新其他策略,并且可以更新运行中的容器的策略
2、对各容器的CPU分配限制
①默认都是1024,每个容器按照它的份额,获取可使用的CPU的时间片
[root@kuang-73 ~]# docker run -it --cpu-shares 512 centos bash
[root@04af4b570b7d /]# cat /sys/fs/cgroup/cpu/cpu.shares
512
[root@kuang-73 ~]# cat /sys/fs/cgroup/cpu/cpu.shares #Linux主机也有这一项
1024
②另外一种固定的分配限额模式
[root@kuang-73 ~]# docker run -it --cpu-period 1000000 --cpu-quota 200000 centos /bin/bash #每1000000微秒对容器重新分配,在这个周期内最多只能获取200000微秒的时间片,这种分配方式没有弹性
③限制使用的CPU内核
[root@kuang-73 ~]# docker run -it --name cpu1 --cpuset-cpus 0-2 centos #只给3个内核使用
[root@4f142f15c6f7 /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus #默认情况是0-3
0-2
3、拓展实现两个进程争夺CPU资源现象
#实现原理:让两个进程绑定到同一个CPU上,然后对CPU做压测。然后使用stress让CPU做任意随机数的平方根
#方法:创建两个容器:docker10和docker20。让docker10和docker20只运行在cpu0和cpu1上,最终测试一下docker10和docker20使用cpu的百分比。
①分别运行两个Docker容器,并指定相同CPU内核
[root@kuang-73 ~]# docker run -itd --name docker10 --cpuset-cpus 0,1 --cpu-shares 512 centos /bin/bash
[root@kuang-73 ~]# docker run -itd --name docker20 --cpuset-cpus 0,1 --cpu-shares 1024 centos /bin/bash
②各自安装上压测工具stress,并进行压测
[root@caaa74d5b0d3 /]# yum -y install epel-release
[root@caaa74d5b0d3 /]# yum -y install stress
[root@b514e5da1ff8 /]# stress -c 2 -v -t 10m #运行压力测试,选项v显示详情
#拓展zabbix中介绍的一个压测方法
[root@caaa74d5b0d3 /]# cat /dev/urandom | md5sum #对随机数进行求md5,多运行几个
③host主机上查看CPU使用率
[root@kuang-75 ~]# top #按1显示所有CPU内核使用率
top内还能看到每个进程(即容器)占用的CPU内核使用率
4、当容器命令运行结束后,自动删除容器释放资源
#应用场景:在某些环境下,可能需要大量的新建docker实例,然后仅仅运行几分钟或几秒钟,就彻底删除,比如运行单元测试或测试弹性云计算。
#举例:阿里云,要模拟双11的压力,需要快速创建1万docker实例,每个docker容器实例中都运行ab命令,拼命访问tmall.com首页,运行1个小时,1个小时后自动删除
[root@kuang-73 ~]# docker run -it --rm --name mk centos sleep 5 #5秒后自动删除容器
5、Docker容器资源配置控制内存
[root@kuang-73 ~]# docker run -it -m 128M centos bash #给容器限额128M的内存
[root@9737df65bcb1 /]# cat /sys/fs/cgroup/memory/memory.limit_in_bytes
134217728
[root@9737df65bcb1 /]# cat /sys/fs/cgroup/memory/memory.usage_in_bytes
950272
6、Docker数据目录映射
①当容器坏了,数据还在物理机上,重新起一个容器就可以了
[root@kuang-73 ~]# docker run -it --name web1 -v /var/www/html/:/var/www/html centos bash #前面是host主机的目录,后面是容器的目录
[root@262fe04d4e5d /]# echo aaa > /var/www/html/index.html
[root@kuang-73 ~]# ls /var/www/html/ #在物理机上查看还在,是同步的
index.html
7、Docker容器资源配额控制IO
①启动一个限速容器
[root@kuang-73 ~]# docker run -it -v /var/www/html/:/var/www/html --device /dev/sda:/dev/sda --device-write-bps /dev/sda:1mb centos /bin/bash #因为容器一般没有sda这个设备的,所以要映射出一个这样的设备,然后做限速(1M每秒)
②测试容器IO速率
[root@a10be8c46a16 /]# time dd if=/dev/sda of=/var/www/html/test.out bs=1M count=10 oflag=direct,nonblock #direct:读写数据采用直接IO方式,不走缓存,直接从内存写硬盘。nonblock:读写数据采用非阻塞IO方式,优先写dd命令数据,避免其他使用IO进程的干扰
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 10.008 s, 1.0 MB/s
real 0m10.014s
user 0m0.002s
sys 0m0.017s