了解了Docker是一个什么东西,基于什么原理之后,不免要尝试一番。涉及实践,就必须要考虑诸如安装、运行、镜像管理、持久化存储、监控、日志等等方面了,下面一一说来。
更新日志
2022-08-17 初稿 2022-10-21 添加了存储引擎的坑
安装
软件安装
参照Docker官网的安装文档,建议妥善选择和发行版匹配且较新的Docker版本,我一般安装默认的推荐版本,有问题再记录和更换。
register配置
官方默认的仓库是hub.docker.com,由于在海外,访问速度很慢,可以换成国内的源,修改或创建文件/etc/docker/daemon.json
{
"registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
这里的https://xxxx.mirror.aliyuncs.com换成你找到的docker hub源地址
daemon.json
20.10版本的daemon.json示例
{
"allow-nondistributable-artifacts": [],
"api-cors-header": "",
"authorization-plugins": [],
"bip": "",
"bridge": "",
"cgroup-parent": "",
"cluster-advertise": "",
"cluster-store": "",
"cluster-store-opts": {},
"containerd": "/run/containerd/containerd.sock",
"containerd-namespace": "docker",
"containerd-plugin-namespace": "docker-plugins",
"data-root": "", # Docker运行时使用的根路径,根路径下的内容稍后介绍,默认/var/lib/docker
"debug": true, # 启用debug的模式,启用后,可以看到很多的启动信息。默认false
"default-address-pools": [
{
"base": "172.30.0.0/16",
"size": 24
},
{
"base": "172.31.0.0/16",
"size": 24
}
],
"default-cgroupns-mode": "private",
"default-gateway": "",
"default-gateway-v6": "",
"default-runtime": "runc",
"default-shm-size": "64M",
"default-ulimits": {
"nofile": {
"Hard": 64000,
"Name": "nofile",
"Soft": 64000
}
},
"dns": [],
"dns-opts": [],
"dns-search": [],
"exec-opts": [],
"exec-root": "",
"experimental": false,
"features": {},
"fixed-cidr": "",
"fixed-cidr-v6": "",
"group": "",
"hosts": [], # 设置监听地址端口和文件
"icc": false,
"init": false,
"init-path": "/usr/libexec/docker-init",
"insecure-registries": [], # 私库
"ip": "0.0.0.0",
"ip-forward": false,
"ip-masq": false,
"iptables": false,
"ip6tables": false,
"ipv6": false,
"labels": [],
"live-restore": true,
"log-driver": "json-file",
"log-level": "",
"log-opts": {
"cache-disabled": "false",
"cache-max-file": "5",
"cache-max-size": "20m",
"cache-compress": "true",
"env": "os,customer",
"labels": "somelabel",
"max-file": "5",
"max-size": "10m"
},
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"max-download-attempts": 5,
"mtu": 0,
"no-new-privileges": false,
"node-generic-resources": [
"NVIDIA-GPU=UUID1",
"NVIDIA-GPU=UUID2"
],
"oom-score-adjust": -500,
"pidfile": "",
"raw-logs": false,
"registry-mirrors": [],
"runtimes": {
"cc-runtime": {
"path": "/usr/bin/cc-runtime"
},
"custom": {
"path": "/usr/local/bin/my-runc-replacement",
"runtimeArgs": [
"--debug"
]
}
},
"seccomp-profile": "",
"selinux-enabled": false,
"shutdown-timeout": 15,
"storage-driver": "",
"storage-opts": [],
"swarm-default-advertise-addr": "",
"tls": true,
"tlscacert": "",
"tlscert": "",
"tlskey": "",
"tlsverify": true,
"userland-proxy": false,
"userland-proxy-path": "/usr/libexec/docker-proxy",
"userns-remap": ""
}
存储引擎
docker官方推荐使用overlay2, daemon.json中配置"storage-driver": "overlay2",即可,如果无法启动,可以排查docker的存储目录分区是否为xfs格式,d_type是否为true。查看方式:
$ xfs_info /opt
meta-data=/dev/mapper/centos-opt isize=256 agcount=4, agsize=6553344 blks
= sectsz=512 attr=2, projid32bit=1
= crc=0 finobt=0
data = bsize=4096 blocks=26213376, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal bsize=4096 blocks=12799, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
注意,ftype=1
格式化命令选项
mkfs.xfs -n ftype=1 /dev/mapper/centos-opt
运行
启动dockerd daemon
一般使用systemd管理docker.service,配置改完之后直接启动systemctl start docker
启动容器
docker服务启动之后,就可以启动docker容器了,经典命令docker run hello-world。
一般启动容器要用到的几个参数:
- -d 容器后台运行
- -p hostPort:containerPort 端口映射
- -v hostPath:containerPath 目录挂载
- --name containerName 容器命名
- -e key=value 环境变量定义
- --add-host host:ip 主机名定义
- --entrypoint path 覆盖默认的entrypoint,优先级比cmd高,启动容器命令格式:entrypoint cmd,一般entrypoint类似/bin/bash; cmd 类似 ls /etc/hosts。entrypoint也可以执行所有命令,但不是推荐做法。
- imageName:tag 启动哪个镜像和tag,必须
- cmd 覆盖默认的启动命令和参数
镜像管理
如果仅仅是测试docker,测试机本地docker daemon自带的镜像管理就足够了。但是,在公司内网业务使用的情况下,一般是需要部署私有镜像仓库的,原因在于安全考虑、访问速度、合规政策等。
现有的开源镜像仓库Harbor足以满足中小企业的日常用途,如何安装搭建这里忽略,使用方法和官网的hub.docker.com类似。
持久化存储
容器启动后,变更的数据,例如配置变更、数据变更,日志,会随着容器的删除而消失,要持久化存储这些数据,需要将其存储到容器镜像之外才行,例如使用-v挂载,数据写入宿主机;数据写入数据库;日志传给elasticsearch。下面讲讲本地目录挂载的场景:
- 单机场景,直接使用
-v参数挂载本地目录到容器中,然后持久化数据写入该目录,避免容器删除后数据也被删掉了。 - 多机场景,如果各自挂载各自的,参照单机场景,如果有文件需要通过本地路径共享,则需要借助共享存储,每台服务器上挂载该共享存储路径,并在docker启动时使用
-v参数挂载进容器。 - 容器云场景,例如Kubernetes等容器云使用共享存储时,可以参照多机场景,每个k8s node节点挂载共享存储,然后pod上做hostPath挂载到容器中。当然,这种做法比较粗暴,优雅的做法是使用容器云的存储插件,例如kubernetes的pv,pvc来进行持久化存储和共享存储。
监控
容器是做了隔离和限制的进程,监控容器实际上就是监控进程。
- docker ps可以查看容器列表
- docker stats container 可以查看容器的实时CPU, 内存,IO
- docker inspect container 可以查看容器的底层参数详情
- docker top container 可以查看容器中正在运行进程的情况,类似命令ps -ef
还有一些容器监控程序,例如promethues, 需要额外安装,这里暂不讨论。
查看pid是属于哪个docker容器,可用于在宿主机上查找异常的容器,例如内存占用过高、文件打开数过多的容器
docker inspect -f "{{.Id}} {{.State.Pid}} {{.Config.Hostname}}" $(docker ps -q) | grep PID
日志
Docker推荐以前台的方式运行容器中的主程序,主程序的标准输出和错误输出,直接打印到容器的console中。实际应用中,也可以将日志文件写入到挂载的目录中,以便自行管理日志的分类、切割、收集等。
容器后台运行后,console的日志会存储到docker安装目录下的containers/{containerID}目录下。如果使用docker logs container命令,查看到的就是这个文件的内容。
容器云场景下,容器所处的宿主机飘忽不定,且存在多副本,日志的输出和采集,更加复杂。可以考虑直接输出到数据库、es、logstash、本地+filebeat等方式。