【Docker】实践心得

154 阅读3分钟

了解了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等方式。