这篇文章是洒家刚接触 Docker 时写的,部分操作即使在当时也不太恰当。推荐使用 Docker Compose 等容器编排工具,尽量不要直接使用 docker
命令。
由于 Docker 版本变化很快(笑),这篇文章的内容已经过时,可能不会再更新。建议查阅 Docker Documentation。
这篇文章最初发布于旧博客。2017 年 4 月 14 日搭建新博客时,对内容做了一些增改,作为测试文章发出来。
这篇文章针对 Ubuntu Server 16.04 和 Docker 1.12.6,主要参考《Docker 技术入门与实战》(杨保华等编著),内容都是洒家用过的命令。
安装¶
现在 Docker 又分成了 Community Edition 和 Enterprise Edition,以前安装 docker.io
包的命令已经过时,请参考官方文档的安装方法。
搜索镜像¶
一般我们只需要拉取官方镜像,基于官方镜像写 Dockerfile。常用的镜像也就那几个,因此搜索功能并不常用,一般直接在 Docker Hub 网站搜索即可。
使用命令搜索¶
我们也可以使用 docker
命令搜索:
# docker search debian
输出:
NAME | DESCRIPTION | STARS | OFFICIAL | AUTOMATED |
---|---|---|---|---|
debian | Debian is a Linux distribution that's comp... | 1519 | [OK] | |
neurodebian | NeuroDebian provides neuroscience research... | 25 | [OK] | |
jesselang/debian-vagrant | Stock Debian Images made Vagrant-friendly ... | 8 | [OK] | |
armbuild/debian | ARMHF port of debian | 8 | [OK] |
常用镜像¶
下载镜像¶
指定镜像的 tag:
# docker pull php:5.6.24-apache
如果不指定 tag,则视为使用默认 latest
tag:
# docker pull centos
显示本地镜像¶
# docker images
输出:
REPOSITORY | TAG | IMAGE ID | CREATED | VIRTUAL SIZE |
---|---|---|---|---|
ubuntu | latest | 4ef6a5ece191 | 3 days ago | 120.1 MB |
reinblau/lamp | latest | e9df29833f32 | 9 days ago | 703.8 MB |
创建并启动容器¶
临时运行 ubuntu:latest
镜像(退出后自动删除容器),把工作目录挂载到容器中,把宿主机 8080 端口映射到容器 80 端口
# docker run -it --rm --mount "type=bind,src=$(pwd),dst=/opt" -w /opt -p 8080:80 ubuntu:latest bash
root@0123456789ab:/opt# pwd
/opt
运行某 LAMP 镜像,把宿主机 8080 端口映射到容器 80 端口,e9d
是 镜像 ID 或镜像名
# docker run -it -p 8080:80 e9d apache2
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.1. Set the 'ServerName' directive globally to suppress this message
# docker run -it -p 8080:80 e9d /bin/bash
root@0123456789ab:/var/www/html# apache2
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
在后台运行,启动后容器内自动运行 /root/run.sh
# docker run -itd -p 8080:80 e9d /root/run.sh
参数¶
加上 -i
和 -t
可以先按 Ctrl
+ P
,再按 Ctrl
+ Q
unattach(退出并保持运行)。
-d, --detach=false Run container in background and print container ID
-i, --interactive=false Keep STDIN open even if not attached
-P, --publish-all=false Publish all exposed ports to random ports
-p, --publish=[] Publish a container's port(s) to the host
-t, --tty=false Allocate a pseudo-TTY
--name string Assign a name to the container
列出容器¶
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ac4c74c9ac8a e9d:latest "/bin/bash" 7 minutes ago Up 7 minutes 0.0.0.0:8080->80/tcp insane_mayer
3a4b37b41ea7 e9d:latest "apache2" 7 minutes ago Exited (0) 7 minutes ago suspicious_darwin
参数¶
-a, --all=false Show all containers (default shows just running)
-q, --quiet=false Only display numeric IDs
依附到运行中的容器¶
ac4c
是容器号
# docker attach ac4c
操作完毕退出时,不要按 Ctrl
+ C
,否则会停止 Docker 容器。
要先按 Ctrl
+ P
,再按 Ctrl
+ Q
。
在容器内增加进程¶
使用 docker exec
命令:
# docker exec -it 88c /bin/bash
退出:输入 exit
命令(不必先按 Ctrl
+ P
再按 Ctrl
+ Q
)
容器内外复制文件¶
如果有这种需求,建议使用 volume。
c9f
是容器 ID
容器外向容器内¶
# docker exec -i c9f /bin/sh -c 'cat > /var/static/original/img/xxx.jpg' < ./xxx.jpg
# docker exec -i 7d0 /bin/sh -c 'cat > /home/ctf/pwn1' < ./pwn1
容器内向容器外¶
# docker cp c9f:/opt/CTFd/CTFd/static/original/img/xxx.jpg ./
目录自动递归复制
查看端口映射¶
ac4c
是容器 ID
# docker port ac4c
80/tcp -> 0.0.0.0:8080
Dockerfile¶
ENTRYPOINT 和 CMD 的区别¶
The main purpose of a CMD is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT instruction as well.
- CMD ["executable","param1","param2"] (exec form, this is the preferred form)
- CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
- CMD command param1 param2 (shell form)
从 Dockerfile 创建镜像¶
# docker build -t mylamp/test ~/Docker/mylamp_test/
上例中,Dockerfile 文件位于 ~/Docker/mylamp_test/
,镜像 tag 为 mylamp/test
参数¶
-t, --tag= Repository name (and optionally a tag) for the image
删除镜像¶
先删除所有依赖容器,再删除镜像。
后面跟上标签或 ID,跟标签会先删除标签(untag),如果没有标签指向镜像,就删除(delete)镜像。
跟 ID,删除所有相关标签(untag),再删除(delete)镜像。
# docker rmi 2318
# docker rmi ubuntu
删除容器¶
# docker rm e81
停止容器¶
docker stop¶
# docker stop e81
命令用法:
Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
Options:
-t, --time int Seconds to wait for stop before killing it (default 10)
使用 docker stop
命令,Docker 首先会向容器发送一个 SIGTERM
信号。如果默认 10 秒之后没有停止,会发送 SIGKILL
信号强行停止。可以用 -t
参数修改等待时间。
Docker 1.12.6 存在的 bug:如果用一个 Shell Script 脚本作为 Docker 的 ENTRYPOINT
,最后一条命令是 sleep infinity
或者 exec sleep infinity
等都会出现可以收到 SIGTERM
但是不能立即停止的问题。暂时的解决方法是 Shell Script 中最后执行 exec bash
才对 SIGTERM
有反应。
docker kill¶
如果想发送 SIGKILL
信号直接杀死容器,可以使用:
# docker kill e81
命令用法:
Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
Options:
-s, --signal string Signal to send to the container (default "KILL")
批量操作容器¶
停止所有正在运行的容器:
# docker stop $(docker ps -q)
删除所有已经停止的容器:
# docker container prune
删除所有已经停止的容器(旧方法,利用正在运行的容器无法删除,会报错并跳过的特性):
# docker rm $(docker ps -a -q)
更改容器端口¶
建议使用 Docker Compose 和 volume,不要在 container、iptables 上瞎搞。
以 CTFd 为例。老版本的 CTFd 没有使用 volume,可以直接这么搞
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e669c2bddb74 ctfd "gunicorn --bind 0.0." 16 minutes ago Up 16 minutes 0.0.0.0:8086->8000/tcp ctfd
# docker commit e669 ctfdrunning
sha256:bae813fdc553022c9a6fdb2bb7bcddb182cb2c7ab9ef396ac9941ab3ef17a8e2
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ctfdrunning latest bae813fdc553 4 seconds ago 507.2 MB
# docker stop e669
# docker run -itd -p 8000:8000 --name ctfd_newport ctfdrunning
CTFd 的新版本有 volume,docker commit
不包括 volume。可以运行一个新的容器,直接加上参数
# docker run -itd -p 8912:8000 --name ctfd_newport --volumes-from <老的 container 的 name> <ctfd 的 image 名>
查看容器详细信息¶
使用 docker inspect
命令:
Usage: docker inspect [OPTIONS] CONTAINER|IMAGE|TASK [CONTAINER|IMAGE|TASK...]
Return low-level information on a container, image or task
-f, --format Format the output using the given go template
--help Print usage
-s, --size Display total file sizes if the type is container
--type Return JSON for specified type, (e.g image, container or task)
Volume¶
查看所有 volume
# docker volume inspect $(docker volume ls -q)