docker常用命令

将常用的一些命令记录下,方便以后查阅。

配置文件

服务配置文件

docker 服务的配置文件(可以配置各项启动参数):
/etc/systemd/system/docker.service
内容类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd --insecure-registry hub-dev.hexin.cn -g /data/docker/
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target

daemon.json

/etc/docker/daemon.json
可以配置私有仓库信息(比如内网需要用到 http 协议的私有仓库),内容类似这样:

1
2
3
4
5
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["http://hub.hexin.cn"]
}

注意该文件修改后,必须重启 docker 进程才会生效。

docker 服务

启动

systemctl start docker

重启

systemctl restart docker

关闭

systemctl stop docker

查看 docker 信息

docker info

加入自启动

systemctl enable docker

镜像

搜索镜像

docker search [options] imageName

※ -s num :可以查找多少星以上的镜像
※ –automated:默认 false,显示 automated build 镜像
※ –no-trunk :默认 false ,不以截断方式查找镜像

还可以去https://hub.docker.com/ 网站进行搜索;如果你想看某个镜像具体有哪些标签,也是在这个网站上查询,比如查询 centos 的 tag 列表:https://hub.docker.com/_/centos/

查看镜像的所有标签

需要自己写脚本,参考这个文章:https://blog.csdn.net/kongxx/article/details/86558328

1
2
3
4
5
6
#!/bin/sh

repo_url=https://registry.hub.docker.com/v1/repositories
image_name=$1

curl -s ${repo_url}/${image_name}/tags | json_reformat | grep name | awk '{print $2}' | sed -e 's/"//g'

通过镜像 ID 拉取镜像

查看本地镜像

docker images

拉取镜像

docker pull [options] 镜像名称[:tags]

※ -a :下载所有该 tags 的镜像
※ 忽略 tags 下载最新版本的镜像
比如:docker pull hub.hexin.cn/imageName

拉取并启动镜像

docker run -d hub.hexin.cn/imageName

启动镜像

docker run -t -i a6cd10f85c07 /bin/sh

cannot execute binary file

这个一般是 Dockerfile 中使用了 ENTRYPOINT 来启动某些程序,但是参数设置有误导致的,参考这个文章

需要给你的 ENTRYPOINT 命令加上-c 参数,比如这样:

1
ENTRYPOINT ["/bin/bash", "-l", "-c", "/usr/local/openresty/nginx/sbin/nginx"]

启动镜像(后台):

docker run -d -t -i a6cd10f85c07 /bin/sh

注意:不加/bin/bash,启动后执行完 Dockerfile 中指定的命令,就会关闭容器

启动镜像并添加 host 映射:

docker run -d –add-host this-is-domain1:10.0.6.29 –add-host this-is-domain2:10.0.6.30 -t -i a6cd10f85c07 /bin/sh

启动镜像并随机映射端口:

sudo docker run -d -t -i -P 镜像 ID

启动镜像并映射端口:

sudo docker run -d -t -i -p 10001:22 镜像 ID

启动镜像并映射多个端口:

sudo docker run -d -p 10022:22 -p 13306:3306 -p 10080:80 -p 18080:8080 镜像 ID

1
2
3
4
5
6
7
8
9
小知识:

如果一个参数的选项格式是[],比如

-H=[]host

-p=[]portdirection

这都意味着这个flag可以多次出现,所以此处可以多次指定端口映射规则。

将镜像保存为压缩包

docker save -o nginx.tar nginx:latest

或:

docker save > nginx.tar nginx:latest

导入压缩包,还原镜像

docker load -i nginx.tar

或:

docker load < nginx.tar

删除镜像

docker rmi

unable to delete fc6c02e0c01c (cannot be forced) - image has dependent child images

参考这个回答:

https://stackoverflow.com/questions/38118791/can-t-delete-docker-image-with-dependent-child-images

通过指定镜像:tag 名称来删除:

1
docker rmi centos:test

通过 Dockfile 生成镜像

docker build -f Dockerfile.local -t resource:local .

如果 dockerfile 中需要连接网络,比如下载安装包,那么一般需要制定网络信息,比如指定代理,或者通过--network=host选择使用宿主机的网络:

1
docker build -f ffmpeg -t testffpmeg --network=host  .

重命名镜像和 tag

1
docker tag IMAGEID(镜像id) REPOSITORY:TAG(仓库:标签)

将镜像推送到仓库

首先我们在官网上创建一个仓库(repository),假设名为 zhouchangju/micro-video

然后修改本地的镜像名和 tag,使其和仓库中的名称一致,比如仓库是 zhouchangju/micro-video,则要命名为这种格式:

1
docker tag 172c31c441ff  zhouchangju/micro-video:java-node-puppeteer-ffmpeg-chrome

然后通过 docker login 登录仓库:

1

在推送上去即可:

1
docker push zhouchangju/micro-video:java-node-puppeteer-ffmpeg-chrome

容器

查看全部容器(包括停止的):

docker ps -a

查看所有已启动的容器:

docker ps

查看某个已启动的容器:

docker inspect 容器 id

进入 docker 容器:

docker exec -ti 54c6395feb62 /bin/bash

停止容器

docker stop 容器 ID

停止所有容器

docker stop $(docker ps -q)

重启容器

docker restart 容器 ID

启动容器

docker start 容器 ID

(有时候容器意外停止了,可以重新启动下,里面修改的内容还在的)

查看容器日志

docker logs 容器 ID

完全删除容器(得先停止再删除):

docker stop 容器 ID && docker rm 容器 ID

将容器保存为镜像(注意,镜像名称只能取字符[a-z]和数字[0-9]):

docker commit 容器 ID 新的 j 镜像名称

如何在保存镜像的时候添加说明信息?

可以通过-a 添加作者,-m 添加说明信息,比如:

1
docker commit -a 'xxx@xxx.com' -m "用于测试截取中文的镜像,里面的/home/test目录下有测试脚本test.js" 90ecbda2eb48  testpuppeteer

然后通过 inspect 就可以看到这些信息了:

1
docker inspect testpuppeteer

为什么 docker commit 生成的镜像,没有保存/etc/hosts 的修改信息?

参考这个文章

一、原因
/etc/hosts, /etc/resolv.conf 和/etc/hostname,容器中的这三个文件不存在于镜像,在启动容器的时候,通过 mount 的形式将这些文件挂载到容器内部。因此,如果在容器中修改这些文件的话,修改部分不会存在于容器的 top layer,而是直接写入这三个物理文件中。

为什么重启后修改内容不存在了?原因是:每次 Docker 在启动容器的时候,通过重新构建新的/etc/hosts 文件,这又是为什么呢?原因是:容器重启,IP 地址为改变,hosts 文件中原来的 IP 地址无效,因此理应修改 hosts 文件,否则会产生脏数据。

二、解决办法
在每次启动容器的时候指定 IP、hostname、往/etc/hosts 里添加 hosts,命令如下:

docker run -itd –name hadoop0 –hostname hadoop0 –net network_my –ip 192.168.10.30 –add-host hadoop1:192.168.10.31 –add-host hadoop2:192.168.10.32 -d -P -p 50070:50070 -p 8088:8088 hadoop:master

Docker 系列(四)Docker 网络模式及配置

–hostname :指定 hostname;
–net : 指定网络模式
–ip:指定 IP
–add-host :指定往/etc/hosts 添加的 host

解决容器命令行界面(TTY 窗口)太小的问题

docker exec -it -e LINES=$(tput lines) -e COLUMNS=$(tput cols) 镜像 bash

解决容器不能联网的问题

http://cloud.51cto.com/art/201502/465958.htm

将容器保存为压缩包

docker export -o nginx.tar container

导入压缩包,还原镜像

docker import nginx.tar nginx:tagName

export 命令是从容器(container)中导出 tar 文件,而 save 命令则是从镜像(images)中导出

基于第二点,export 导出的文件再 import 回去时,无法保留镜像所有历史(即每一层 layer 信息,不熟悉的可以去看 Dockerfile),不能进行回滚操作;而 save 是依据镜像来的,所以导入时可以完整保留下每一层 layer 信息。

查看容器的文件/目录变更情况

docker diff container

报错:error: “Read-only file system” setting key “kernel.msgmnb”

error: “Read-only file system” setting key “kernel.msgmnb”
error: “Read-only file system” setting key “kernel.msgmni”

解决方案:加入–privileged 参数,注意要加在前面,不能追加到末尾
docker run -ti –privileged 0705b9e24c78 /bin/bash

启动参数

挂载

简写:docker run -ti -v 宿主机目录:容器内目录

完整:docker run -ti –volume 宿主机目录:容器内目录

比如:

docker run -ti -v /data/dir1:/data1/dir1 -v /data/dir2:/data1/dir2

这一篇文章很详细:https://www.cnblogs.com/ivictor/p/4834864.html

修改挂载的宿主机的文件,docker 里面是可以马上生效的。

MySQL 数据持久化到宿主机

1
docker run -ti -d -p 3306:3306 -v /opt/mysql/data:/var/lib/mysql --name mysql mysql/mysql-server:5.7

参考:https://blog.csdn.net/lvbian/article/details/83030308

容器退出时自动重启

docker run -ti –restart=[always|on-failure:10|unless-stopped|no]

no,默认策略,在容器退出时不重启容器
on-failure,在容器非正常退出时(退出状态非 0),才会重启容器
on-failure:3,在容器非正常退出时重启容器,最多重启 3 次
always,在容器退出时总是重启容器
unless-stopped,在容器退出时总是重启容器,但是不考虑在 Docker 守护进程启动时就已经停止了的容器

容器与主机之间的数据拷贝-docker cp

1
2
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

OPTIONS 说明:

1
-L :保持源目标中的链接

存储

查看硬盘信息

1
docker system df

修改 docker 存储目录

参考这个文章:https://blog.csdn.net/kevinsingapore/article/details/89175398

优化镜像大小

可以使用 docker-squash 这个工具:

https://github.com/jwilder/docker-squash

http://jasonwilder.com/blog/2014/08/19/squashing-docker-images/

1
2
3
4
$ docker save <image id> > image.tar
$ sudo docker-squash -i image.tar -o squashed.tar -t newtag
$ cat squashed.tar | docker load
$ docker images <new image id>

如果 docker 宿主机内存较小,建议手动设置 TMPDIR:

1
TMPDIR=/data/tmp  docker-squash -i video.tar -o squash.tar -t small

很奇怪,我通过 docker-squash 对镜像进行精简后,发现最终导入的镜像大小并没有改变,是我哪里弄错了么?

PS:docker build 有个–squash 参数,可以将多个 layer 整合为一个,以实现精简镜像大小的目的,这个待尝试。

另外合并 RUN 命令也是一个方案,待尝试。

DEBUG

获取容器/镜像的元信息

docker inspect [OPTIONS] NAME|ID [NAME|ID…]

OPTIONS 说明:

-f :指定返回值的模板文件。

-s :显示总的文件大小。

–type :为指定类型返回 JSON。

关于 Go 模板的应用:https://88250.b3log.org/docker-inspect-template-magic-chinese

常见报错

内核版本问题

我遇到过这个问题:制作的 docker 镜像,在有的机器上能跑起来,但是有的机器上,docker run 报如下错误:

1
2
s6-rmrf: fatal: unable to remove /var/run/s6/env-stage1: Invalid argument
s6-mkdir: warning: unable to mkdir /var/run/s6/env-stage2: Invalid argument

问了下云平台的同事,反馈可能是内核版本的问题,需要升级内核。

RUN 执行 source 命令报错

docker 默认应该是用的/bin/sh,和/bin/bash 有些差异,我们改为明确指定使用/bin/bash 即可:

1
RUN /bin/bash -c "source /opt/rh/devtoolset-7/enable"

网上的说法:

sh 不支持 source
bash 支持 source

1
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

1
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"

另外注意:对于环境变量文件/etc/profile 不起作用。

容器启动日志报错:unable to exec import: Argument list too long

(误)一般是内存不足导致的,申请容器扩容。

内存扩容了还是出现这个问题。后来发现,是因为这个报错才导致内存不停增长的,并不是因为内存增长才报错的。

后来尝试给容器加上 read 检查,期望通过自动重启修复,无效。

联系运维,反馈可能是文件多的缘故,他删除了 core.113 文件/目录,再手动重启,就 OK 了。但是我感觉应该和文件数没关系。

Mac 系统

在 M 芯片的 Mac 电脑上,使用 docker pull 拉取镜像时,会默认拉取 arm 架构的镜像,而不是 x86 或 amd64 架构的镜像。

https://zhuanlan.zhihu.com/p/713118127

有 2 个解决方案:

方案一:设置环境变量DOCKER_DEFAULT_PLATFORM

1
export DOCKER_DEFAULT_PLATFORM=linux/amd64

方案二:docker pull 时指定 platform

1
docker pull --platform linux/amd64 openjdk

教训

直接将新镜像存为现有镜像的名称

修改了一点东西,以为没问题,结果出问题了。然后因为我直接覆盖了老镜像,导致无法回滚。

没有弄清楚 s6、Dockerfile 命令、CMD 命令的执行顺序

导致的问题就是一些脚本命令没有执行,比如 nginx 的配置没有拷贝。

执行顺序如下:

1
原始镜像的启动命令->Dockerfile中的常规命令->3个s6脚本->Dockerfile中的CMD命令

几个知识点:
1、init 是在 Dockerfile 中常规命令之后、非 CMD 命令之前执行的,因为这是在新构建的容器起来之后执行的

2、CMD 命令是最后执行的

所以:

1、init 中不能执行挂起操作,否则会导致 nginx 配置拷贝不执行

2、CMD 的 bootstrap 中执行挂起操作