docker运行笔记
2019年10月20日清理docker
你以前可能执行过一些docker命令,给镜像或容器命过名,或者当前有容器正在运行,占用了某些端口。如果不清理,下文的某些命令可能会失败。下面的清理脚本是暴力清理,会删除所有东西。如果你知道怎么清理不要的东西,或者会自己解决冲突,恐怕你也不用看本篇初学者笔记了。
最基本示例
这个dockerfile意思说把宿主机当前目录的index.html复制到镜像/usr/share/nginx/html/index.html。为了成功构建,我们还需要准备一份index.html文件。
docker build -t nginx:v3 .
构建镜像,并命名为nginx:v3。
docker run --name web3 -d -p 80:80 nginx:v3
将镜像实例化为容器,把该容器命名为web3。后台运行。把容器的80端口映射到宿主机的80端口。
这样打开http://localhost/就能看到
这时运行docker ps
,可以看到容器web3正在运行。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d3e2ade58356 nginx:v3 "nginx -g 'daemon of…" 14 seconds ago Up 13 seconds 0.0.0.0:80->80/tcp web3
探索与修改
运行docker run --name web3 -d -p 81:80 nginx:v3
,试试看能不能把容器的80端口映射到宿主机的81端口。
docker: Error response from daemon: Conflict. The container name "/web3" is already in use by container "4815697d6ec798d533fb52c2e56cf185f93804af8662045ca87d267c6b37ccb1". You have to remove (or rename) that container to be able to reuse that name. See 'docker run --help'.
出错了。原来,已经有一个容器叫做web3了,我们不能再实例化一个叫做web3的容器。于是,把--name
选项删掉,命令成功执行。这时打开http://localhost:81能看到大字“Hello, Docker!”。
现在我们把dockerfile修改成
刷新http://localhost:81,发现文字没有改变!回想起来,dockerfile说的是把index.html复制到镜像/usr/share/nginx/html/index.html。现在镜像已经构建完毕,里面的index.html还是老的index.html。我们需要重新构建镜像。
docker build -t nginx:v3 . docker run -d -p 80:80 nginx:v3
第二个命令失败,“docker: Error response from daemon: driver failed programming external connectivity on endpoint relaxed_burnell (cedd92a7cf630d7ba7fd28eea42fa2f5663bc14965aa5a9b5427d067d7b76075): Bind for 0.0.0.0:80 failed: port is already allocated.” 80端口被刚才的容器占用了,我们要停止那个容器。于是运行
这句话的意思是停止当前所有容器,也是相当暴力。然后重新运行docker run -d -p 80:80 nginx:v3
。刷新http://localhost:80,发现终于正确显示“Hello, world!”了。
优化
上面的步骤有一个不好,就是我们要指定镜像名称。我们平时练习,不想给那些乱七八糟的镜像取名字,能不能不取名字直接编译、实例化镜像?
docker build -q .
意思是构建镜像,且只输出镜像ID。外面的命令和刚才的差不多,删除了-d后台运行,添加了--rm
,表示用户按下ctrl+c结束容器后,就把容器删除。
随便修改index.html,然后运行代码,你的修改应当立即生效。对dockerfile进行不合法的修改,运行上述命令,控制台应提示构建失败。
代码还有一个特点,就是会输出日志。每访问一次http://localhost:80控制台就会打印一些东西。如
$ docker run --rm -p 80:80 $(docker build -q .)
172.17.0.1 - - [20/Oct/2019:23:43:27 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" "-"
172.17.0.1 - - [20/Oct/2019:23:43:28 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" "-"
172.17.0.1 - - [20/Oct/2019:23:43:28 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36" "-"
因为当容器以前台模式运行时,docker会重定向stdout和stderr。[4]那具体是哪个进程在输出这些消息呢?已知我们的dockerfile没有运行任何进程,我们就要去其基镜像里看看了。
$ docker history --no-trunc --format "{{.ID}}: {{.CreatedBy}}" nginx
sha256:5a9061639d0aeca4b13f8e18b985eea79e55168969d069febdb6723993ebba7d: /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon off;"]
<missing>: /bin/sh -c #(nop) STOPSIGNAL SIGTERM
<missing>: /bin/sh -c #(nop) EXPOSE 80
<missing>: /bin/sh -c ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
<missing>: /bin/sh -c set -x && addgroup --system --gid 101 nginx && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates && NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; found=''; for server in ha.pool.sks-keyservers.net hkp://keyserver.ubuntu.com:80 hkp://p80.pool.sks-keyservers.net:80 pgp.mit.edu ; do echo "Fetching GPG key $NGINX_GPGKEY from $server"; apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; done; test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* && dpkgArch="$(dpkg --print-architecture)" && nginxPackages=" nginx=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-${PKG_RELEASE} " && case "$dpkgArch" in amd64|i386) echo "deb https://nginx.org/packages/mainline/debian/ buster nginx" >> /etc/apt/sources.list.d/nginx.list && apt-get update ;; *) echo "deb-src https://nginx.org/packages/mainline/debian/ buster nginx" >> /etc/apt/sources.list.d/nginx.list && tempDir="$(mktemp -d)" && chmod 777 "$tempDir" && savedAptMark="$(apt-mark showmanual)" && apt-get update && apt-get build-dep -y $nginxPackages && ( cd "$tempDir" && DEB_BUILD_OPTIONS="nocheck parallel=$(nproc)" apt-get source --compile $nginxPackages ) && apt-mark showmanual | xargs apt-mark auto > /dev/null && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } && ls -lAFh "$tempDir" && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) && grep '^Package: ' "$tempDir/Packages" && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list && apt-get -o Acquire::GzipIndexes=false update ;; esac && apt-get install --no-install-recommends --no-install-suggests -y $nginxPackages gettext-base && apt-get remove --purge --auto-remove -y ca-certificates && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list && if [ -n "$tempDir" ]; then apt-get purge -y --auto-remove && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; fi
<missing>: /bin/sh -c #(nop) ENV PKG_RELEASE=1~buster
<missing>: /bin/sh -c #(nop) ENV NJS_VERSION=0.3.5
<missing>: /bin/sh -c #(nop) ENV NGINX_VERSION=1.17.4
<missing>: /bin/sh -c #(nop) LABEL maintainer=NGINX Docker Maintainers <docker-maint@nginx.com>
<missing>: /bin/sh -c #(nop) CMD ["bash"]
<missing>: /bin/sh -c #(nop) ADD file:74b2987cacab5a6b067ccf3785408687d0bff53dbff198c6d8f06bed5187292c in /
原来基镜像运行了nginx -g daemon off
,docker run
输出的日志就是从这里来的。如果nginx以后台方式运行,docker不光不会输出日志,而且容器会立即退出。[5]
总结
本文介绍了清理docker的代码、停止所有容器的代码、方便调试容器的一次性方法(代码)。
参考资料
. 利用 commit 理解镜像构成. . [2019-10-20].参考资料
- beeman. remove-all-from-docker.sh. . 2016-11-15 [2019-10-20].↑
- 不少文章说Dockerfile的首字母必须大写,但我在Ubuntu上运行docker 19.03,发现小写的dockerfile也能被docker自动加载。为了以后能及时发现错误,下文始终用小写的dockerfile。↑
- starthal. Build and run Dockerfile with one command. . 2018-07-12 [2019-10-20].↑
- . Docker run reference. . [2019-10-20].↑
- . CMD 容器启动命令. . [2019-10-20].↑