n1.Docker容器安装运行所遇异常解决

2022-09-28 19:50:02 浏览数 (1)

[TOC]

0x00 Docker 目录与路径

CentOS7:默认的Docker安装目录以及配置文件

代码语言:javascript复制
# Systemctl 启动项参数
/etc/systemd/system/docker.service
/usr/lib/systemd/system/docker.service

# Docker 元数据目录
/var/lib/docker

# Docker Deamon启动项
/etc/sysconfig/docker

# Docker daemon.json 参数
/etc/docker/daemon.json
/root/.docker/config.json

Ubuntu:snap安装的Docker

代码语言:javascript复制
# 全局配置
/var/snap/docker
/var/snap/docker/current/  # docker 启动配置
config/ etc/  run/

# 用户配置
/root/snap/docker

0x01 常规基础配置

.Docker日志设置定期清理 1) 设置容器为3个日志文件容,分别是id .json、id 1.json、id 2.json,但是此时只对新建的容器有效;

代码语言:javascript复制
cat > /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://kfwkfulq.mirror.aliyuncs.com",
"https://2lqq34jg.mirror.aliyuncs.com",
"https://pee6w651.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com"
],
  "dns": ["114.114.114.114","8.8.4.4"],
  "log-driver":"json-file",
  "log-opts":{ "max-size" :"100m","max-file":"1"},
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64"
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

2) 清理已存在的容器日志(全部容器)

代码语言:javascript复制
#容器日志一般存放在/var/lib/docker下面
ls -lh $(find /var/lib/docker/containers/ -name *-json.log)

#方法1:
find /var/lib/docker/containers/ -name *-json.log -exec truncate -s 0 {} ;

#方法2:(已经停止的容器)
find /var/lib/docker/containers/ -name *-json.log -exec cat /dev/null > {} ;

如果docker容器正在运行,那么使用rm -rf 方式删除日志后,通过df -h会发现磁盘空间并没有释放;

原因:在Linux或者Unix系统中,通过rm或者文件管理器删除文件将会从文件系统的目录结构上解除链接(unlink).然而如果文件是被打开的(有一个进程正在使用),那么进程将仍然可以读取该文件,磁盘空间也一直被占用

1.如何进行 Docker 默认存储位置修改?

描述:默认情况下Docker的存放位置为 /var/lib/docker , 具体的位置可以通过sudo docker info | grep "Docker Root Dir"查看。

方式1:通过软连接来实现,启动Docker时发现存储目录依旧是/var/lib/docker但是实际上是存储在数据盘的(容量变化)。

代码语言:javascript复制
systemctl stop docker
#方式1.软连接
mv /var/lib/docker /disk/docker
ln -s /disk/docker /var/lib/docker  #目标 软连接

#方式2.打包docker目录 
sudo tar -czvf /usr/docker.tar.gz docker/
cd /disk/ && sudo tar -xzvf docker.tar.gz

方式2:改镜像和容器的存放路径即我们需要修改配置文件指定启动参数即可,指定镜像和容器存放路径的参数是--graph=/var/lib/docker,由于在docker.service中加载下面到环境变量中,最后一张图即可明了(可将下面几种方式看作一种)

代码语言:javascript复制
#(1)注意:发行版本的异同,修改后重启即可
Ubuntu: /etc/default/docker
OPTIONS='--graph="/disk/docker" -H fd://'  # 或者DOCKER_OPTS="-g /disk/docker"

CentOS6: /etc/sysconfig/docker
OPTIONS='--graph="/disk/docker" --selinux-enabled -H fd://'

#(2) 配置文件位置(不推荐此种方式)
#/usr/lib/docker-storage-setup/docker-storage-setup或者/etc/sysconfig/docker-storage-setup、/etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS=--graph="要保存的路径"
#限制性默认值,例如100GB最大存储空间。
DATA_SIZE=800GB #更改docker默认存储大小


#实际上都是依托于下述文件的加载我们可以直接在ExecStart启动中指定docker挂的存储位置所以看作一种修改方式);
CentOS7: /usr/lib/systemd/system/docker.service  
EnviromentFile=-/etc/sysconfig/docker
Environment=GRAPH=/disk/docker
ExecStart=/usr/bin/dockerd --graph=/disk/docker $GRAPH $OPTIONS 
systemctl daemon-reload           # reload配置文件  
systemctl restart docker.service  # 重启docker

WeiyiGeek.docker

方式4:如果docker是1.12或以上的版本可以修改(或新建)/etc/docker/daemon.json文件 该方式的优点修改后会立即生效,不需重启docker服务。

代码语言:javascript复制
vim /etc/docker/daemon.json 
{"registry-mirrors": ["http://7e61f7f9.m.daocloud.io"],"graph": "/disk/docker"}
2.如果进行容器日志文件的分割?

描述:除了docker image 时间长了会占用大量磁盘空间外,容器在运行时大量写日志也是个很头疼的问题,而且在没有任何监控预警的情况下业务随时都会宕掉(至少我遇到过1次)。

默认情况下(JSON File logging drive ),Docker捕获所有容器的标准输出(和标准错误),并使用JSON格式将其写入文件中,对于应用的标准输出(stdout)日志,Docker Daemon 在运行这个容器时就会创建一个协程(goroutine),负责标准输出日志。 由于此 goroutine 绑定了整个容器内所有进程的标准输出文件描述符,因此容器内应用的所有标准输出日志都会被 goroutine 接收并写入与此容器—对应的日志文件中,即日志文件位于/var/lib/docker/containers/<container_id>/文件名为-json.log

Docker 则通过 docker logs 命令向用户提供日志接口,其实现原理的本质均基于与容器一一对应的-json.log,(kubectl logs类似)

WeiyiGeek.goroutine

针对日志文件过大的几种解决办法:

堵: 限定一个容器最多使用多少磁盘空间;

代码语言:javascript复制
#docker的storage-driver是overlay2时,限制单个容器可占用的磁盘空间
- 1.xfs,linux 文件系统 CentOS 7开始,预设的文件系统由原来的EXT4变成了XFS文件系统
- 2.pquot(project quotas )SystemXFS支持按用户、组和项目设置磁盘配额。项目磁盘配额允许您限制单个目录层次结构上的磁盘空间数量。
# mount 时 指定文件系统类型,使用-o enbale project quotas
mount –o prjquota /dev/xvdb1 /xfs
# 限定 project=test 的 /data 目录 soft limit=5M hard limit=6M
xfs_quota –x –c 'limit –p bsoft=5m bhard=6m test' /data

疏: 以特定用户运行项目,该容器内用户只可以访问特定的文件夹,比如/logs,然后将容器/logs 映射到物理机上,定时清理;

监控: 时监控磁盘,异常时报警;执行docker system df -v可以列出每个容器占用的 磁盘空间,当期大小超过一定阈值时,可以根据container id(想办法将container id 与应用信息关联起来)将其删除

代码语言:javascript复制
(1)Images space usage:
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE                SHARED SIZE         UNIQUE SIZE         CONTAINERS
onlyoffice/documentserver   latest              d06214a03e27        2 months ago        2.145GB             0B                  2.145GB             1

(2)Containers space usage:
CONTAINER ID        IMAGE                       COMMAND                  LOCAL VOLUMES       SIZE                CREATED             STATUS                NAMES
d415211e52da        onlyoffice/documentserver   "/bin/sh -c /app/ds/…"   6                   986MB               4 weeks ago         Up 3 days             onlyoffice

(4)Local Volumes space usage:
VOLUME NAME                                                        LINKS               SIZE
a4974599165f539b98fd57fc53ccc073a7e8cdf4cd36cbc5e349fb8d4f6a1325   0                   2.51MB

(5)Build cache usage: 0B
CACHE ID            CACHE TYPE          SIZE                CREATED             LAST USED           USAGE               SHARED

日志由日志采集工具收集,不在磁盘上停留;

实操解决:

代码语言:javascript复制
#示例1.清空停止的容器以及卷包括日志/容器/网络/镜像(以释放空间-尽量在缺订需要的容器)
docker system prune -af
# Deleted Containers:
# 9c8a4f60ad62cee63c7d5b48041e29363ee4f839aedb2cec9a76df3e6ccda2e8
# 2d5cca572c06e11a6a2005cd46d154b71bad151610ce074424a32850aedb2b39
# 8c78c868d29285afeb00eb617d0a8e3280b6da2f69bf8dd42e04a8e334d3ae22

# Deleted Networks:
# blog_default

# Deleted Images:
# untagged: snipe/snipe-it:latest
# untagged: snipe/snipe-it@sha256:7a61e8a407490b9e99c758a18ba814c10fe55f1465e036bfd1ee5445537c7661
# Total reclaimed space: 1.096GB

#示例2./etc/docker/daemon.json 经创建了的容器该选项的修改【重启daemon】是无法生效的,只对新建立的容器有效;
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"}

docker inspect -f '{{.HostConfig.LogConfig}}' test1
# {json-file map[max-file:10 max-size:2m]}
more /var/lib/docker/containers/25d2d645bfc9e6530039d6aac890f69dd9af33f8f966adc2d7287b74964678e3/25d2d645bfc9e6530039d6aac890f69dd9af33f8f966adc2d7287b74964678e3-json.log
# {"log":"Mem: 3164836K used, 696576K free, 45448K shrd, 2104K buff, 1633504K cachedn","stream":"stdout","time":"2020-06-18T03:34:33.738111441Z"}
# {"log":"CPU:   0% usr   0% sys   0% nic 100% idle   0% io   0% irq   0% sirqn","stream":"stdout","time":"2020-06-18T03:34:33.73833528Z"}
# {"log":"Load average: 0.16 0.20 0.19 1/639 5n","stream":"stdout","time":"2020-06-18T03:34:33.738342617Z"}


#示例3.将每个容器可以使用的磁盘空间设置为1G:
{
  "data-root": "/data/docker",
  "storage-driver": "overlay2",
  "storage-opts": [
  "overlay2.override_kernel_check=true",
  "overlay2.size=1G"
  ],
}

# 示例4.清理日志文件
# 通过rm -rf或者文件管理器删除文件,将会从文件系统的目录结构上解除链接(unlink)前提是容器是停止的状态,否则如果该文件被进程占用,磁盘空间也一直被占用。
cat /dev/null >/var/lib/docker/containers/<container_id>/containerid-json.log
3.如何配置Docker Deamon能被Docker Client远程链接?

答: 我们需要在docker.service配置文件中进行更改dockerd的启动参数中添加-H tcp://0.0.0.0:2375

代码语言:javascript复制
# 修改启动参数
nano /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375

# 重载守护进程与重启docker
systemctl daemon-reload
systemctl restart docker

# 查看监听情况
netstat -tlnp
# Active Internet connections (only servers)
# Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
# tcp6       0      0 :::2375                 :::*                    LISTEN      11389/dockerd

# 简单验证远程访问
curl http://127.0.0.1:2375/containers/json | jq
[
  {
    "Id": "25d2d645bfc9e6530039d6aac890f69dd9af33f8f966adc2d7287b74964678e3",
    "Names": [
      "/test1"
    ],
    "Image": "test1",
    "ImageID": "sha256:5ec0e2b89f7aadb6178c17b3db73aba2e209f9556a436562de7f32b077b776bd",
    "Command": "top -b -d 2",
    "Created": 1592451272,
    "Ports": [],
    "Labels": {
      "Author": "WeiyiGeek",
      "Description": "Test Dockerfile"
    },
    "State": "running",
    "Status": "Up 35 minutes",
    "HostConfig": {
      "NetworkMode": "default"
    },
    "NetworkSettings": {
      "Networks": {
        "bridge": {
          "IPAMConfig": null,
          "Links": null,
          "Aliases": null,
          "NetworkID": "257f6a8500710d76efba6a1c9be8c0f10b4308afb481baf1e9ba77cf98f596bd",
          "EndpointID": "ac4518815359da7b8182167dfeeec728c0ea51accd1736719005f1596797e944",
          "Gateway": "172.17.0.1",
          "IPAddress": "172.17.0.2",
          "IPPrefixLen": 16,
          "IPv6Gateway": "",
          "GlobalIPv6Address": "",
          "GlobalIPv6PrefixLen": 0,
          "MacAddress": "02:42:ac:11:00:02",
          "DriverOpts": null
        }
      }
    },
    "Mounts": []
  }
]

WeiyiGeek.Dockerd-TCP

4.修改正在运行的容器其映射端口?

描述:正在运行的容器修改其映射端口的方式推荐方式2与方式3,端口修改;

方式1:停止并删除该容器然后新建立一个全新容器(最简单方案,在测试环境中常常使用一下)

方式2:利用docker commit新构镜像把一个容器的文件改动和配置信息commit到一个新的镜像,然后用这个新的镜像重起一个容器,该方法的优点是该方式不会对宿主机上的其它容器有任何影响;

代码语言:javascript复制
docker stop container01
docker commit container01 new_image:tag
docker run --name container02 -p 80:80 new_image:tag

方式3:修改容器配置文件然后重启docker服务即可

优点:是没有副作用,操作简单

缺点:是需要停止容器以及重启docker服务,如果在同一个宿主机上运行着多个容器服务的话,就会影响其他容器服务。

代码语言:javascript复制
$nano /var/lib/docker/containers/d415211e52da6ca66aeee3c81b38be609ffac59522b06e0ff9fa253e29fa441a/hostconfig.json
#将需要映射的端口,按照以下json格式进行设置
"PortBindings":{
  "443/tcp":[{"HostIp":"","HostPort":"9000"}],
  "80/tcp":[{"HostIp":"","HostPort":"9001"}]
}

$ docker stop onlyoffice
$ systemctl restart docker && docker start onlyoffice
$ docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                             PORTS                                                 NAMES
d415211e52da        onlyoffice/documentserver   "/bin/sh -c /app/ds/…"   43 minutes ago      Up 14 seconds                      0.0.0.0:9001->80/tcp, 0.0.0.0:9000->443/tcp           onlyoffice
5.本地的镜像文件都存放在哪里?

答:与 Docker 相关的本地资源默认存放在 /var/lib/docker/ 目录下,默认以 overlay2 文件系统为例 其中 container 目录存放容器信息,graph 目录存放镜像信息,aufs 目录下存放具体的镜像层文件。

代码语言:javascript复制
$ll /var/lib/docker/image/overlay2/distribution/diffid-by-digest/sha256/
总用量 16
-rw-r--r-- 1 root root 71 6月   4 15:15 3c78d525c5d6e0101e4f53d5e4ee827c838b9d346f44e40db49c66638040d980
-rw-r--r-- 1 root root 71 6月   4 15:15 44559339aea968e196d4930b3d79068926964f415c0fccd3e1b197a5dd928ee7
6.如何给容器指定一个固定 IP 地址,而不是每次重启容器 IP 地址都会变?_

答:自定义建立网络设置固定的子网以及容器固定IP

代码语言:javascript复制
$ docker network create -d bridge --subnet 172.25.0.0/16 my-net
$ docker run --network=my-net --ip=172.25.3.3 -itd --name=my-container busybox
7.修改已创建的镜像或者正在运行的容器中存储挂载的路径?

描述:修改已经创建的镜像或者正在运行的容器中的新挂载的路径相关操作流程; 流程如下:

代码语言:javascript复制
#1.停止docker容器和服务
sudo docker stop $(docker ps -a | awk '{ print $1}' | tail -n  2)
sudo service docker stop

#2.备份容器配置文件 
cd /var/lib/docker/containers/de9c6501cdd3
cp hostconfig.json{,.bak}
cp config.v2.json{,.bak}

#3.修改hostconfig的冒号前的配置路径 
cat -n hostconfig.json | grep -C 5 "Binds"

#4.修改config的Source的配置路径 
cat config.v2.json
"MountPoints": {
  "/etc/mysql/my.cnf": {
  "Source": "/home/server/mysql/conf/my.cnf",
  "Destination": "/etc/mysql/my.cnf",
  "RW": true,
  "Name": "",
  "Driver": "",
  "Relabel": "",
  "Propagation": "rprivate",
  "Named": false,
  "ID": ""
},....


#5.然后启动docker服务即可
8.如何进入 Docker 容器的网络命名空间?

描述:Docker 在创建容器后删除了宿主主机上 /var/run/netns 目录中的相关的网络命名空间文件。 因此,在宿主主机上是无法看到或访问容器的网络命名空间的。

代码语言:javascript复制
#以下操作可以查看并设置网络命名空间
$ docker inspect --format='{{. State.Pid}} ' $container_id  #获取容器进程ID
1234
$ sudo ln -s /proc/1234/ns/net /var/run/netns/ #在proc目录下把对应的网络命名空间文件链接到 /var/run/netns 目录。
#然后,在宿主主机上就可以看到容器的网络命名空间信息。例如**
$ sudo ip netns show
1234

#设置操作容器的命名空间
$ sudo ip netns exec 1234 ifconfig eth0 172.17.0.100/16
9.如何重置 Docker 本地数据?

$ sudo rm -rf /var/lib/docker #注意本操作会移除所有的 Docker 本地数据,包括镜像和容器等。


0x02 入坑出坑

报错问题0:requires containerd.io >= 1.2.2-3, but none of the providers can be installed 环境:CentOS 8 1911(Core) 错误问题:

代码语言:javascript复制
package docker-ce-3:18.09.9-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but none of the providers can be installed
  - conflicting requests
  - package containerd.io-1.2.10-3.2.el7.x86_64 is excluded
  - package containerd.io-1.2.13-3.1.el7.x86_64 is excluded
  - package containerd.io-1.2.2-3.3.el7.x86_64 is excluded
  - package containerd.io-1.2.2-3.el7.x86_64 is excluded
  - package containerd.io-1.2.4-3.1.el7.x86_64 is excluded
  - package containerd.io-1.2.5-3.1.el7.x86_64 is excluded
  - package containerd.io-1.2.6-3.3.el7.x86_64 is excluded
(尝试添加 '--skip-broken' 来跳过无法安装的软件包 或 '--nobest' 来不只使用最佳选择的软件包)

解决方法:

1)要么就降低docker 的版本

2)如果不想降低docker 版本,那么就更新 containerd.io 的版本

代码语言:javascript复制
yum install -y wget
wget https://download.docker.com/linux/centos/7/x86_64/edge/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
yum install -y containerd.io-1.2.6-3.3.el7.x86_64.rpm
yum install docker-ce docker-ce-cli

报错问题1:Error running DeviceCreate (createSnapDevice) dm_task_run failed 错误信息:

代码语言:javascript复制
docker:Error running DeviceCreate (createSnapDevice) dm_task_run failed

解决办法: 重新构建资源池元数据即可,https://stackoverflow.com/questions/30719896/docker-dm-task-run-failed-error

代码语言:javascript复制
#不同安装路径可能不同
service docker stop
thin_check /var/lib/docker/devicemapper/devicemapper/metadata
thin_check --clear-needs-check-flag /var/lib/docker/devicemapper/devicemapper/metadata
service docker start

报错问题2:Error response from daemon: devmapper: Error mounting: invalid argument 错误信息:

代码语言:javascript复制
docker start e7e
Error response from daemon: devmapper: Error mounting '/dev/mapper/docker-253:4-11534337-ee772425c4996ca581e5c234806adf41aede9424a83ce1402596105a9f66434d' on '/export/docker/devicemapper/mnt/ee772425c4996ca581e5c234806adf41aede9424a83ce1402596105a9f66434d': invalid argument

错误原因:因为selinux enable的时候,创建了该容器。而后修改了/etc/selinux/config 修改成selinux为disabled。

物理机重启后selinux处于关闭状态,则原先在selinux enable时候创建的容器就会无法启动报出这种错误。

修复方法:

代码语言:javascript复制
主要有两种:
1.可以将selinux重新置为enable然后重启物理机即可修复。
2.修改容器的配置,比如我的容器的配置是/var/lib/docker/containers/e7ef71494940ba293be4b3f74198bf34835c35537810053b051d9a6c33adbd32/config.v2.json文件。将其中的"MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c12,c257", "ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c12,c257"重修修改为"MountLabel": "", "ProcessLabel": "",然后重新启动docker daemon,容器即可修复。

报错问题3: Error response from daemon: devmapper: Thin Pool has 155398 free data blocks which is less than minimum required 163840 free data blocks. 错误信息:

代码语言:javascript复制
/usr/bin/docker-current: Error response from daemon: devmapper: Thin Pool has 155398 free data blocks which is less than minimum required 163840 free data blocks. Create more free space in thin pool or use dm.min_free_space option to change behavior

解决办法:

代码语言:javascript复制
sudo docker rm $(sudo docker ps -q -f status=exited)
sudo docker volume rm $(sudo docker volume ls -qf dangling=true)
sudo docker rmi $(sudo docker images --filter "dangling=true" -q --no-trunc)

报错问题4:[graphdriver] prior storage driver ”devicemapper” failed: devmapper: Base Device UUID and Filesystem verification failed: devmapper: Current Base Device 运行环境: CentOS 7.3.1611 , Docker Version 1.12.6-16.el7.centis.x86_64 , API 1.24; 报错信息:

代码语言:javascript复制
#Docker 启动报错
docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/docker.service.d
           └─flannel.conf
  Process: 5226 ExecStart=/usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current $OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS $ADD_REGISTRY $BLOCK_REGISTRY $INSECURE_REGISTRY (code=exited, status=1/FAILURE)
 Main PID: 5226 (code=exited, status=1/FAILURE)
#错误关键点
dockerd-current[5226]: time="..." level=info msg="libcontainerd: new containerd process, pid: 5238"
dockerd-current[5226]: time="..." level=warning msg="devmapper: Usage of loopback devices is strongly discouraged for production use. Please use `--storage-opt dm.thinpooldev` or use `man docker` to refer to dm.thinpooldev section."
node-198 dockerd-current[5226]: time="2020-01-18T17:00:27.872191345 08:00" level=error msg="[graphdriver] prior storage driver "devicemapper" failed: devmapper: Base Device UUID and Filesystem verification failed: devmapper: Current Base Device UUID:59df6192-df22-4d88-9e90-02755e7e3242 does not match with stored UUID:24907e3f-5114-4948-91ea-c1a4e92854ef. Possibly using a different thin pool than last invocation"
node-198 dockerd-current[5226]: time="2020-01-18T17:00:27.872410561 08:00" level=fatal msg="Error starting daemon: error initializing graphdriver: devmapper: Base Device UUID and Filesystem verification failed: devmapper: Current Base Device UUID:59df6192-df22-4d88-9e90-02755e7e3242 does not match with stored UUID:24907e3f-5114-4948-91ea-c1a4e92854ef. Possibly using a different thin pool than last invocation"

错误原因:由于存放Docker的Metadata磁盘是挂载上来的,在某次关机的时候存储异常关闭在解决后机器挂载上远程的NFS磁盘,在挂载后磁盘的UUID发生变化,导致通过loopback的方式不能连接到Docker的DeviceMapper的存储池;

解决方法:查看实际的loop0的uuid并且修改deviceset-metadata中的UUID

代码语言:javascript复制
#查看系统磁盘UUID
$ls -alh /dev/disk/by-uuid
$blkid
#59df6192-df22-4d88-9e90-02755e7e3242

#常规路径
/var/lib/docker/devicemapper/metadata/deviceset-metadata
#自定义的路径
/disk/docker/devicemapper/metadata/deviceset-metadata
#内容设置
{"next_device_id":1,"BaseDeviceUUID":"59df6192-df22-4d88-9e90-02755e7e3242","BaseDeviceFilesystem":"xfs"}

注意事项:

  • 目前docker支持的存储驱动类型有aufs/Device mapper/btrfs/overlayfs和zfs并且都采用写时复制(CoW)的技术,但是在CentOS上默认不支持aufs;
  • 注意:Docker使用的Devicemapper存储驱动的默认模式是loopback的方式,但是它的性能和稳定性都不太好;
  • 注意:默认它是loop-lvm模式采用空闲文件来构建存储池,建议在生产环境中使用direct-lvm模式;

报错信息5:Usage of loopback devices is strongly discouraged for production use

代码语言:javascript复制
#docker info 或者在启动时候可以看见
WARNING: Usage of loopback devices is strongly discouraged for production use

报错原因:用loopback的方式运行docker是强烈不建议的;

解决方法:

代码语言:javascript复制
#方式1:在Docker启动项里添加DOCKER_STORAGE_OPTIONS(不推荐,仅仅是忽略警告)
DOCKER_STORAGE_OPTIONS="--storage-opt dm.no_warn_on_loop_devices=true"

#方式2:在docker daemon启动时,加入device mapper的元数据存储和docker的镜像数据存储选择独立的块设备即可,lvm或者独立磁盘分区都可以
--storage-opt dm.datadev=/dev/xxxx  --storage-opt dm.metadatadev=/dev/xxx

WeiyiGeek.解决方法

报错信息6:Docker Deamon服务Socket/TCP无法连接

(1) 报错信息:ERROR: Couldn’t connect to Docker daemon at http docker://localunixsocket - is it running? 报错原因:由于Docker的守护进程未启动导致本地的UNIX.sock不能成功连接;

(2) 报错信息:Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock 报错原因:由于Docker Deamon启动权限是ROOT用户,而在非root用户下进行连接Docker Server 通信而产生错误; 解决方式:

代码语言:javascript复制
#1.启动/停止docker:
启动             systemctl start docker
守护进程重启      sudo systemctl daemon-reload
重启docker服务    systemctl restart  docker
重启docker服务    sudo service docker restart
关闭docker        service docker stop   
关闭docker        systemctl stop docker
#2.将当前用户加入docker用户组,然后重新登陆当前用户
sudo gpasswd -a ${USER} docker
#3.采用高权限用户运行docker
sudo systemctl start docker

异常信息7:指定容器连接到当前连接以及networks关键字自定义网络,应用任然无法进行相互互联 问题:利用Docker-compose部署多个容器时候已设置将指定容器连接到当前连接以及networks关键字自定义网络,应用任然无法进行相互互联; 原因:firewalld 的没有信任 docker 的 ip 地址 解决方法:将所有 docker 的 ip 添加都白名单即可。

代码语言:javascript复制
$firewall-cmd  --zone=trusted --add-source=172.17.0.1/16 --permanent
success
$firewall-cmd  --zone=trusted --add-source=172.20.0.1/16 --permanent
success
$firewall-cmd --reload
success

WeiyiGeek.容器互联

异常信息8: pull images x509 certificate has expired or is not yet valid 描述:设置了docker拉取镜像mirro源,拉取下载镜像时候提示证书验证失败;

代码语言:javascript复制
$sudo docker pull onlyoffice/documentserver
Using default tag: latest
Error response from daemon: Get https://registry-1.docker.io/v2/: x509: certificate has expired or is not yet valid

错误原因:一般都是本地系统时间错误导致报错证书过期,所以先查看本地系统时间

代码语言:javascript复制
$date
2019年 05月 19日 星期日 07:57:54 CST

解决办法:将时间同步至当前时间即可解决:ntpdate cn.pool.ntp.org;

异常信息9.执行docker info出现如下警告WARNING: bridge-nf-call-iptables is disabled 问题描述:

代码语言:javascript复制
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

解决方法: 配置 iptables 来查看桥接网络流量

代码语言:javascript复制
cat > /etc/sysctl.conf<<'EOF'
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl -p

异常信息10.构建容器镜像提示错误信息standard_init_linux.go:211: exec user process caused “no such file or directory” 问题复原:

代码语言:javascript复制
$docker-compose up
Starting blog ... done
Attaching to blog
blog    | standard_init_linux.go:211: exec user process caused "no such file or directory"
blog exited with code 1

问题原因:

1.docker-compose.yaml 或者 DockerFile 格式不是 unix (/n) 而是 dos (/r/n) 导致的 解决办法:

代码语言:javascript复制
# 方式1
dos2unix docker-compose.yaml && dos2unix DockerFile

异常信息11.Error response from daemon: driver failed programming external connectivity on endpoint loving_bassi (37b4c399f676cf46e35fd26b2298ad81aac87739d8aee416f449e36c6cb22503) 问题信息:docker: Error response from daemon: driver failed programming external connectivity on endpoint loving_bassi (37b4c399f676cf46e35fd26b2298ad81aac87739d8aee416f449e36c6cb22503): (iptables failed: iptables –wait -t nat -A DOCKER -p tcp -d 0/0 –dport 90 -j DNAT –to-destination 172.17.0.2:80 ! -i docker0: iptables: No chain/target/match by that name. 问题原因: 在 iptables 中的docker0网卡中没有这样的链、目标、规则匹配,即是docker服务启动时定义的自定义链DOCKER由于某种原因被清掉; 解决办法: 重启docker服务及可重新生成自定义链DOCKER然后再启动容器;

代码语言:javascript复制
# pkill docker
# iptables -t nat -F
# ifconfig docker0 down
# brctl delbr docker0
# service docker restart

异常信息12.使用 docker port 命令映射容器的端口时,系统报错“Error: No public port ‘80’ published for xxx” 问题原因:创建镜像时 Dockerfile 要通过 EXPOSE 指定正确的开放端口。 解决办法:容器启动时指定 PublishAllPort = true

异常信息13.使用内存和 swap 限制启动容器时候报警告:”WARNING: Your kernel does not support cgroup swap limit. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.”? 问题原因:因为系统默认没有开启对内存和 swap 使用的统计功能,引入该功能会带来性能的下降。要开启该功能,可以采取如下操作; 解决办法:

  • 编辑 /etc/default/grub 文件(Ubuntu 系统为例),配置 GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
  • 更新 grub:$ sudo update-grub 重启系统即可。

异常信息14.docker警告WARING:No swap limit support 问题描述:Linux操作系统下docker内存限制中的警告WARNING: No swap limit support,大概意思就是不支持swap内存的限制; 解决办法:已在Ubuntu 20.04 TLS 下测试

代码语言:javascript复制
# 1.编辑/etc/default/grub文件。
vim /etc/default/grub

# 2.找到GRUB_CMDLINE_LINUX=配置项,并追加“cgroup_enable=memory swapaccount=1”。

# 3.保存文件并执行一下命令:
sudo update-grub

# 4.重启服务器
reboot

异常信息15.Docker 无法启动提示 Job docker.service/start failed with result ‘dependency’. 错误信息 错误信息: 通过journalctl -xe查看详细错误

代码语言:javascript复制
-- Unit containerd.service has begun starting up.
6月 04 21:27:33 WeiyiGeek-101 containerd[8304]: containerd: Near line 58 (last key parsed 'plugins.io.containerd.grpc.v1.cri.sandbox_image'): Key 'plugins.io.containerd.grpc.v1.cri.sandbox_image' has already been defined.  # 关键点
6月 04 21:27:33 WeiyiGeek-101 systemd[1]: containerd.service: main process exited, code=exited, status=1/FAILURE
6月 04 21:27:33 WeiyiGeek-101 systemd[1]: Failed to start containerd container runtime.
6月 04 21:27:33 WeiyiGeek-101 systemd[1]: Dependency failed for Docker Application Container Engine.
6月 04 21:27:33 WeiyiGeek-101 systemd[1]: Job docker.service/start failed with result 'dependency'.
6月 04 21:27:33 WeiyiGeek-101 systemd[1]: Unit containerd.service entered failed state.
6月 04 21:27:33 WeiyiGeek-101 systemd[1]: containerd.service failed.

问题原因: 由于 Key 'plugins.io.containerd.grpc.v1.cri.sandbox_image' has already been defined. 重复定义导致的.

WeiyiGeek.sandbox_image

解决办法: vim /etc/containerd/config.toml 删除重复的 sandbox_image 项并重启 docker 即可。

异常信息16.docker 报 chown socket at step GROUP: No such process导致启动失败

错误信息:

代码语言:javascript复制
$ journalctl -xn
-- Unit docker.socket has begun starting up.
Dec 30 13:25:23 ITX systemd[1868]: Failed to chown socket at step GROUP: No such process
Dec 30 13:25:23 ITX systemd[1]: docker.socket control process exited, code=exited status=216
Dec 30 13:25:23 ITX systemd[1]: Failed to listen on Docker Socket for the API.
-- Subject: Unit docker.socket has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit docker.socket has failed.
--

解决办法:

代码语言:javascript复制
方法1.添加 docker 用户组 ( 如果`/etc/group`用统一配置管理的话记得在源group文件中添加docker组信息 )
groupadd docker

方法2.修改`/usr/lib/systemd/system/docker.socket`文件:
[Unit]
Description=Docker Socket for the API
PartOf=docker.service

[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker    # 改成 SocketGroup=root 或其他存在的组

[Install]
WantedBy=sockets.target

异常信息17: Error in deleting repository in a private registry V2 #1573;

  • 问题原因:在启动registry时候没有启用REGISTRY_STORAGE_DELETE_ENABLED=true环境变量; ISSUE: https://github.com/docker/distribution/issues/1573
  • 解决办法: 启动docker registry 加入环境变量 -e "REGISTRY_STORAGE_DELETE_ENABLED=true"
0x03 面试问题
面试问答1.仓库(Repository)、注册服务器(Registry)、注册索引(Index) 有何关系?
  • 仓库是存放一组关联镜像的集合,比如同一个应用的不同版本的镜像。
  • 注册服务器是存放实际的镜像文件的地方。
  • 注册索引则负责维护用户的账号、权限、搜索、标签等的管理。 因此,注册服务器利用注册索引来实现认证等管理。
面试问答2.如何临时退出一个正在交互的容器的终端,而不终止它?

答:按 Ctrl-p Ctrl-q,如果按 Ctrl-c 往往会让容器内应用进程终止,进而会终止容器。

面试问答3.Dockerfile中 ADD 与 COPY 的区别?

答: 使用 ADD 指令时如果拷贝的源文件是个 tar 包,则在构建容器时会帮我们把 tar 包解开到指定目录,而使用 copy 指令则不会解压 tar 包; 另外一个区别是ADD指令既可以添加一个构建上下文环境中的文件也可以是个URL,而COPY则只能添加构建上下文中的文件;

面试问答4.Dockerfile中 CMD 与 ENTRYPOINT 的区别?

答: 使用场景的区别CMD指令是在容器启动后默认执行的命令和参数((如果定义多个CMD只有最后一个执行)),而ENTRYPOINT是用于应用运行前的准备工作(让容器以应用程序或服务形式运行); 注意:在Dockerfile至少需要设置一条CMD或者ENTRYPOINT指令;

0 人点赞