From e65cf126256f05759f90511f5acdd0425b711da1 Mon Sep 17 00:00:00 2001 From: khs1994 Date: Fri, 24 Nov 2017 18:36:30 +0800 Subject: [PATCH 1/6] Add multistage builds #226 --- image/demo/multistage-builds/.gitignore | 1 + image/demo/multistage-builds/Dockerfile | 12 ++ image/demo/multistage-builds/Dockerfile.build | 10 + image/demo/multistage-builds/Dockerfile.copy | 9 + image/demo/multistage-builds/Dockerfile.one | 15 ++ image/demo/multistage-builds/app.go | 7 + image/demo/multistage-builds/build.sh | 14 ++ image/multistage-builds.md | 176 ++++++++++++++++++ 8 files changed, 244 insertions(+) create mode 100644 image/demo/multistage-builds/.gitignore create mode 100644 image/demo/multistage-builds/Dockerfile create mode 100644 image/demo/multistage-builds/Dockerfile.build create mode 100644 image/demo/multistage-builds/Dockerfile.copy create mode 100644 image/demo/multistage-builds/Dockerfile.one create mode 100644 image/demo/multistage-builds/app.go create mode 100755 image/demo/multistage-builds/build.sh diff --git a/image/demo/multistage-builds/.gitignore b/image/demo/multistage-builds/.gitignore new file mode 100644 index 0000000..b80f0bd --- /dev/null +++ b/image/demo/multistage-builds/.gitignore @@ -0,0 +1 @@ +app diff --git a/image/demo/multistage-builds/Dockerfile b/image/demo/multistage-builds/Dockerfile new file mode 100644 index 0000000..5516262 --- /dev/null +++ b/image/demo/multistage-builds/Dockerfile @@ -0,0 +1,12 @@ +FROM golang:1.9-alpine +RUN apk --no-cache add git +WORKDIR /go/src/github.com/go/helloworld/ +RUN go get -d -v github.com/go-sql-driver/mysql +COPY app.go . +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . + +FROM alpine:latest +RUN apk --no-cache add ca-certificates +WORKDIR /root/ +COPY --from=0 /go/src/github.com/go/helloworld/app . +CMD ["./app"] diff --git a/image/demo/multistage-builds/Dockerfile.build b/image/demo/multistage-builds/Dockerfile.build new file mode 100644 index 0000000..60e97ba --- /dev/null +++ b/image/demo/multistage-builds/Dockerfile.build @@ -0,0 +1,10 @@ +FROM golang:1.9-alpine + +RUN apk --no-cache add git + +WORKDIR /go/src/github.com/go/helloworld + +COPY app.go . + +RUN go get -d -v github.com/go-sql-driver/mysql \ + && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . diff --git a/image/demo/multistage-builds/Dockerfile.copy b/image/demo/multistage-builds/Dockerfile.copy new file mode 100644 index 0000000..53f65df --- /dev/null +++ b/image/demo/multistage-builds/Dockerfile.copy @@ -0,0 +1,9 @@ +FROM alpine:latest + +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +COPY app . + +CMD ["./app"] diff --git a/image/demo/multistage-builds/Dockerfile.one b/image/demo/multistage-builds/Dockerfile.one new file mode 100644 index 0000000..79694e3 --- /dev/null +++ b/image/demo/multistage-builds/Dockerfile.one @@ -0,0 +1,15 @@ +FROM golang:1.9-alpine + +RUN apk --no-cache add git ca-certificates + +WORKDIR /go/src/github.com/go/helloworld/ + +COPY app.go . + +RUN go get -d -v github.com/go-sql-driver/mysql \ + && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ + && cp /go/src/github.com/go/helloworld/app /root + +WORKDIR /root/ + +CMD ["./app"] diff --git a/image/demo/multistage-builds/app.go b/image/demo/multistage-builds/app.go new file mode 100644 index 0000000..0141105 --- /dev/null +++ b/image/demo/multistage-builds/app.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main(){ + fmt.Printf("Hello World!"); +} diff --git a/image/demo/multistage-builds/build.sh b/image/demo/multistage-builds/build.sh new file mode 100755 index 0000000..596a1e7 --- /dev/null +++ b/image/demo/multistage-builds/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +echo Building go/helloworld:build + +docker build -t go/helloworld:build . -f Dockerfile.build + +docker create --name extract go/helloworld:build +docker cp extract:/go/src/github.com/go/helloworld/app ./app +docker rm -f extract + +echo Building go/helloworld:2 + +docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy +rm ./app diff --git a/image/multistage-builds.md b/image/multistage-builds.md index 4d474e1..046b6ad 100644 --- a/image/multistage-builds.md +++ b/image/multistage-builds.md @@ -1 +1,177 @@ ## 多阶段构建 + +### 之前的做法 + +在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式: + +#### 全部放入一个 Dockerfile + +一种方式是将所有的构建过程编包含在一个 `Dockerfile` 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题: + + * `Dockerfile` 特别长,可维护性降低 + + * 镜像层次多,镜像体积较大,部署时间变长 + + * 源代码存在泄露的风险 + +例如 + +编写 `app.go` 文件,该程序输出 `Hello World!` + +```go +package main + +import "fmt" + +func main(){ + fmt.Printf("Hello World!"); +} +``` + +编写 `Dockerfile.one` 文件 + +```docker +FROM golang:1.9-alpine + +RUN apk --no-cache add git ca-certificates + +WORKDIR /go/src/github.com/go/helloworld/ + +COPY app.go . + +RUN go get -d -v github.com/go-sql-driver/mysql \ + && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ + && cp /go/src/github.com/go/helloworld/app /root + +WORKDIR /root/ + +CMD ["./app"] +``` + +构建镜像 + +```bash +$ docker build -t go/helloworld:1 -f Dockerfile.one . +``` + +#### 分散到多个 Dockerfile + +另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。 + +例如 + +编写 `Dockerfile.build` 文件 + +```docker +FROM golang:1.9-alpine + +RUN apk --no-cache add git + +WORKDIR /go/src/github.com/go/helloworld + +COPY app.go . + +RUN go get -d -v github.com/go-sql-driver/mysql \ + && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . +``` + +编写 `Dockerfile.copy` 文件 + +```docker +FROM alpine:latest + +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +COPY app . + +CMD ["./app"] +``` + +新建 `build.sh` + +```bash +#!/bin/sh +echo Building go/helloworld:build + +docker build -t go/helloworld:build . -f Dockerfile.build + +docker create --name extract go/helloworld:build +docker cp extract:/go/src/github.com/go/helloworld/app ./app +docker rm -f extract + +echo Building go/helloworld:2 + +docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy +rm ./app +``` + +现在运行脚本即可构建镜像 + +```bash +$ chmod +x build.sh + +$ ./build.sh +``` + +对比两种方式生成的镜像大小 + +```bash +$ docker images + +REPOSITORY TAG IMAGE ID CREATED SIZE +go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB +go/helloworld 1 f55d3e16affc 2 minutes ago 295MB +``` + +### 使用多阶段构建 + +为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`: + +例如 + +编写 `Dockerfile` 文件 + +```docker +FROM golang:1.9-alpine + +RUN apk --no-cache add git + +WORKDIR /go/src/github.com/go/helloworld/ + +RUN go get -d -v github.com/go-sql-driver/mysql + +COPY app.go . + +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . + +FROM alpine:latest + +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +COPY --from=0 /go/src/github.com/go/helloworld/app . + +CMD ["./app"] +``` + +构建镜像 + +```bash +$ docker build -t go/helloworld:3 . +``` + +对比三个镜像大小 + +```bash +$ docker images + +REPOSITORY TAG IMAGE ID CREATED SIZE +go/helloworld 3 d6911ed9c846 7 seconds ago 6.47MB +go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB +go/helloworld 1 f55d3e16affc 2 minutes ago 295MB +``` + +很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。 From f2386afe6c99d3752310d3c4669d94e5badc4cea Mon Sep 17 00:00:00 2001 From: khs1994 Date: Fri, 24 Nov 2017 18:37:38 +0800 Subject: [PATCH 2/6] Add multistage builds #226 --- image/demo/multistage-builds/Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/image/demo/multistage-builds/Dockerfile b/image/demo/multistage-builds/Dockerfile index 5516262..c54c11d 100644 --- a/image/demo/multistage-builds/Dockerfile +++ b/image/demo/multistage-builds/Dockerfile @@ -1,12 +1,21 @@ FROM golang:1.9-alpine + RUN apk --no-cache add git + WORKDIR /go/src/github.com/go/helloworld/ + RUN go get -d -v github.com/go-sql-driver/mysql + COPY app.go . + RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest + RUN apk --no-cache add ca-certificates + WORKDIR /root/ + COPY --from=0 /go/src/github.com/go/helloworld/app . + CMD ["./app"] From 4eabbf4661828fbf157ddedecb55eaa33aa71ee6 Mon Sep 17 00:00:00 2001 From: khs1994 Date: Fri, 24 Nov 2017 18:39:59 +0800 Subject: [PATCH 3/6] Add multistage builds #226 --- SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SUMMARY.md b/SUMMARY.md index 9ec42c7..a78c8b5 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -37,6 +37,7 @@ * [HEALTHCHECK 健康检查](image/dockerfile/healthcheck.md) * [ONBUILD 为他人作嫁衣裳](image/dockerfile/onbuild.md) * [参考文档](image/dockerfile/references.md) + * [Dockerfile 多阶段构建](image/multistage-builds.md) * [其它制作镜像的方式](image/other.md) * [删除本地镜像](image/rmi.md) * [实现原理](image/internal.md) From fd1eb89c1e29db4f775b0d23bb5958df6d85bfe0 Mon Sep 17 00:00:00 2001 From: khs1994 Date: Fri, 24 Nov 2017 22:42:17 +0800 Subject: [PATCH 4/6] Update content --- revision.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/revision.md b/revision.md index 35d44ab..ef8dd1d 100644 --- a/revision.md +++ b/revision.md @@ -7,9 +7,7 @@ * 0.9-rc2: 2017-12-10 * 更新 `CoreOS` 章节 - * 增加 `Docker Cloud` 介绍 - * 增加 `Docker Store` 介绍 - + * 0.9-rc1: 2017-11-30 * 根据最新版本(v17.09)修订内容 From c9ee2a34e4b416a6a1f99662497422dffe998bca Mon Sep 17 00:00:00 2001 From: khs1994 Date: Fri, 24 Nov 2017 22:42:49 +0800 Subject: [PATCH 5/6] Fix #245 --- repository/dockerhub.md | 89 ++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/repository/dockerhub.md b/repository/dockerhub.md index 6bd9ad8..e989ec8 100644 --- a/repository/dockerhub.md +++ b/repository/dockerhub.md @@ -1,15 +1,23 @@ ## Docker Hub -目前 Docker 官方维护了一个公共仓库 [Docker Hub](https://hub.docker.com/),其中已经包括了超过 15,000 的镜像。大部分需求,都可以通过在 Docker Hub 中直接下载镜像来实现。 -### 注册 -你可以在 https://cloud.docker.com 免费注册一个 Docker 账号。 -### 登录 -可以通过执行 `docker login` 命令交互式的输入用户名及密码来完成在命令行界面的登录。 -登录成功后,本地用户目录的 `.dockercfg` 中将保存用户的认证信息。 -### 基本操作 +目前 Docker 官方维护了一个公共仓库 [Docker Hub](https://hub.docker.com/),其中已经包括了数量超过 15,000 的镜像。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。 + +### 注册 + +你可以在 https://cloud.docker.com 免费注册一个 Docker 账号。 + +### 登录 + +可以通过执行 `docker login` 命令交互式的输入用户名及密码来完成在命令行界面登录 Docker Hub。 + +你可以通过 `docker logout` 退出登录。 + +### 拉取镜像 + 你可以通过 `docker search` 命令来查找官方仓库中的镜像,并利用 `docker pull` 命令来将它下载到本地。 -例如以 centos 为关键词进行搜索: +例如以 `centos` 为关键词进行搜索: + ```bash $ docker search centos NAME DESCRIPTION STARS OFFICIAL AUTOMATED @@ -18,18 +26,22 @@ tianon/centos CentOS 5 and 6, created using ri blalor/centos Bare-bones base CentOS 6.5 image 6 [OK] saltstack/centos-6-minimal 6 [OK] tutum/centos-6.4 DEPRECATED. Use tutum/centos:6.4 instead. ... 5 [OK] -... ``` -可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、星级(表示该镜像的受欢迎程度)、是否官方创建、是否自动创建。 + +可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、收藏数(表示该镜像的受关注程度)、是否官方创建、是否自动创建。 + 官方的镜像说明是官方项目组创建和维护的,automated 资源允许用户验证镜像的来源和内容。 根据是否是官方提供,可将镜像资源分为两类。 -一种是类似 centos 这样的基础镜像,被称为基础或根镜像。这些基础镜像是由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。 -还有一种类型,比如 `tianon/centos` 镜像,它是由 Docker 的用户创建并维护的,往往带有用户名称前缀。可以通过前缀 `user_name/` 来指定使用某个用户提供的镜像,比如 tianon 用户。 -另外,在查找的时候通过 `-s N` 参数可以指定仅显示评价为 `N` 星以上的镜像(新版本Docker推荐使用`--filter=stars=N`参数)。 +一种是类似 `centos` 这样的镜像,被称为基础镜像或根镜像。这些基础镜像由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。 + +还有一种类型,比如 `tianon/centos` 镜像,它是由 Docker 的用户创建并维护的,往往带有用户名称前缀。可以通过前缀 `username/` 来指定使用某个用户提供的镜像,比如 tianon 用户。 + +另外,在查找的时候通过 `--filter=stars=N` 参数可以指定仅显示收藏数量为 `N` 以上的镜像。 + +下载官方 `centos` 镜像到本地。 -下载官方 centos 镜像到本地。 ```bash $ docker pull centos Pulling repository centos @@ -38,19 +50,48 @@ Pulling repository centos 511136ea3c5a: Download complete 7064731afe90: Download complete ``` -用户也可以在登录后通过 `docker push` 命令来将镜像推送到 Docker Hub。 + +### 推送镜像 + +用户也可以在登录后通过 `docker push` 命令来将自己的镜像推送到 Docker Hub。 + +以下命令中的 `username` 请替换为你的 Docker 账号用户名。 + +```bash +$ docker tag ubuntu:17.10 username/ubuntu:17.10 + +$ docker images + +REPOSITORY TAG IMAGE ID CREATED SIZE +ubuntu 17.10 275d79972a86 6 days ago 94.6MB +username/ubuntu 17.10 275d79972a86 6 days ago 94.6MB + +$ docker push username/ubuntu:17.10 + +$ docker search username + +NAME DESCRIPTION STARS OFFICIAL AUTOMATED +username/ubuntu +``` ### 自动创建 -自动创建(Automated Builds)功能对于需要经常升级镜像内程序来说,十分方便。 -有时候,用户创建了镜像,安装了某个软件,如果软件发布新版本则需要手动更新镜像。。 -而自动创建允许用户通过 Docker Hub 指定跟踪一个目标网站(目前支持 [GitHub](https://github.com) 或 [BitBucket](https://bitbucket.org))上的项目,一旦项目发生新的提交,则自动执行创建。 +自动创建(Automated Builds)功能对于需要经常升级镜像内程序来说,十分方便。 + +有时候,用户创建了镜像,安装了某个软件,如果软件发布新版本则需要手动更新镜像。 + +而自动创建允许用户通过 Docker Hub 指定跟踪一个目标网站(目前支持 [GitHub](https://github.com) 或 [BitBucket](https://bitbucket.org))上的项目,一旦项目发生新的提交或者创建新的标签(tag),则自动执行创建。 要配置自动创建,包括如下的步骤: -* 创建并登录 Docker Hub,以及目标网站; -* 在目标网站中连接帐户到 Docker Hub; -* 在 Docker Hub 中 [配置一个自动创建](https://registry.hub.docker.com/builds/add/); -* 选取一个目标网站中的项目(需要含 Dockerfile)和分支; -* 指定 Dockerfile 的位置,并提交创建。 -之后,可以 在Docker Hub 的 [自动创建页面](https://registry.hub.docker.com/builds/) 中跟踪每次创建的状态。 +* 创建并登录 Docker Hub,以及目标网站; + +* 在目标网站中连接帐户到 Docker Hub; + +* 在 Docker Hub 中 [配置一个自动创建](https://registry.hub.docker.com/builds/add/); + +* 选取一个目标网站中的项目(需要含 `Dockerfile`)和分支; + +* 指定 `Dockerfile` 的位置,并提交创建。 + +之后,可以在 Docker Hub 的 [自动创建页面](https://registry.hub.docker.com/builds/) 中跟踪每次创建的状态。 From 766f3015aa36a3b22fb62a82b0ad64b824e4702b Mon Sep 17 00:00:00 2001 From: khs1994 Date: Sat, 25 Nov 2017 09:28:28 +0800 Subject: [PATCH 6/6] Remove english --- container/daemon.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/container/daemon.md b/container/daemon.md index fd27047..582e2f4 100644 --- a/container/daemon.md +++ b/container/daemon.md @@ -1,4 +1,4 @@ -## 后台(background)运行 +## 后台运行 更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 `-d` 参数来实现。 @@ -7,7 +7,7 @@ 如果不使用 `-d` 参数运行容器。 ```bash -$ docker run ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" +$ docker run ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done" hello world hello world hello world @@ -19,7 +19,7 @@ hello world 如果使用了 `-d` 参数运行容器。 ```bash -$ docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" +$ docker run -d ubuntu:17.10 /bin/sh -c "while true; do echo hello world; sleep 1; done" 77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a ``` @@ -32,7 +32,7 @@ $ docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep ```bash $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -77b2dc01fe0f ubuntu:14.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright +77b2dc01fe0f ubuntu:17.10 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright ``` 要获取容器的输出信息,可以通过 `docker logs` 命令。