目录
7.1. failed to create NAT chain DOCKER 25
7.2. Failed to start firewalld - dynamic firewall daemon 26
7.3. can't initialize iptables table `nat' 27
7.4. list bridge addresses failed 28
7.7. start request repeated too quickly for docker.service 30
7.8. Module nf_nat not found 31
7.9. applying cgroup configuration for process caused 31
7.10. Transaction check error: 31
7.11. Your kernel does not support swap limit capabilities or the cgroup is not mounted 32
7.12. Cannot connect to the Docker daemon at 32
7.13. Minimum memoryswap limit should be larger than memory limit 32
7.14. Value too large for defined data type 32
本文操作基于CentOS7,其它Linux发行版本可能存在差异,分基于yum的在线安装和基于二进制包的离线安装(实际还有基于rpm包的离线安装),离线安装可以更多地了解Docker及相关体系。
Docker要求Linux内核版本不低于3.10,并且必须为64位系统,执行命令“docker version”可查看Docker版本。
CentOS7防火墙默认采用的是firewalld管理netfilter子系统,底层调用的仍然是iptables命令,firewalld实际是iptables的一个封装。不同的防火墙相互间存在冲突,使用某其中一个时应禁用其他的。
谨记:容器运行在Linux内核之上,不包含位于内核之上的glibc等库,以及ls等命令。如果容器中的程序依赖glibc等库或者依赖ls等命令,则容器自身应当包含这些设施。另外,容器中的程序等必须和内核兼容,否则将会遇到“FATAL: kernel too old”错误,该错误和库文件ld-linux.so有关。
Docker仓库(Repository)是存储Docker镜像的地方。
镜像(image)是静态的,容器(container)是运行中的镜像。如果说镜像是程序文件,则容器是进程。把镜像ID看作文件名,则容器ID可视为进程ID,因此每次启动的容器ID是不相同的。
同一镜像可以启动多个容器,容器间的ID不会相同:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7518f632b6d0 centos "/bin/bash" 4 seconds ago Up 2 seconds focused_turing d97bd379589c centos "/bin/bash" 6 minutes ago Up 6 minutes friendly_nightingale |
容器默认使用网桥网络模式,且默认桥接器名为docker0。在启动Docker之前(即执行命令“sytemctl start docker.service”前),需要先创建和启用好网桥,执行下例命令可创建和设置网桥。
# ip link add name docker0 type bridge # 创建网桥 # ip addr add dev docker0 172.17.0.1/16 # 设置网桥的IP和网关 # ip link set docker0 up # 启用网桥 # ip a # 查看创建好的网桥 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 60:eb:69:fe:2e:20 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 60:eb:69:fe:2e:21 brd ff:ff:ff:ff:ff:ff inet 10.22.25.101/26 brd 10.223.25.127 scope global eth1 valid_lft forever preferred_lft forever 4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether 6e:3c:cb:3e:a7:44 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global docker0 valid_lft forever preferred_lft forever |
网桥状态为up,则表示没有起来。如果没有网桥或网桥没有起来,执行“systemctl start docker.service”启动Docker时将可能遇到错误“list bridge addresses failed”而启动失败。
在能访问网络的环境或者有本地Docker仓库的环境,建议使用yum安装,简单省事。
在不能访问网络环境,可手工安装Docker。进入Index of /,下载对应的安装包,这里又分两种:一是下载通用的二进制安装包,二是下载RPM安装包。相对yum安装,手工安装(离线安装)可以了解更多细节,有助于深入了解Docker。
这个方法比较复杂,容易遇到各种问题。
通用的二进制安装包下载路径:Index of linux/static/stable/x86_64/,截至2019/12/17可下载的最新版本为docker-19.03.5.tgz,就以它为安装对象。下载好后,将docker-19.03.5.tgz上传到目标Linux的任一目录,然后进入该目录解压docker-19.03.5.tgz,解压后的内容如下:
# ls /usr/bin/docker containerd containerd-shim ctr docker dockerd docker-init docker-proxy runc |
解压生成的目录Docker下全是64位可执行程序文件,其中dockerd是运行在母机上的服务,dockerd负责加载镜像(image)拉起容器container。
# ls -l /usr/bin/docker 总用量 204720 -rwxr-xr-x 1 root root 34625816 2019-11-13 15:30 containerd -rwxr-xr-x 1 root root 6116160 2019-11-13 15:30 containerd-shim -rwxr-xr-x 1 root root 18850136 2019-11-13 15:30 ctr -rwxr-xr-x 1 root root 65641786 2019-11-13 15:30 docker -rwxr-xr-x 1 root root 72090824 2019-11-13 15:30 dockerd -rwxr-xr-x 1 root root 764144 2019-11-13 15:30 docker-init -rwxr-xr-x 1 root root 2877369 2019-11-13 15:30 docker-proxy -rwxr-xr-x 1 root root 8649792 2019-11-13 15:30 runc |
将目录“/usr/bin/docker”加入到环境变量PATH中,如果不这么做,则可将目录/usr/bin/docker下的所有文件复制到目录“/usr/bin”。
新建和编辑文件docker.service,文件docker.service所在目录可有多种选择,实际为systemd查找目录,执行命令“man 5 systemd.unit”或“man 5 systemd.service”可看到所支持的目录包含如下一些:
目录 | 说明 |
/etc/systemd/system | Local configuration |
/run/systemd/system | Runtime units |
/usr/lib/systemd/system | Units of installed packages yum方式安装时,docker.service可能在此目录 |
以“/etc/systemd/system/docker.service”为例:
# cat /etc/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=http://docs.docker.com After=network.target rhel-push-plugin.socket Wants=docker-storage-setup.service [Service] Type=notify NotifyAccess=all EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network Environment=GOTRACEBACK=crash ExecStart=/usr/bin/dockerd daemon \ --graph /data/docker \ --exec-opt native.cgroupdriver=systemd \ $OPTIONS \ $DOCKER_STORAGE_OPTIONS \ $DOCKER_NETWORK_OPTIONS \ $ADD_REGISTRY \ $BLOCK_REGISTRY \ $INSECURE_REGISTRY LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity TimeoutStartSec=0 MountFlags=slave Restart=on-abnormal [Install] WantedBy=multi-user.target |
其中“--graph”用于指定镜像(image)存放目录。
执行命令“systemctl start docker.service”启动Docker:
# systemctl start docker.service # ps aux|grep docker | grep -v grep root 16052 0.3 0.1 600076 37332 ? Ssl 16:46 0:00 /usr/bin/docker/dockerd --data-root /data/docker --exec-opt native.cgroupdriver=systemd root 16060 0.1 0.0 571644 22196 ? Ssl 16:46 0:00 containerd --config /var/run/docker/containerd/containerd.toml --log-level info |
从Index of linux/centos/7/x86_64/stable/Packages/下载RPM安装包,以下载docker-ce-19.03.5-3.el7.x86_64.rpm、docker-ce-cli-19.03.5-3.el7.x86_64.rpm、containerd.io-1.2.6-3.3.el7.x86_64.rpm、docker-ce-selinux-17.03.3.ce-1.el7.noarch.rpm为例,其中docker-ce-19.03.5-3.el7.x86_64.rpm依赖其它几个RPM包,而containerd.io-1.2.6-3.3.el7.x86_64.rpm又依赖docker-ce-selinux。
基于RPM包安装涉及很多依赖,安装可能复杂(视实际的依赖程度),所以尽量避免这种安装方式。本文尝试时,因为太多的依赖需要安装或更新,导致未能完成。
yum会将Docker安装到/usr/bin目录,可执行“ls /usr/bin/dock*”查看有哪些文件,不同版本会有差异。
实际上可以用yum安装RPM包,但和直接使用RPM命令一样,有复杂的依赖问题,所以除非不得已,最好不要采用yum+RPM包方式安装。这节介绍可访问网络(能访问Docker仓库)时的yum安装。
需要安装的内容包括:
包名 | 说明 |
docker-ce | 社区版(Community)容器引擎(Docker Engine),依赖containerd.io。包含了: /usr/bin/dockerd /usr/bin/docker-init /usr/bin/docker-proxy |
docker-ce-cli | docker-ce的命令行客户端工具,包含了命令行客户端工具/usr/bin/docker |
containerd.io | 隔离了Docker和OS(比如Linux容器LXC),有独立的官网:containerd – An industry-standard container runtime with an emphasis on simplicity, robustness and portability。 |
docker | 对社区版而言,就是docker-ce,有些非官方仓库需要使用这个名字安装,使用docker-ce报“No package docker-ce available”。 |
其中docker-ce为容器引擎,安装步骤:
这一步不一定是必须的,比如内网已配置好本地仓库而不需要访问Docker官方仓库,或者已添加好Docker官方仓库。
如果yum-config-manager不可用,则需执行“yum install -y yum-utils”先安装好yum-config-manager。
执行下列命令添加Docker仓库:
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo |
完成后,可以目录/etc/yum.repos.d下看到文件docker-ce.repo。如果执行失败,则文件docker-ce.repo为空文件。
执行下列命令安装:
# yum -y install docker-ce |
上述实际相当于:
# yum -y install docker.io/docker-ce |
如果报“No package docker-ce available”,可改成下列试试:
# yum -y install docker |
安装成功后,会产生新文件:
# file /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service: cannot open (No such file or directory) # ls /usr/bin/dock* ls: cannot access /usr/bin/dock*: No such file or directory # yum -y install docker-ce # file /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service: ASCII text # ls /usr/bin/dock* /usr/bin/docker /usr/bin/docker-fetch /usr/bin/dockertarsum |
其中docker.service供systemd使用,当执行“systemctl start docker.service”时依赖文件docker.service定义的信息。文件docker.service不一定要位于目录/usr/lib/systemd/system/,systemd支持搜索多个目录查找docker.service,比如二进制安装时将docker.service放在目录/etc/systemd/system。
默认的文件docker.service内容如下:
# cat /usr/lib/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=http://docs.docker.com After=network.target [Service] Type=notify EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network ExecStart=/usr/bin/docker -d $OPTIONS \ $DOCKER_STORAGE_OPTIONS \ $DOCKER_NETWORK_OPTIONS \ $ADD_REGISTRY \ $BLOCK_REGISTRY \ $INSECURE_REGISTRY LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity MountFlags=slave TimeoutSec=0 [Install] WantedBy=multi-user.target |
其中参数“-d”表示以后台守护进程方式启动,配置项“WantedBy”用于指定随系统启动时docker.service发布的子目录为“multi-user.target”。注意“multi-user.target”的名不能随便取,这是systemd约定的名之一,对应系统启动级别3,可通过命令“systemctl set-default”修改默认级别,multi-user.target的完整目录路径为/etc/systemd/system/multi-user.target。
官方最新的docker.service如下:
# cat /usr/lib/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com BindsTo=containerd.service After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=docker.socket [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. # Both the old, and new location are accepted by systemd 229 and up, so using the old location # to make them work for either version of systemd. StartLimitBurst=3 # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make # this option work for either version of systemd. StartLimitInterval=60s # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Comment TasksMax if your systemd version does not support it. # Only systemd 226 and above support this option. TasksMax=infinity # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process [Install] WantedBy=multi-user.target |
执行命令“systemctl start docker.service”启动Docker:
# systemctl start docker.service # ps aux|grep docker | grep -v grep /usr/bin/docker -d --selinux-enabled -b=none |
Docker的各程序或命令基本都支持“--help”参数查看帮助,比如:docker --help、dockerd --help、docker images --help。
和其它服务一样启动即可,停止和重启方法也相同。
# systemctl start docker.service |
执行命令“docker images”,可查看有哪些镜像(image):
# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/hello-world latest fce289e99eb9 11 months ago 1.84 kB |
如果Docker服务没有起来,执行“docker images”将报如下错误:
# docker images Cannot connect to the Docker daemon. Is the docker daemon running on this host? |
默认拉取到的是latest镜像(image)。
# docker pull hello-world Using default tag: latest Trying to pull repository docker.io/library/hello-world ... latest: Pulling from docker.io/library/hello-world 1b930d010525: Pull complete |
如果执行命令“docker images”看不到拉取的镜像(image),则可重拉取后再看看。如果从非Docker官方(docker.io)拉取image,则需要指定仓库地址:
# docker pull myrep.io/public/hello-world |
如不确定hello-world所在路径,则可先执行“docker search myrep.io/hello”查找:
# docker search myrep.io/hello-world |
如果没有latest版镜像,则可指定版本:
# docker pull myrep.io/public/hello-world:v1 |
从从Docker官方拉取centos7为例(其中7实为镜像的tag):
# docker pull centos:7 |
拉取tag为“centos7.2.1511”的镜像:
# docker pull centos:centos7.2.1511 |
注意,这里并不是“docker pull http://myrep.io/public/hello-world”,没有“http://”或“https://”前缀,否则报错“is not a valid repository/tag: invalid reference format”。
拉取下来的images存放在哪?请参见《指定Docker的images存放目录》一节的内容。官方的“hello-world”镜像长这样子:
# cat /data/docker/image/aufs/imagedb/content/sha256/fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e {"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"ArgsEscaped":true,"Image":"sha256:a6d1aaad8ca65655449a26146699fe9d61240071f6992975be7e720f1cd42440","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"8e2caa5a514bb6d8b4f2a2553e9067498d261a0fd83a96aeaaf303943dff6ff9","container_config":{"Hostname":"8e2caa5a514b","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"ArgsEscaped":true,"Image":"sha256:a6d1aaad8ca65655449a26146699fe9d61240071f6992975be7e720f1cd42440","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2019-01-01T01:29:27.650294696Z","docker_version":"18.06.1-ce","history":[{"created":"2019-01-01T01:29:27.416803627Z","created_by":"/bin/sh -c #(nop) COPY file:f77490f70ce51da25bd21bfc30cb5e1a24b2b65eb37d4af0c327ddc24f0986a6 in / "},{"created":"2019-01-01T01:29:27.650294696Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:af0b15c8625bb1938f1d7b17081031f649fd14e6b233688eea3c5483994a66a3"]}} |
以“hello-world”为例(如果不带参数“--rm”运行,则窗口退出后不会自动删除):
# docker run --rm hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: |
可为“docker run”指定资源控制参数,比如限定内存等。执行“docker run --help”可以看到相关参数说明。
# docker inspect hello-world [ { "Id": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e", "RepoTags": [ "docker.io/hello-world:latest" ], 。。。 。。。 |
还可用命令“docker inspect”查看容器的IP地址:
# docker inspect 1fb1e1ad7356|grep '"IPAddress"' | head -n 1 "IPAddress": "172.17.0.2", |
这根Docker版本有关,有些版本的叫/usr/bin/dockerd,有些叫/usr/bin/docker,有些叫/usr/bin/docker-current,而且参数会有差异。启动遇到错误时,可只带参数“--help”查看帮助,比如执行“dockerd --help”。
但如果是yum方式安装的,Docker服务启动配置文件一般均是/usr/lib/systemd/system/docker.service。
注意文件docker.service是供系统的systemd使用的,通过命令systemctl来操控。并不是Docker自己的配置文件,实为一个Docker启动配置,下面分两种分别介绍。
- 带“--graph”参数
这个实际是老版本的参数名,新版本(如“Docker version 19.03.1”)已改叫--data-root,新版本的参数命名更为具体好理解和记忆。
ExecStart=/usr/bin/docker-current daemon \ --graph /data/docker \ --exec-opt native.cgroupdriver=systemd \ $OPTIONS \ $DOCKER_STORAGE_OPTIONS \ $DOCKER_NETWORK_OPTIONS \ $ADD_REGISTRY \ $BLOCK_REGISTRY \ $INSECURE_REGISTRY |
“--graph /data/docker”也可写成“--graph=/data/docker”,效果是一样的。另外,还可通过docker-current的命令行参数“--registry-mirror=”指定images仓库。
在文件docker.service发生变化后,需要执行一次“systemctl daemon-reload”通知systemd重新加载,否则使用的仍然是老的配置。
执行“systemctl restart docker.service”重启启动,然后执行ps命令可看到相关的变化:
# ps aux|grep docker root 21757 0.0 0.0 358584 21060 ? Ssl 09:45 0:00 /usr/bin/docker-current daemon --graph /data/docker --exec-opt native.cgroupdriver=systemd --selinux-enabled --log-driver=journald -b=none --iptables=false |
以镜像“hello-world”为例,它的路径为(注:新版本已使用文件系统overlay2替代aufs):
/data/docker/image/aufs/imagedb/content/sha256/fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e |
其中“sha256”后面为镜像“hello-world”内容的sha256值:
# cat /data/docker/image/aufs/imagedb/content/sha256/fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e | openssl dgst -sha256 -hex (stdin)= fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e |
- 带“--data-root”参数
这个是新版本的参数名,命名更为具体好理解和记忆,镜像(image)存放在data目录。
# cat /usr/lib/systemd/system/docker.service [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com BindsTo=containerd.service After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=docker.socket [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. # Both the old, and new location are accepted by systemd 229 and up, so using the old location # to make them work for either version of systemd. StartLimitBurst=3 # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make # this option work for either version of systemd. StartLimitInterval=60s # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity # Comment TasksMax if your systemd version does not support it. # Only systemd 226 and above support this option. TasksMax=infinity # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process [Install] WantedBy=multi-user.target |
找到docker.service中“ExecStart”所在行,修改为(镜像存放在data目录):。
ExecStart=/usr/bin/dockerd -H fd:// \ --containerd=/run/containerd/containerd.sock \ --data-root=/data/docker/data \ --exec-root=/data/docker/run |
Docker在启动时会自动创建这两个目录,但注意需有创建目录权限。并需记得每次修改docker.service后,需要先执行一次“systemctl daemon-reload”,然后才可执行“systemctl start docker.service”启动,否则报“Warning: docker.service changed on disk. Run 'systemctl daemon-reload' to reload units.”。
启动后可看到如下:
# ps aux|grep docker root 22564 0.6 0.1 593460 63488 ? Ssl 11:04 0:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --data-root=/data/docker/data --exec-root=/data/docker/run |
以官方的镜像alpine为例,它的存放位置如下(注:新版本已使用文件系统overlay2替代aufs):
# ls -l /data/docker/data/overlay2/c1b9aec275a2cdf832c9f079389aa63577be6f8371dec164af8cc3e8c7fa77f8/diff 总用量 68 drwxr-xr-x 2 root root 4096 12月 19 23:20 bin drwxr-xr-x 2 root root 4096 12月 19 23:20 dev drwxr-xr-x 15 root root 4096 12月 19 23:20 etc drwxr-xr-x 2 root root 4096 12月 19 23:20 home drwxr-xr-x 5 root root 4096 12月 19 23:20 lib drwxr-xr-x 5 root root 4096 12月 19 23:20 media drwxr-xr-x 2 root root 4096 12月 19 23:20 mnt drwxr-xr-x 2 root root 4096 12月 19 23:20 opt dr-xr-xr-x 2 root root 4096 12月 19 23:20 proc drwx------ 2 root root 4096 12月 19 23:20 root drwxr-xr-x 2 root root 4096 12月 19 23:20 run drwxr-xr-x 2 root root 4096 12月 19 23:20 sbin drwxr-xr-x 2 root root 4096 12月 19 23:20 srv drwxr-xr-x 2 root root 4096 12月 19 23:20 sys drwxrwxrwt 2 root root 4096 12月 19 23:20 tmp drwxr-xr-x 7 root root 4096 12月 19 23:20 usr drwxr-xr-x 12 root root 4096 12月 19 23:20 var |
其中“c1b9aec275a2cdf832c9f079389aa63577be6f8371dec164af8cc3e8c7fa77f8”为diffID,是一个SHA256值,基于镜像层(layer)文件包的内容计算得到。如果该镜像层是最底层(即没有父镜像层),则该层的diffID便是chainID。镜像层元数据存储在目录/data/docker/data/image/overlay2/layerdb下。
# docker logs -f -t --tail=100 container-id |
命令“docker logs”参数说明:
参数名 | 参数说明 |
-f | 跟踪(follow)实时日志 |
-t | 显示时间戳(timestamps) |
--tail=N | 显示最后N条,如果不指定tail则默认是所有 |
--details | 显示详细信息 |
--since= | 显示某个时间后的日志,或者最近多长时间的日志:
|
--until | 查看截止到指定时间的日志 |
包括已停止的和运行中的容器:
# docker ps -a |
命令“docker ps”可选参数:
参数名 | 参数说明 |
-a | 列出当前所有正在运行的容器和历史上运行过的容器,如果运行容器时没有指定参数“--rm”,则容器退出后“docker ps -a”仍然看得到。 |
-l | 显示最新创建的容器,包括已停止的容器 |
-n | 显示最近n个创建的容器,包括已停止的容器 |
-q | 安静模式,只显示容器编号 |
--no-trunc | 不截断输出 |
- 只查看运行中的容器
# docker ps |
- 只查看已停止的容器
# docker ps -a -f status=exited |
先向容器进程发送信号SIGTERM,10秒后再发送SIGKILL。
# docker stop |
优雅停止所有容器:
# docker stop $(docker ps -a -q) |
直接向容器进程发信号SIGKILL。
# docker kill |
# docker rm [OPTIONS] CONTAINER [CONTAINER...] |
- 删除所有的容器:
# docker rm $(docker ps -a -q) |
- 删除所有已停止的容器:
docker rm $(docker ps -a -f status=exited -q) |
OPTIONS可取值:
取值 | 作用 |
-f | 通过SIGKILL信号强制删除一个运行中的容器 |
-l | 移除容器间的网络连接,而非容器本身 |
-v | 删除与容器关联的卷 |
命令“docker rmi”的作用是用来删除本地镜像,可按镜像ID,也可按“镜像名:TAG”方式删。
删除指定ID的镜像:
# docker rmi <image id> |
删除全部镜像:
# docker rmi $(docker images -q) |
删除指定镜像名和TAG的镜像:
$ docker images REPOSITORY TAG IMAGE ID REATED SIZE a/redis 6.0.6 1319b1eaa0b7 3 weeks ago 104MB b/redis 6.0.6 1319b1eaa0b7 3 weeks ago 104MB redis 6.0.6 1319b1eaa0b7 3 weeks ago 104MB |
删除第一条,即“a/redis:6.0.6”:
$ docker rmi a/redis:6.0.6 |
可指定参数“-f”,强制删除:
$ docker rmi -f a/redis:6.0.6 |
如果不指定TAG,默认是删除TAG为latest的,如果没有TAG为latest的,则报错“Error: No such image: a/redis”,如:
$ docker rmi -f a/redis |
导出镜像到文件,导出后可以文件复制到其它机器再导入:
docker save -o 文件名.tar 镜像名称 |
如果镜像不在根目录,则需指定目录,如:
docker save -o tinycore.tar tatsushid/tinycore |
如果不是Docker的官方仓库,还得指定仓库地址,如:
docker save -o tinycore.tar docker.io/tatsushid/tinycore |
docker load < 文件名.tar 或 docker load -i 文件名.tar |
只知道镜像名或部分名,不知道完整的路径时,可以使用Docker提供的查找(search)功能,比如搜索镜像alpine,其中列OFFICIAL指定该镜像是否为Docker官方提供。
# docker search alpine INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED docker.io docker.io/alpine A minimal Docker image based on Alpine Lin... 5927 [OK] docker.io docker.io/frolvlad/alpine-glibc Alpine Docker image with glibc (~12MB) 223 [OK] docker.io docker.io/mhart/alpine-node Minimal Node.js built on Alpine Linux 448 docker.io docker.io/anapsix/alpine-java Oracle Java 8 (and 7) with GLIBC 2.28 over... 434 [OK] docker.io docker.io/gliderlabs/alpine Image based on Alpine Linux will help you ... 180 docker.io docker.io/alpine/git A simple git container running in alpine ... 109 [OK] docker.io docker.io/mvertes/alpine-mongo light MongoDB container 106 [OK] docker.io docker.io/alpine/socat Run socat command in alpine container 43 [OK] docker.io docker.io/zzrot/alpine-caddy Caddy Server Docker Container running on A... 35 [OK] docker.io docker.io/easypi/alpine-arm AlpineLinux for RaspberryPi 32 docker.io docker.io/jfloff/alpine-python A small, more complete, Python Docker imag... 32 [OK] docker.io docker.io/byrnedo/alpine-curl Alpine linux with curl installed and set a... 28 [OK] docker.io docker.io/hermsi/alpine-sshd Dockerize your OpenSSH-server with rsync a... 26 [OK] docker.io docker.io/hermsi/alpine-fpm-php Dockerize your FPM PHP 7.4 upon a lightwei... 21 [OK] docker.io docker.io/zenika/alpine-chrome Chrome running in headless mode in a tiny ... 16 [OK] docker.io docker.io/bashell/alpine-bash Alpine Linux with /bin/bash as a default s... 14 [OK] docker.io docker.io/spotify/alpine Alpine image with `bash` and `curl`. 9 [OK] docker.io docker.io/tenstartups/alpine Alpine linux base docker image with useful... 9 [OK] docker.io docker.io/roribio16/alpine-sqs Dockerized ElasticMQ server + web UI over ... 7 [OK] |
容器是运行中的镜像,Docker提供了两种进入运行中容器的途径:
- 命令“docker container attach”
docker container attach [OPTIONS] CONTAINER-ID |
示例:
docker container attach 2896d0dad64d |
“attach”方式进入容器后,在其中执行“exit”会退出容器(执行“docker ps”将看不到容器还在运行中),原因是attach不会打开新的终端。
- 命令“docker container exec”
docker container exec [OPTIONS] CONTAINER-ID COMMAND [ARG...] |
示例:
docker container exec -it 579f618416ca /bin/bash |
“docker container exec”的参数和“docker run”相似,不同于attach方式,exec方式进入容器会打开一个新的终端和起一个新的进程,因此exec方式执行exit退出不会导致容器退出(执行“docker ps”仍然看得到容器运行中)。
借助“docker cp”命令可以将本地文件复制到容器中:
# docker cp --help Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH Copy files/folders between a container and the local filesystem Use '-' as the source to read a tar archive from stdin and extract it to a directory destination in a container. Use '-' as the destination to stream a tar archive of a container source to stdout. Options: -a, --archive Archive mode (copy all uid/gid information) -L, --follow-link Always follow symbol link in SRC_PATH |
示例(将当前目录下的文件abc复制到容器0eae45845fc3的根目录,0eae45845fc3相当于进程号,执行“docker ps”可看到):
# docker cp abc 0eae45845fc3:/ |
注意容器退出后,复制过去的文件将不会保留,但如果是容器挂载的宿主及目录,则容器重启仍然存在。如果需要持久有效,则应执行命令“docker commit”提交到仓库,这样产生了新的镜像。
方法同复制文件到容器,如将容器中的文件/abc复制到本地的/tmp目录:
# docker cp 0eae45845fc3:/abc /tmp |
修改容器中的文件,或者往容器中新增文件,均不会影响到容器对应的镜像。如果想将新增和修改保存下来,则应执行命令“docker commit”提交到仓库,但这样产生了新的镜像,这新的镜像建立在原镜像层(layer)上。
# docker commit --help Usage: docker commit [OPTIONS] CONTAINER-ID [REPOSITORY[:TAG]] Create a new image from a container's changes Options: -a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>") -c, --change list Apply Dockerfile instruction to the created image -m, --message string Commit message -p, --pause Pause container during commit (default true) |
如果没有冒号“:”后的标记(tag),则标记默认为最新的(latest)
docker tag 1319b1eaa0b2 redis:6.0.6 |
标记私有仓库的:
docker tag 1319b1eaa0b2 myrepository.com/redis:6.0.6 |
上述的“1319b1eaa0b2”为镜像ID,完成后可执行“docker images”检查执行结果。
在上传(推送)镜像到仓库之前,需要先标记(tag)好镜像。
docker push redis:6.0.6 |
上传镜像到私有仓库:
docker push myrepository.com/redis:6.0.6 |
注意 Docker 默认不支持非 HTTPS 方式上传镜像。
登录官方仓库(参数“-u”指定登录用户名,参数“-p”指定用户密码):
docker login -u zhangsan -p password |
登录私有仓库:
docker login -u zhangsan -p password myrepository.com |
Docker采用GO语言实现的,他的命令参数为GO风格,参数名和参数值间可以是单个等号或者单个空格或者连续多个空格。其中单字母参数名以单个横杠(即“-”,如:-f)打头,多字母参数名则以两个横杠(即“--”,如:--file)打头。另外,所有Docker命令均可通过参数“--help”得到使用帮助和参数说明。
命令“docker build”用来构建(生成)镜像,执行“docker build --help”可得到该命令的帮助。
命令“docker build”和“docker run”两者有很多相同参数名,并且很多作用也是相同的,区别在于“docker build”是构建镜像时指定,而“docker run”则是在启动容器时指定,“docker run”能够覆盖“docker build”的同名同作用的参数。
命令“docker build”它的常用参数说明如下:
参数名 | 参数说明 |
-f或--file | 指定Dockerfile文件,默为当前目录下的Dockerfile,示例: # docker build --tag echo -f Dockerfile.echo . 或 # docker build --tag echo -f=Dockerfile.echo . 或 # docker build --tag echo --file Dockerfile.echo . 或 # docker build --tag echo --file=Dockerfile.echo . |
-t或--tag | 指定镜像的名(name)和标签(tag),其中标签是可选的,格式“name:tag” |
-m或--memory | 指定容器最大可用内存,可带单位(不区分大小写): b、k、kb、m、mb、g、gb、t、tb、p、pb 不指定单位为字节数,但不能小于4M,值可大于实际的物理内存。容器中看到的物理内存大小仍然是宿主机的物理内存大小,并不受参数“-m”值的影响。 |
--memory-swap | 内存+交换分区大小总限制,默认值为参数“-m”值的两倍,并且其值必须大于参数“-m”的值。值的格式同参数“-m”,两者差值即为交换分区大小,值-1表示不做限制。 如果只修改“-m”的值,并不会自动更新“--memory-swap”的值。只是如果不指定时,“--memory-swap”的默认值等于“-m”的值的两倍。 容器内的进程占用的内存大小不能超过“-m”和“--memory-swap”两者值之和,否则会被KILL掉。 |
--ulimit | 设置容器的ulimit,示例: # docker build --tag echo --ulimit=nofile=1235 --ulimit=nproc=235 . |
--rm | 成功构建后删除中间环节的容器,默认为true(即:--rm=true) |
--force-rm | 总是删除掉中间环节的容器,默认为false(即:--force-rm=false) |
-q或--quiet | 安静模式,构建成功只输出镜像ID,默认为false(即:--quiet=false) |
--network | 设置容器运行时的网络模式,默认值是default(即:--network=default),可取值:
Docker安装的时候默认会创建三个不同的网络,可以执行命令“docker network ls”命令查看这些网络。 |
--no-cache | 构建镜像过程中不使用缓存 |
--pull | 总是尝试拉取镜像的更新版本 |
--iidfile | 将镜像ID写到指定文件,如: # docker build --tag echo --iidfile=myimage.id . |
--add-host | 添加主机名和主机IP的映射,结果反映在容器的/etc/hosts文件,在/etc/hosts中可以看到添加的映射。 示例: # docker build --add-host=H1:192.168.0.1 --add-host=H2:192.168.0.2 . |
--cpu-period | 设置CPU CFS的调度周期,单位为微秒(us),取值范围为“1000us~1000000us”,即:1000~1000000。默认值为100000(即100ms),即一个调度周期时长为100ms。 |
--cpu-quota | 设置容器的CPU CFS配额,即在一个“--cpu-period”周期内最多占用CPU的时长,单位为微秒(us)。值不能小于1000us,即不能小于1000,值-1表示不做控制。可大于“--cpu-period”的值,当大于“--cpu-period”的值时相当于占满了整个“--cpu-period”周期。 |
-c或--cpu-shares | CPU的共享权值(相对权重) |
--cpuset-cpus | 允许使用的CPU集,可取值:0-3、0或1 |
--cpuset-mems | 对NUMA架构有效,可取值:0-3、0或1 |
命令“docker run”用来启动容器,参数比较多,包括各资源配额等参数,执行“docker run --help”可得到该命令的帮助。
参数名 | 参数说明 |
-d或--detach | 以后台方式启动容器 |
--name | 设置容器名,类似进程名 |
--rm | 容器退出后,自动删除容器 |
-t或--tty | 为容器分配一个伪终端 |
-i或--interactive | 交互模式运行容器,保持标准输入打开 |
-p或--publish | 指定宿主机和容器的端口映射列表,比如: -p 7777:7778 -p 8888:8888 表示将宿主机的7777端口映射到容器的7778,将宿主的8888映射到容器的8888。 如果没有任何端口映射,则在宿主机上看不到容器内进程的痕迹。但如果有映射端口,则在宿主机上,以官方的Redis镜像为例,将可以看到如下: # ps -Ao pid,args|grep 7778|grep -v grep 27736 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 7777 -container-ip 172.17.0.2 -container-port 7778 原因是外部只能通过宿主机访问容器内的进程(比如这里的Redis)。 |
--add-host | 同“docker build” |
--cpu-period | 同“docker build” |
--cpu-quota | 同“docker build” |
-c或--cpu-shares | 同“docker build” |
-m或--memory | 同“docker build” |
--memory-swap | 同“docker build” |
--ulimit | 同“docker build” |
--network | 同“docker build”,设置连接的网络类型,如: # docker run -it --rm --network=bridge centos |
--network-alias | 设置网络别名(列表),自定义网络模式才有效,否则报错“network-scoped aliases are only supported for user-defined networks”。 |
-u或--user | 设置运行容器的用户(也可同时设置用户组),如: # docker run -it --rm -u=dbus centos |
--expose | 容器对外暴露的端口(列表),会覆盖Dockerfile中定义的EXPOSE端口,如: # docker run -it --rm --expose 2019 --expose 2020 centos 注意这只是一个声明,容器中是否有开启这个端口由容器中的程序决定。 |
-v或--volume | 指定容器绑定的本地目录,格式:宿主机目录:容器目录,如:-v /host_data:/container_data |
--link | 设置要连接的其它容器(列表),如: # docker run -it --rm --link=20cf8c99379e centos |
--restart | 容器重启策略:
|
--pids-limit | 设置容器内最多进程数,默认为-1表示不做限制 |
--oom-kill-disable | 禁止容器内的OOM |
--pid | 和指定容器共享PID(进程ID)资源,如: # docker run -it --rm --pid=container:4aae83be7a11 centos |
--env | 设置容器的环境变量 |
--env-file | 设置容器的环境变量,环境变量来源于文件 |
“docker run”可以通过参数覆盖“docker build”时指定的值,而“docker update”又可实时修改“docker run”和“docker build”时指定或未指定的值。
“docker update”能够修改的参数如下表所示:
参数名 | 参数说明 |
--cpu-period | 同“docker run” |
--cpu-quota | 同“docker run” |
-c或--cpu-shares | 同“docker run” |
-m或--memory | 同“docker build” |
--memory-swap | 同“docker run” |
--restart | 同“docker run” |
--pids-limit | 同“docker run” |
命令“docker network”用来查看和管理网格。
参数名 | 参数说明 |
ls | 例举网格,比如: # docker network ls NETWORK ID NAME DRIVER SCOPE 70524b6e0591 bridge bridge local daef1c0068b0 host host local cff2ec4f4275 none null local |
inspect | 查看指定网格,如: # docker network inspect 70524b6e0591 |
connect | 连接容器到指定网络 |
disconnect | 将容器和网络断开 |
rm | 删除指定的一个或多个网络 |
create | 创建一个网络 |
prune | 删除所有未用到的网络 |
执行“systemctl start docker.service”试图启动docker时报如下错误:
# systemctl -l status docker.service failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not found docker.service: main process exited, code=exited, status=1/FAILURE Failed to start Docker Application Container Engine. Unit docker.service entered failed state. |
这个错误是因为没有启动iptables,导致Docker无法做端口转发,执行命令“systemctl status firewalld”查看防火墙状态:
# systemctl status firewalld firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled) Active: inactive (dead) |
firewalld没有起来,启动它(disabled表示不随系统自动启动):
# systemctl start firewalld # systemctl status firewalld firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled) Active: active (running) since 三 2019-12-18 16:14:07 CST; 4s ago Main PID: 8066 (firewalld) CGroup: /system.slice/firewalld.service └─8066 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid 12月 18 16:14:07 X.site systemd[1]: Started firewalld - dynamic firewall daemon. |
在CentOS7中虽然iptables仍然存在,但请使用firewalld来取代iptables服务。执行“systemctl start iptables”启动iptables,将会自动停止firewalld,所以不要启动iptables.service。
执行“systemctl status firewalld.service”时报如下错误:
# systemctl status firewalld.service firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled) Active: failed (Result: exit-code) since 三 2019-12-18 15:46:41 CST; 4s ago Process: 6381 ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS (code=exited, status=1/FAILURE) Main PID: 6381 (code=exited, status=1/FAILURE) 12月 18 15:46:41 X.site systemd[1]: firewalld.service: main process exited, code=exited, status=1/FAILURE 12月 18 15:46:41 X.site systemd[1]: Failed to start firewalld - dynamic firewall daemon. 12月 18 15:46:41 X.site systemd[1]: Unit firewalld.service entered failed state. |
上述错误信息不是很明确,不足以分析出问题。/usr/sbin/firewalld实际上是一个Python脚本,由/usr/lib/systemd/system/firewalld.service中定义拉起firewalld:
ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS |
可手工执行看看情况:
ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS |
手工执行:
# /usr/sbin/firewalld --nofork --nopid Traceback (most recent call last): File "/usr/sbin/firewalld", line 34, in <module> from firewall import config ImportError: No module named firewall |
错误信息显示没有名为firewall的Python模块(修复这个后,仍然可能缺失其它模块,需逐一排查,查看文件/usr/sbin/firewalld可了解到所依赖的其它模块),简单点可直接从其它机器复制一份过来。先找到firewall在其它机器上的位置:
# python Python 2.7.5 (default, Nov 20 2015, 02:00:19) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import firewall >>> print firewall.__file__ /usr/lib/python2.7/site-packages/firewall/__init__.pyc >>> |
注意,不同机器Python包的位置可能不同,可查看sys.path值来确认包存放在哪些目录下。
另外,请注意/usr/sbin/firewalld中使用的Python是否正确(注意python的路径):
# head -1 /usr/sbin/firewalld #!/usr/bin/python -Es |
执行命令“iptables -t nat -F”时报如下错误:
# iptables -t nat -F iptables v1.4.21: can't initialize iptables table `nat': Table does not exist (do you need to insmod?) Perhaps iptables or your kernel needs to be upgraded. |
遇到这个错误时,可能需要重新配置和编译内核。执行命令“modinfo iptable_nat”检查内核中是否有NAT模块:
# modinfo iptable_nat modinfo: ERROR: Module iptable_nat not found. |
如果没有条件编译内核,则可从其它地方将相关的模块文件复制过来,复制过来后注意需执行一次depmod命令。相关路径:“/lib/modules/`uname -r`”。
如果模块存在,则显示如下(内核模块文件名以“.ko”为后缀,ko为“Kernel Object”的缩写,depends显示依赖的其它模块):
# modinfo iptable_nat filename: /lib/modules/3.10.107-1-0050/kernel/net/ipv4/netfilter/iptable_nat.ko license: GPL srcversion: 22FC08135673BF996B25929 depends: nf_nat,ip_tables,nf_nat_ipv4,nf_conntrack intree: Y vermagic: 3.10.107-1-0050 SMP mod_unload modversions signer: sig sig_key: 6E:69:6E:67:20:6B:65:79:2C:94:15:C6:82:EA:DB:06:CF:5A:37:57:72:EE:7A:58:2D:CA:23:38 sig_hashalgo: sha512 |
其它模块可同样方法查看:
# modinfo nf_nat filename: /lib/modules/3.10.107-1-0050/kernel/net/netfilter/nf_nat.ko license: GPL srcversion: 5A7A5091ADF09B929C3EBC8 depends: nf_conntrack intree: Y vermagic: 3.10.107-1-0050 SMP mod_unload modversions signer: sig sig_key: 6E:69:6E:67:20:6B:65:79:2C:94:15:C6:82:EA:DB:06:CF:5A:37:57:72:EE:7A:58:2D:CA:23:38 sig_hashalgo: sha512 |
执行“systemctl start docker.service”时报如下错误:
12月 18 16:26:19 X.site dockerd[23727]: failed to start daemon: Error initializing network controller: list bridge addresses failed: PredefinedLocalScopeDefaultNetworks List: [172.17.0.0/16 172.18.0.0/16 172.19.0.0/16 172.20.0.0/16 172.21.0.0/16 172.22.0.0/16 172.23.0.0/16 172.24.0.0/16 172.25.0.0/16 172.26.0.0/16 172.27.0.0/16 172.28.0.0/16 172.29.0.0/16 172.30.0.0/16 172.31.0.0/16 192.168.0.0/20 192.168.16.0/20 192.168.32.0/20 192.168.48.0/20 192.168.64.0/20 192.168.80.0/20 192.168.96.0/20 192.168.112.0/20 192.168.128.0/20 192.168.144.0/20 192.168.160.0/20 192.168.176.0/20 192.168.192.0/20 192.168.208.0/20 192.168.224.0/20 192.168.240.0/20]: no available network 12月 18 16:26:19 X.site systemd[1]: docker.service: main process exited, code=exited, status=1/FAILURE 12月 18 16:26:19 X.site systemd[1]: Failed to start Docker Application Container Engine. 12月 18 16:26:19 X.site systemd[1]: Unit docker.service entered failed state. |
这个错误是因为没有网桥(可执行命令“ip a”或“netstat -ie”等检查),导致docker无法启动。执行以下命令创建和启动网桥:
# ip link add name docker0 type bridge # ip addr add dev docker0 172.17.0.1/16 # ip link set docker0 up # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 60:eb:69:fe:2e:20 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 60:eb:69:fe:2e:21 brd ff:ff:ff:ff:ff:ff inet 10.22.25.101/26 brd 10.223.25.127 scope global eth1 valid_lft forever preferred_lft forever 4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN link/ether 6e:3c:cb:3e:a7:44 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global docker0 valid_lft forever preferred_lft forever |
创建网桥也可使用专门的工具brctl。
在执行yum命令时,如果报如下错误:
# yum There was a problem importing one of the Python modules required to run yum. The error leading to this problem was: No module named yum Please install a package which provides this module, or verify that the module is installed correctly. It's possible that the above module doesn't match the current version of Python, which is: 2.7.5 (default, Jun 17 2014, 18:11:42) [GCC 4.8.2 20140120 (Red Hat 4.8.2-16)] If you cannot solve this problem yourself, please go to the yum faq at: http://yum.baseurl.org/wiki/Faq
|
命令yum实为Python脚本,这个错误表示找不到名为yum的Python模块。检查Python的模块搜索路径:
# python Python 2.7.5 (default, Jun 17 2014, 18:11:42) [GCC 4.8.2 20140120 (Red Hat 4.8.2-16)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> print sys.path ['', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/gtk-2.0', '/usr/lib/python2.7/site-packages', '/usr/lib/python2.7/site-packages/setuptools-34.4.1-py2.7.egg', '/usr/lib/python2.7/site-packages/MySQL_python-1.2.5-py2.7-linux-x86_64.egg'] >>> |
如果模块yum可用,可通过如下方法找到它所有路径:
# python >>> import yum >>> print yum.__file__ /usr/lib/python2.7/site-packages/yum/__init__.pyc |
如果模块yum并不存在,则可从其它可用的机器复制一份过来,保持目录一致。如果在执行“import yum”报错“No module named urlgrabber”和“No module named rpmUtils.transaction”,则也需要将urlgrabber等模块复制过来,直到“import yum”不再报错。
执行“yum install docker-ce-19.03.5-3.el7.x86_64.rpm”时报如下错误:
# yum install docker-ce-19.03.5-3.el7.x86_64.rpm error: rpmdb: BDB0113 Thread/process 7020/140405160273920 failed: BDB1507 Thread died in Berkeley DB library error: db5 error(-30973) from dbenv->failchk: BDB0087 DB_RUNRECOVERY: Fatal error, run database recovery error: cannot open Packages index using db5 - (-30973) error: cannot open Packages database in /var/lib/rpm CRITICAL:yum.main: Error: rpmdb open failed |
这个错误是因为RPM数据库损坏了,执行以下操作的修复:
# cd /var/lib/rpm # tar czf x.tar.gz __db.* # rm -f __db.* # rpm --rebuilddb # yum clean all |
然后,可再次执行“yum install docker-ce-19.03.5-3.el7.x86_64.rpm”。
执行“systemctl start docker.service”时报如下错误:
systemd[1]: start request repeated too quickly for docker.service systemd[1]: Failed to start Docker Application Container Engine. systemd[1]: Unit docker.service entered failed state. systemd[1]: docker.service failed. |
“systemctl start docker.service”输出的信息可能不全,可直接查看系统日志文件/var/log/messages,如果看到以下错误信息:
Running modprobe nf_nat failed with message: `modprobe: WARNING: Module nf_nat not found.`, error: exit status 1 |
该错误表示没有加载内核模块“iptable_nat”,执行“modinfo iptable_nat”确认:
# modinfo iptable_nat modinfo: ERROR: Module iptable_nat not found. |
该错误表示没有加载内核模块“iptable_nat”,模块文件位于目录/lib/modules/`uname -r`/kernel/。
# ls /lib/modules/`uname -r`/kernel/ arch crypto drivers fs kernel lib mm net |
内核模块“iptable_nat”又依赖nf_nat和ip_tables等内核模块,成功加载后问题将解决。
# lsmod | grep nat iptable_nat 13011 1 nf_nat_ipv4 13263 1 iptable_nat nf_nat 26711 3 ipt_MASQUERADE,nf_nat_ipv4,iptable_nat nf_conntrack 96187 8 ipt_MASQUERADE,nf_nat,nf_nat_ipv4,xt_conntrack,nf_conntrack_netlink,iptable_nat,nf_conntrack_ipv4,nf_conntrack_ipv6 ip_tables 27239 4 iptable_filter,iptable_mangle,iptable_nat,iptable_raw |
启动容器时报如下错误:
Error response from daemon: oci runtime error: container_linux.go:235: starting container process caused "process_linux.go:258: applying cgroup configuration for process caused \"Cannot set property TasksAccounting, or unknown property.\"". |
这个错误是因为镜像和Linux内核版本不一致,一般是镜像要求更高版本的内核,因此需要升级内核。
执行“yum -y install docker-ce”时报如下错误:
Transaction check error: file /usr/bin/docker from install of docker-ce-cli-1:19.03.1-3.el7.x86_64 conflicts with file from package docker-common-2:1.13.1-96.gitb2f74b2.tl2.x86_64 file /usr/bin/dockerd from install of docker-ce-3:19.03.1-3.el7.x86_64 conflicts with file from package docker-common-2:1.13.1-96.gitb2f74b2.tl2.x86_64 错误概要 ------------- |
这是依赖包版本冲突问题,需先执行“yum -y remove docker-common”删除依赖的包“docker-common”,然后再执行“yum -y install docker-ce”。
启动容器时遇到如下错误:
Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap. |
执行命令“lssubsys --all”检查是否安装了cgroups相关组件,如果执行“yum install -y cgroup-bin”或“yum install -y libcgroup libcgroup-tools”安装。
进一步检查是否打开了内核的“cgroup_enable”和“swapaccount”,如果没有则可编辑/etc/default/grub,为GRUB_CMDLINE_LINUX所在行添加如下内容:
cgroup_enable=memory swapaccount=1 |
在修改文件/etc/default/grub后,得执行命令“/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg”以将/etc/default/grub更新到/boot/grub2/grub.cfg,然后还需重启系统以生效。
启动容器时遇到如下错误:
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?. See 'docker run --help'. |
这个错误是因为没有启动Docker服务。
执行“docker update”时报如下错误:
Error response from daemon: Minimum memoryswap limit should be larger than memory limit, see usage |
这是因为参数“--memory-swap”的值小于参数“-m”的值。
下列错误,可能是因为在64位上跑32位程序:
Value too large for defined data type |
此错误对应的出错代码为EOVERFLOW,原因可能是目标文件超过2GB大小。
下列代码可能会导致这个错误出错(为何说是可能,本节最后部分解释):
// g++ -g -o x x.cpp -m32 #include <errno.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <string> int main(int argc, char* argv[]) { struct stat st; if (stat(argv[1], &st) != 0) { printf("stat failed: %s.\n", strerror(errno)); return 1; } else { printf("%zd\n", st.st_size); return 0; } } |
改成下列后,运行正常:
// g++ -g -o x x.cpp -m32 #include <errno.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <string> int main(int argc, char* argv[]) { struct stat64 st; if (stat64(argv[1], &st) != 0) { printf("stat failed: %s.\n", strerror(errno)); return 1; } else { printf("%zd\n", st.st_size); return 0; } } |
前面说的可能,是因为不同机器的编译环境(可理解为默认编译参数)可能并不相同,因此导致结果是可能,原因是宏“-D_FILE_OFFSET_BITS=64”会影响结果,如果定义了,则效果如同最后一段代码,否则报错“Value too large for defined data type”。
附1:rpm安装
RPM包实际也是一个压缩包,为“RedHat Package Manager”的缩写,在Windows上可用7-zip等软件直接打开见其卢山真面目。以下是RPM命令的常见应用:
命令 | 作用 | 说明 |
rpm -ivh packagename.rpm | 安装 | -i为install之意,即安装,等同--install; -v为verbose之意,即显示详细信息,等同--verbose; -h为hash之意,即显示进度信息,等同--hash。 |
rpm -ivh packagename.rpm --nodeps | 强制安装,并忽略依赖 | |
rpm -ivh packagename.rpm --force | 强制安装,不忽略依赖 | |
rpm -e packagename | 卸载 | |
rpm -qi packagename | 查看信息 | |
rpm -pq packagename.rpm | 查询安装后的名字 | |
rpm -ql packagename | 查询安装后生成的文件 | |
rpm -qlp packagename.rpm | 查询安装后生成的文件 |
RPM没有解决包依赖问题,所以使用它安装时,可能会遇到很多依赖包版本不匹配或者依赖的包不存在问题。就Docker而言,使用RPM包安装,可能并不简单,如果不能yum安装,则更建议直接二进制安装。
Docker RPM包可在Index of linux/centos/7/x86_64/stable/Packages/上找到。
container-selinux等部分包可在CentOS Mirror上找到。
附2:yum安装
Linux上的yum是一个Python脚本,为“Yellow dog Updater, Modified”的缩写,基于RPM的Shell前端软件包管理器。
/etc/yum.conf为yum的配置文件,仓库配置放在目录/etc/yum.repos.d下。如果需添加本地仓库,可在目录/etc/yum.repos.d下新建一仓库配置,然后清除下缓存,执行“yum repolist”即可看到。
以下是yum命令的常见应用:
命令 | 作用 | 说明 |
yum list all | 列举出仓库中的所有包 | |
yum list installed | 列举已安装的 | |
yum list available | 列举可安装的包 | |
yum repolist all | 列举出所有仓库,含禁用的 | |
yum repolist | 列举出可用的仓库 | 等同“yum repolist enabled” |
yum repolist disabled | 列举出禁用的仓库 | |
yum clean all | 清除所有缓存 | |
yum search packagename | 查找可安装的包 | 示例: yum search docker |
yum info packagename | 查询包的摘要信息 | 示例: yum info docker |
yum deplist packagename | 查看包依赖 | 示例: yum deplist docker |
yum list all packagename | 查看仓库中指定名的包 | 救命: yum list all docker |
yum -y install packagename | 安装 | 示例1(安装单个): yum -y install docker 示例2(安装多个): yum -y install \ docker-ce \ docker-ce-cli \ containerd.io \ docker |
yum -y remove packagenameX | 删除安装的包 | 注意packagenameX是命令yum list installed列出的包名(第1列),比如docker-ce-cli.x86_64。 示例1: yum -y remove docker.x86_64 示例2: yum -y remove \ docker-ce-cli.x86_64 |
yum-config-manager \ --add-repo=ADDREPO | 添加和启用一个新的仓库,执行时会在目录/etc/yum.repos.d下生成一个repo文件。 | 示例: yum-config-manager \ --add-repo=\ https://download.docker.com/linux/centos/docker-ce.repo 如果没有yum-config-manager,则可用下列命令安装: yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 yum-config-manager是包yum-utils中的一员。 |
附3:systemctl和systemd
常见systemctl用法:
命令 | 作用 | 说明 |
systemctl start service | 启动服务 | 示例1: system start docker.service 或 system start docker |
systemctl stop service | 停止服务 | 示例1 system stop crond 或 system stop crond.service |
systemctl restart service | 重启服务 | |
systemctl enable service | 设置服务随系统自动启动 | 以docker.service为例,“systemctl enable service”的作用实际等同于: ln -s \ '/etc/systemd/system/docker.service' \ '/etc/systemd/system/multi-user.target.wants/docker.service' |
systemctl disable service | 取消服务随系统自动启动 | 以docker.service为例,“systemctl disable service”的作用实际等同于: rm '/etc/systemd/system/multi-user.target.wants/docker.service' |
systemctl status service | 查看服务状态 | |
systemctl reload | 重加载配置 | 当修改诸如docker.service文件时,需要执行一次reload |
systemctl reboot | 重启系统 | |
systemctl set-default | 设置默认的启动级别,其中multi-user.target对应级别3,graphical.target对应级别5 | 示例1: systemctl \ set-default \ multi-user.target 示例2: systemctl \ set-default \ graphical.target |
systemctl类似于Windows平台的服务管理器,工作原理是通过与服务systemd交互完成各项工作,比如重启crond进程。
systemd是Linux系统启动后的第一个进程,取代了以前的init进程。systemd进程和init进程不会同时存在,低版本Linux为init,高版本Linux为systemd。
“systemctl status”和“systemctl -l status”输出的信息实际来源于系统日志文件“/var/log/message”。
当使用“systemctl start”启动一个服务失败,通过“systemctl -l status”又找不到确切原因时,可尝试直接执行service文件(比如docker.service)中ExecStart的定义的命令,这样可能可查明失败原因。
附4:命令brctl
可用brctl命令管理网桥,为包bridge-utils中的一员。
命令 | 作用 | 说明 |
brctl addbr <bridge> | 创建网桥 | 示例: brctl addbr docker0 |
brctl delbr <bridge> | 删除网桥 | 示例: brctl delbr docker0 |
brctl show <bridge> | 查询网桥信息 | |
brctl setfd <bridge> <time> | 设置网桥转发延迟 | 示例: brctl setfd docker0 10 |
brctl addif <bridge> <device> | 网卡接入网桥 | 示例: brctl addif docker0 eth1 |
brctl delif <bridge> <device> | 删除接入网桥的网卡 | |
brctl stp <bridge> <on> | 启用网桥 | 示例: brctl stp docker0 on |
brctl stp <bridge> <off> | 禁用网桥 | |
brctl showmacs <bridge> | 查看mac信息 | 示例: brctl showmacs docker0 |
附5:命令ip
Linux中网格管理命令,功能覆盖ifconfig、netstat、route、arp等命令,是一个十分强大的大而全集成工具。为包iproute中的一员,而netstat和ifconfig为包net-tools包中的一员(执行“rpm -ql net-tools”可查看)。
常见对比:
Ifconfig/netstat命令 | ip命令 | |
归属包 | net-tools | iproute |
ifconfig | ip link | |
ifconfig eth0 up | ip link set eth0 up | |
查看所有接口,包括已禁用的 | ifconfig -a | ip addr show或ip a |
ifconfig -s | ip -s link | |
netstat -i | ip -s link | |
netstat -r | ip route |
还可使用命令ip创建和设置网桥:
- 创建网桥
ip link add name docker0 type bridge |
注:执行“ip link help”可查看“ip link”的使用帮助。
- 设置网桥的IP和网关
ip addr add dev docker0 172.17.0.1/16 |
注:“172.17.0.1/16”中的“172.17.0.1”为网桥的IP地址,16表示16个1,对应的网关地址为255.255.0.0(十填制数255对应的二进制值为11111111)。
- 启用网桥
ip link set docker0 up |
- 禁用网桥
ip link set docker0 down |
- 删除网桥
ip link delete docker0 type bridge |
附6:内核模块
Linux内核模块放在目录/lib/modules/`uname -r`/kernel下,模块文件以“.ko”为后缀:
# file /lib/modules/`uname -r`/kernel/net/netfilter/nf_nat.ko /lib/modules/3.10.107-1-0046/kernel/net/netfilter/nf_nat.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=1a7527386082c922caeb208c7c9a1d530c079f1d, not stripped |
- 查看模块信息
使用命令modinfo查看模块信息
# modinfo xt_limit.ko filename: /lib/modules/3.10.107-1-0046/kernel/net/netfilter/xt_limit.ko alias: ip6t_limit alias: ipt_limit description: Xtables: rate-limit match author: Herve Eychenne <rv@wallfire.org> license: GPL srcversion: B22C9E4BCCDBDFBFD5D4EFD depends: intree: Y vermagic: 3.10.107-1-0046 SMP mod_unload modversions signer: sig sig_key: 6E:69:6E:67:20:6B:65:79:2C:94:15:C6:82:EA:DB:06:CF:5A:37:57:72:EE:7A:58:2D:CA:23:38 sig_hashalgo: sha512 |
- 查看已加载模块
使用命令lsmod查看已加载模块列表:
# lsmod Module Size Used by nf_nat 26754 0 ip6t_rpfilter 12546 1 ip6t_REJECT 12939 2 nf_conntrack_ipv6 18738 4 nf_defrag_ipv6 34651 1 nf_conntrack_ipv6 # lsmod | grep nf_nat nf_nat 26754 0 nf_conntrack 96187 4 nf_nat,xt_conntrack,nf_conntrack_ipv4,nf_conntrack_ipv6 |
- 卸载模块
使用命令rmmod卸载模块:
# rmmod nf_nat_proto_udplite # rmmod nf_nat.ko |
- 加载模块
使用命令insmod加载模块,要求指定模块文件名的全路径或相对路径:
# insmod ./nf_nat_proto_udplite.ko # insmod netfilter/nf_nat.ko |
也可使用modprobe加载模块,这种方式不需要指定模块路径。modprobe依靠文件/lib/modules/`uname -r`/modules.dep来查找模块文件,因此当在目录/lib/modules/`uname -r`/kernel下有新增模块文件时,需要先执行一次depmod命令,才能执行modprobe加载模块,否则报错:
# modprobe nf_nat modprobe: FATAL: Module nf_nat not found. |
如果模块格式不匹配,将报如下所示错:
# modprobe nf_nat modprobe: ERROR: could not insert 'nf_nat': Exec format error # insmod ./nf_nat.ko insmod: ERROR: could not insert module ./nf_nat.ko: Invalid module format |
- 更新模块依赖关系
模块依赖关系文件为/lib/modules/`uname -r`/modules.dep,当有在目录/lib/modules/`uname -r`/kernel下新增模块文件后,需要执行一次depmod来更新文件modules.dep,否则modprobe将找不到模块文件。