Use vuepress build book

Signed-off-by: Kang HuaiShuai <khs1994@khs1994.com>
This commit is contained in:
Kang HuaiShuai 2019-10-29 14:31:45 +08:00
parent 7690686ddb
commit c788212aad
No known key found for this signature in database
GPG Key ID: 0A380828B1C243A7
35 changed files with 690 additions and 84 deletions

View File

@ -16,3 +16,17 @@ jobs:
uses: docker://yeasy/docker_practice uses: docker://yeasy/docker_practice
with: with:
args: build args: build
- name: vuepress
run: |
npx vuepress build
- name: Upload Vuepress dist
uses: docker://pcit/pages
env:
PCIT_EMAIL: khs1994@khs1994.com
PCIT_GIT_TOKEN: ${{ secrets.PCIT_GIT_TOKEN }}
PCIT_GIT_URL: github.com/docker-practice/vuepress
PCIT_KEEP_HISTORY: "1"
PCIT_LOCAL_DIR: .vuepress/dist
PCIT_MESSAGE: Sync from yeasy/docker-practice@${{github.sha}} by PCIT
PCIT_TARGET_BRANCH: master
PCIT_USERNAME: khs1994

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ _book/
*.edx *.edx
.DS_Store .DS_Store
node_modules/ node_modules/
.vuepress/dist

352
.vuepress/config.js Normal file
View File

@ -0,0 +1,352 @@
module.exports = {
title: 'Docker 从入门到实践',
base: '/',
themeConfig: {
docsRepo: 'yeasy/docker_practice',
docsDir: '/',
editLinks: true,
nav: [{
text: '安装 Docker',
link: '/install/',
},
{
text: 'Docker 入门',
link: '/'
},
{
text: 'Docker 实战',
link: '/cases/os/'
},
{
text: 'CI/CD',
link: '/cases/ci/'
},
{
text: 'Docker 仓库',
link: '/repository/'
},
{
text: '底层实现',
link: '/underly/',
},
{
text: 'Compose',
link: '/compose/',
},
{
text: 'Kubernetes',
link: '/kubernetes/',
},
{
text: 'GitHub',
link: 'https://github.com/yeasy/docker_practice'
},
// {
// text: '捐赠',
// link: ''
// },
{
text: '腾讯云容器服务',
link: 'https://cloud.tencent.com/redirect.php?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61'
},
// {
// text: '语言',
// items: [{
// text: 'English',
// link: ''
// }]
// }
],
sidebar: {
'/kubernetes/': [
'intro',
'quickstart',
'concepts',
'kubectl',
'design',
],
'/compose/': [
'introduction',
'install',
'usage',
'commands',
'compose_file',
'django',
'rails',
'wordpress',
],
'/install/': [
'/install/',
'ubuntu',
'debian',
'fedora',
'centos',
'raspberry-pi',
'mac',
'windows',
'mirror',
],
'/underly/': [
'/underly/',
'arch',
'namespace',
'cgroups',
'ufs',
'container_format',
'network',
],
'/repository/': [
'/repository/',
'dockerhub',
'registry',
'registry_auth',
'nexus3_registry',
],
'/cases/os/': [
{
title: "操作系统",
collapsable:false,
children: [
'/cases/os/',
'busybox',
'alpine',
'debian',
'centos',
'summary',
],
},
],
'/cases/ci/': [
'/cases/ci/',
'/cases/ci/actions/',
{
title: "Drone",
collapsable: false,
children: [
'drone/',
'drone/install'
]
},
'travis/'
],
'/': [
'/',
'/CHANGELOG',
'/CONTRIBUTING',
{
title: "Docker 简介",
collapsable: false,
children: [
'/introduction/',
'/introduction/what',
'/introduction/why',
]
},{
title: "基本概念",
collapsable: false,
children: [
'/basic_concept/',
'/basic_concept/image',
'/basic_concept/container',
'/basic_concept/repository'
]
},
{
title: "使用镜像",
collapsable: false,
children: [
'/image/',
'/image/pull',
'/image/list',
'/image/rm',
'/image/commit',
'/image/build',
'/image/other.md',
'/image/internal.md',
]
},
{
title: 'Dockerfile',
collapsable: false,
children: [
"/image/dockerfile/",
'/image/dockerfile/copy',
'/image/dockerfile/add',
'/image/dockerfile/cmd',
'/image/dockerfile/entrypoint',
'/image/dockerfile/env',
'/image/dockerfile/arg',
'/image/dockerfile/volume',
'/image/dockerfile/expose',
'/image/dockerfile/workdir',
'/image/dockerfile/user',
'/image/dockerfile/healthcheck',
'/image/dockerfile/onbuild',
'/image/dockerfile/references',
'/image/multistage-builds/',
'/image/multistage-builds/laravel',
'/image/manifest',
'/image/buildx_multi-arch-images',
'/image/buildkit',
'/image/buildx',
]
},{
title: "操作容器",
collapsable: false,
children: [
'container/',
'container/run',
'container/daemon',
'container/stop',
'container/attach_exec',
'container/import_export',
'container/rm',
],
},
{
title: "数据管理",
collapsable:false,
children: [
'data_management/',
'data_management/volume',
'data_management/bind-mounts',
],
},{
title: "使用网络",
collapsable:false,
children: [
'network/',
'network/port_mapping',
'network/linking',
'network/dns',
],
},
{
title: "高级网络配置",
collapsable:false,
children: [
'advanced_network/',
'advanced_network/quick_guide',
'advanced_network/access_control',
'advanced_network/port_mapping',
'advanced_network/bridge',
'advanced_network/example',
'advanced_network/config_file',
'advanced_network/ptp',
],
},
{
title: "Swarm mode",
collapsable:false,
children: [
'swarm_mode/',
'swarm_mode/overview',
'swarm_mode/create',
'swarm_mode/deploy',
'swarm_mode/stack',
'swarm_mode/secret',
'swarm_mode/config',
'swarm_mode/rolling_update',
],
},
{
title: "安全",
collapsable: false,
children: [
'security/',
'security/kernel_ns',
'security/control_group',
'security/daemon_sec',
'security/kernel_capability',
'security/other_feature',
'security/summary',
],
},
{
title: "Etcd",
collapsable:false,
children: [
'etcd/',
'etcd/intro',
'etcd/install',
'etcd/cluster',
'etcd/etcdctl',
],
},
{
title: "Fedora CoreOS",
collapsable: false,
children: [
'coreos/',
'coreos/intro',
'coreos/intro_tools',
],
},
{
title: "容器与云计算",
collapsable:false,
children: [
'cloud/',
'cloud/intro',
'cloud/aws',
'cloud/tencentCloud',
'cloud/alicloud',
'cloud/summary',
],
},
{
title: "Docker 开源项目",
collapsable:false,
children:[
'opensource/',
'opensource/linuxkit',
],
},
{
title: "附录",
collapsable:false,
children: [
'appendix/',
'appendix/faq/',
'appendix/repo/',
'appendix/repo/ubuntu',
'appendix/repo/centos',
'appendix/repo/nginx',
'appendix/repo/php',
'appendix/repo/nodejs',
'appendix/repo/mysql',
'appendix/repo/wordpress',
'appendix/repo/mongodb',
'appendix/repo/redis',
'appendix/command/',
'appendix/best_practices',
'appendix/debug',
'appendix/resources'
],
},
{
title: "Docker Machine",
collapsable: false,
children: [
'machine/',
'machine/install',
'machine/usage',
],
},
{
title: 'Mesos',
collapsable: false,
children: [
'/mesos/intro',
'/mesos/installation',
'/mesos/architecture',
'/mesos/configuration',
'/mesos/monitor',
'/mesos/framework',
'/mesos/summary',
]
},
],
},
}
}

View File

@ -1,8 +1,9 @@
## 主要修订记录 # 修订记录
* 1.1.0 2019-12-31 * 1.1.0 2019-12-31
* 全面支持 v19.x 新版本 * 全面支持 v19.x 新版本
* 增加 `BuildKit` * 增加 `BuildKit`
* 增加 `docker buildx` 命令使用说明
* 增加 `docker manifest` 命令使用说明 * 增加 `docker manifest` 命令使用说明
* 移除 `Ubuntu 14.04` `Debian 8` `Debian 7` * 移除 `Ubuntu 14.04` `Debian 8` `Debian 7`

View File

@ -1,4 +1,4 @@
## 如何贡献项目 # 如何贡献
领取或创建新的 [Issue](https://github.com/yeasy/docker_practice/issues),如 [issue 235](https://github.com/yeasy/docker_practice/issues/235),添加自己为 `Assignee`。 领取或创建新的 [Issue](https://github.com/yeasy/docker_practice/issues),如 [issue 235](https://github.com/yeasy/docker_practice/issues/235),添加自己为 `Assignee`。

View File

@ -42,7 +42,9 @@
* [Dockerfile 多阶段构建](image/multistage-builds/README.md) * [Dockerfile 多阶段构建](image/multistage-builds/README.md)
* [实战多阶段构建 Laravel 镜像](image/multistage-builds/laravel.md) * [实战多阶段构建 Laravel 镜像](image/multistage-builds/laravel.md)
* [构建多种系统架构支持的 Docker 镜像](image/manifest.md) * [构建多种系统架构支持的 Docker 镜像](image/manifest.md)
* [使用 BuildKit 构建镜像](image/buildkit.md) * [使用 buildx 构建多种系统架构支持的 Docker 镜像](image/buildx_multi-arch-images.md)
* [Docker v18.09 版本使用 BuildKit 构建镜像](image/buildkit.md)
* [Docker v19.03 版本使用 BuildKit 构建镜像](image/buildx.md)
* [其它制作镜像的方式](image/other.md) * [其它制作镜像的方式](image/other.md)
* [实现原理](image/internal.md) * [实现原理](image/internal.md)
* [操作容器](container/README.md) * [操作容器](container/README.md)

View File

@ -36,7 +36,7 @@
下面是来自 `buildpack-deps` 镜像的例子 下面是来自 `buildpack-deps` 镜像的例子
```dockerfile ```docker
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
bzr \ bzr \
cvs \ cvs \
@ -72,7 +72,7 @@ RUN apt-get update && apt-get install -y \
>注意如果你的字符串中包含空格必须将字符串放入引号中或者对空格使用转义如果字符串内容本身就包含引号必须对引号使用转义 >注意如果你的字符串中包含空格必须将字符串放入引号中或者对空格使用转义如果字符串内容本身就包含引号必须对引号使用转义
```dockerfile ```docker
# Set one or more individual labels # Set one or more individual labels
LABEL com.example.version="0.0.1-beta" LABEL com.example.version="0.0.1-beta"
@ -85,7 +85,7 @@ LABEL com.example.version.is-production=""
一个镜像可以包含多个标签但建议将多个标签放入到一个 `LABEL` 指令中 一个镜像可以包含多个标签但建议将多个标签放入到一个 `LABEL` 指令中
```dockerfile ```docker
# Set multiple labels at once, using line-continuation characters to break long lines # Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \ LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \ com.example.is-beta= \
@ -108,7 +108,7 @@ LABEL vendor=ACME\ Incorporated \
永远将 `RUN apt-get update` `apt-get install` 组合成一条 `RUN` 声明例如 永远将 `RUN apt-get update` `apt-get install` 组合成一条 `RUN` 声明例如
```dockerfile ```docker
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
package-bar \ package-bar \
package-baz \ package-baz \
@ -117,7 +117,7 @@ RUN apt-get update && apt-get install -y \
`apt-get update` 放在一条单独的 `RUN` 声明中会导致缓存问题以及后续的 `apt-get install` 失败比如假设你有一个 `Dockerfile` 文件 `apt-get update` 放在一条单独的 `RUN` 声明中会导致缓存问题以及后续的 `apt-get install` 失败比如假设你有一个 `Dockerfile` 文件
```dockerfile ```docker
FROM ubuntu:18.04 FROM ubuntu:18.04
RUN apt-get update RUN apt-get update
@ -127,7 +127,7 @@ RUN apt-get install -y curl
构建镜像后所有的层都在 Docker 的缓存中假设你后来又修改了其中的 `apt-get install` 添加了一个包 构建镜像后所有的层都在 Docker 的缓存中假设你后来又修改了其中的 `apt-get install` 添加了一个包
```dockerfile ```docker
FROM ubuntu:18.04 FROM ubuntu:18.04
RUN apt-get update RUN apt-get update
@ -139,7 +139,7 @@ Docker 发现修改后的 `RUN apt-get update` 指令和之前的完全一样。
使用 `RUN apt-get update && apt-get install -y` 可以确保你的 Dockerfiles 每次安装的都是包的最新的版本而且这个过程不需要进一步的编码或额外干预这项技术叫作 `cache busting`你也可以显示指定一个包的版本号来达到 `cache-busting`这就是所谓的固定版本例如 使用 `RUN apt-get update && apt-get install -y` 可以确保你的 Dockerfiles 每次安装的都是包的最新的版本而且这个过程不需要进一步的编码或额外干预这项技术叫作 `cache busting`你也可以显示指定一个包的版本号来达到 `cache-busting`这就是所谓的固定版本例如
```dockerfile ```docker
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
package-bar \ package-bar \
package-baz \ package-baz \
@ -150,7 +150,7 @@ RUN apt-get update && apt-get install -y \
下面是一个 `RUN` 指令的示例模板展示了所有关于 `apt-get` 的建议 下面是一个 `RUN` 指令的示例模板展示了所有关于 `apt-get` 的建议
```dockerfile ```docker
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
aufs-tools \ aufs-tools \
automake \ automake \
@ -193,7 +193,7 @@ RUN apt-get update && apt-get install -y \
最后`ENV` 也能用于设置常见的版本号比如下面的示例 最后`ENV` 也能用于设置常见的版本号比如下面的示例
```dockerfile ```docker
ENV PG_MAJOR 9.3 ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4 ENV PG_VERSION 9.3.4
@ -211,7 +211,7 @@ ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
如果你的 `Dockerfile` 有多个步骤需要使用上下文中不同的文件单独 `COPY` 每个文件而不是一次性的 `COPY` 所有文件这将保证每个步骤的构建缓存只在特定的文件变化时失效例如 如果你的 `Dockerfile` 有多个步骤需要使用上下文中不同的文件单独 `COPY` 每个文件而不是一次性的 `COPY` 所有文件这将保证每个步骤的构建缓存只在特定的文件变化时失效例如
```dockerfile ```docker
COPY requirements.txt /tmp/ COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt RUN pip install --requirement /tmp/requirements.txt
@ -223,7 +223,7 @@ COPY . /tmp/
为了让镜像尽量小最好不要使用 `ADD` 指令从远程 URL 获取包而是使用 `curl` `wget`这样你可以在文件提取完之后删掉不再需要的文件来避免在镜像中额外添加一层比如尽量避免下面的用法 为了让镜像尽量小最好不要使用 `ADD` 指令从远程 URL 获取包而是使用 `curl` `wget`这样你可以在文件提取完之后删掉不再需要的文件来避免在镜像中额外添加一层比如尽量避免下面的用法
```dockerfile ```docker
ADD http://example.com/big.tar.xz /usr/src/things/ ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
@ -233,7 +233,7 @@ RUN make -C /usr/src/things all
而是应该使用下面这种方法 而是应该使用下面这种方法
```dockerfile ```docker
RUN mkdir -p /usr/src/things \ RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \ && curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \ | tar -xJC /usr/src/things \
@ -250,7 +250,7 @@ RUN mkdir -p /usr/src/things \
例如下面的示例镜像提供了命令行工具 `s3cmd`: 例如下面的示例镜像提供了命令行工具 `s3cmd`:
```dockerfile ```docker
ENTRYPOINT ["s3cmd"] ENTRYPOINT ["s3cmd"]
CMD ["--help"] CMD ["--help"]
@ -295,7 +295,7 @@ exec "$@"
该辅助脚本被拷贝到容器并在容器启动时通过 `ENTRYPOINT` 执行 该辅助脚本被拷贝到容器并在容器启动时通过 `ENTRYPOINT` 执行
```dockerfile ```docker
COPY ./docker-entrypoint.sh / COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"] ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@ -52,11 +52,18 @@
### 如何获取某个容器的 PID 信息 ### 如何获取某个容器的 PID 信息
可以使用 `docker inspect --format '{{ .State.Pid }}' <CONTAINER ID or NAME>` 命令 可以使用
```bash
docker inspect --format '{{ .State.Pid }}' <CONTAINER ID or NAME>
```
### 如何获取某个容器的 IP 地址 ### 如何获取某个容器的 IP 地址
可以使用 `docker inspect --format '{{ .NetworkSettings.IPAddress }}' <CONTAINER ID or NAME>` 命令 可以使用
```bash
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <CONTAINER ID or NAME>
```
### 如何给容器指定一个固定 IP 地址而不是每次重启容器 IP 地址都会变 ### 如何给容器指定一个固定 IP 地址而不是每次重启容器 IP 地址都会变

View File

@ -1,4 +1,4 @@
## Docker 容器 # Docker 容器
镜像`Image`和容器`Container`的关系就像是面向对象程序设计中的 `` `实例` 一样镜像是静态的定义容器是镜像运行时的实体容器可以被创建启动停止删除暂停等 镜像`Image`和容器`Container`的关系就像是面向对象程序设计中的 `` `实例` 一样镜像是静态的定义容器是镜像运行时的实体容器可以被创建启动停止删除暂停等

View File

@ -1,10 +1,10 @@
## Docker 镜像 # Docker 镜像
我们都知道操作系统分为内核和用户空间对于 Linux 而言内核启动后会挂载 `root` 文件系统为其提供用户空间支持 Docker 镜像Image就相当于是一个 `root` 文件系统比如官方镜像 `ubuntu:18.04` 就包含了完整的一套 Ubuntu 18.04 最小系统的 `root` 文件系统 我们都知道操作系统分为内核和用户空间对于 Linux 而言内核启动后会挂载 `root` 文件系统为其提供用户空间支持 Docker 镜像Image就相当于是一个 `root` 文件系统比如官方镜像 `ubuntu:18.04` 就包含了完整的一套 Ubuntu 18.04 最小系统的 `root` 文件系统
Docker 镜像是一个特殊的文件系统除了提供容器运行时所需的程序资源配置等文件外还包含了一些为运行时准备的一些配置参数如匿名卷环境变量用户等镜像不包含任何动态数据其内容在构建之后也不会被改变 Docker 镜像是一个特殊的文件系统除了提供容器运行时所需的程序资源配置等文件外还包含了一些为运行时准备的一些配置参数如匿名卷环境变量用户等镜像不包含任何动态数据其内容在构建之后也不会被改变
### 分层存储 ## 分层存储
因为镜像包含操作系统完整的 `root` 文件系统其体积往往是庞大的因此在 Docker 设计时就充分利用 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。 因为镜像包含操作系统完整的 `root` 文件系统其体积往往是庞大的因此在 Docker 设计时就充分利用 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。

View File

@ -1,4 +1,4 @@
## Docker Registry # Docker Registry
镜像构建完成后可以很容易的在当前宿主机上运行但是如果需要在其它服务器上使用这个镜像我们就需要一个集中的存储分发镜像的服务[Docker Registry](../repository/registry.md) 就是这样的服务 镜像构建完成后可以很容易的在当前宿主机上运行但是如果需要在其它服务器上使用这个镜像我们就需要一个集中的存储分发镜像的服务[Docker Registry](../repository/registry.md) 就是这样的服务
@ -10,7 +10,7 @@
仓库名经常以 *两段式路径* 形式出现比如 `jwilder/nginx-proxy`前者往往意味着 Docker Registry 多用户环境下的用户名后者则往往是对应的软件名但这并非绝对取决于所使用的具体 Docker Registry 的软件或服务 仓库名经常以 *两段式路径* 形式出现比如 `jwilder/nginx-proxy`前者往往意味着 Docker Registry 多用户环境下的用户名后者则往往是对应的软件名但这并非绝对取决于所使用的具体 Docker Registry 的软件或服务
### Docker Registry 公开服务 ## Docker Registry 公开服务
Docker Registry 公开服务是开放给用户使用允许用户管理镜像的 Registry 服务一般这类公开服务允许用户免费上传下载公开的镜像并可能提供收费服务供用户管理私有镜像 Docker Registry 公开服务是开放给用户使用允许用户管理镜像的 Registry 服务一般这类公开服务允许用户免费上传下载公开的镜像并可能提供收费服务供用户管理私有镜像
@ -20,7 +20,7 @@ Docker Registry 公开服务是开放给用户使用、允许用户管理镜像
国内也有一些云服务商提供类似于 Docker Hub 的公开服务比如 [时速云镜像仓库](https://hub.tenxcloud.com/)、[网易云镜像服务](https://c.163.com/hub#/m/library/)、[DaoCloud 镜像市场](https://hub.daocloud.io/)、[阿里云镜像库](https://cr.console.aliyun.com) 等。 国内也有一些云服务商提供类似于 Docker Hub 的公开服务比如 [时速云镜像仓库](https://hub.tenxcloud.com/)、[网易云镜像服务](https://c.163.com/hub#/m/library/)、[DaoCloud 镜像市场](https://hub.daocloud.io/)、[阿里云镜像库](https://cr.console.aliyun.com) 等。
### 私有 Docker Registry ## 私有 Docker Registry
除了使用公开服务外用户还可以在本地搭建私有 Docker RegistryDocker 官方提供了 [Docker Registry](https://hub.docker.com/_/registry/) 镜像,可以直接使用做为私有 Registry 服务。在 [私有仓库](../repository/registry.md) 一节中,会有进一步的搭建私有 Registry 服务的讲解。 除了使用公开服务外用户还可以在本地搭建私有 Docker RegistryDocker 官方提供了 [Docker Registry](https://hub.docker.com/_/registry/) 镜像,可以直接使用做为私有 Registry 服务。在 [私有仓库](../repository/registry.md) 一节中,会有进一步的搭建私有 Registry 服务的讲解。

View File

@ -10,7 +10,7 @@
在项目根目录新建一个 `Dockerfile` 文件 在项目根目录新建一个 `Dockerfile` 文件
```dockerfile ```docker
FROM alpine FROM alpine
RUN echo "Hello World" RUN echo "Hello World"

View File

@ -8,7 +8,7 @@
第一步因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容内容如下 第一步因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容内容如下
```dockerfile ```docker
FROM python:3 FROM python:3
ENV PYTHONUNBUFFERED 1 ENV PYTHONUNBUFFERED 1
RUN mkdir /code RUN mkdir /code

View File

@ -8,7 +8,7 @@
首先因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容内容如下 首先因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容内容如下
```dockerfile ```docker
FROM ruby FROM ruby
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
RUN mkdir /myapp RUN mkdir /myapp
@ -117,5 +117,3 @@ $ docker-compose run web rake db:create
``` ```
这个 web 应用已经开始在你的 docker 守护进程里面监听着 3000 端口了 这个 web 应用已经开始在你的 docker 守护进程里面监听着 3000 端口了
![](../_images/docker-compose-rails-screenshot.png)

View File

@ -40,7 +40,7 @@ if __name__ == "__main__":
编写 `Dockerfile` 文件内容为 编写 `Dockerfile` 文件内容为
```dockerfile ```docker
FROM python:3.6-alpine FROM python:3.6-alpine
ADD . /code ADD . /code
WORKDIR /code WORKDIR /code

View File

@ -16,7 +16,7 @@ $ touch Dockerfile
其内容为 其内容为
```dockerfile ```docker
FROM nginx FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
``` ```
@ -33,7 +33,7 @@ RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
除了选择现有镜像为基础镜像外Docker 还存在一个特殊的镜像名为 `scratch`这个镜像是虚拟的概念并不实际存在它表示一个空白的镜像 除了选择现有镜像为基础镜像外Docker 还存在一个特殊的镜像名为 `scratch`这个镜像是虚拟的概念并不实际存在它表示一个空白的镜像
```dockerfile ```docker
FROM scratch FROM scratch
... ...
``` ```
@ -48,7 +48,7 @@ FROM scratch
* *shell* 格式`RUN <命令>`就像直接在命令行中输入的命令一样刚才写的 Dockerfile 中的 `RUN` 指令就是这种格式 * *shell* 格式`RUN <命令>`就像直接在命令行中输入的命令一样刚才写的 Dockerfile 中的 `RUN` 指令就是这种格式
```Dockerfile ```docker
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
``` ```
@ -56,7 +56,7 @@ RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
既然 `RUN` 就像 Shell 脚本一样可以执行命令那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 比如这样 既然 `RUN` 就像 Shell 脚本一样可以执行命令那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 比如这样
```dockerfile ```docker
FROM debian:stretch FROM debian:stretch
RUN apt-get update RUN apt-get update
@ -77,7 +77,7 @@ RUN make -C /usr/src/redis install
上面的 `Dockerfile` 正确的写法应该是这样 上面的 `Dockerfile` 正确的写法应该是这样
```dockerfile ```docker
FROM debian:stretch FROM debian:stretch
RUN buildDeps='gcc libc6-dev make wget' \ RUN buildDeps='gcc libc6-dev make wget' \
@ -142,7 +142,7 @@ docker build [选项] <上下文路径/URL/->
如果在 `Dockerfile` 中这么写 如果在 `Dockerfile` 中这么写
```Dockerfile ```docker
COPY ./package.json /app/ COPY ./package.json /app/
``` ```

View File

@ -6,7 +6,7 @@
**注意docker-compose build 命令暂时不支持 BuildKit** **注意docker-compose build 命令暂时不支持 BuildKit**
下面介绍如何在 Docker CE 18.09+ 版本中使用 `BuildKit` 提供的 `Dockerfile` 新指令来更快更安全的构建 Docker 镜像 下面介绍如何在 Docker CE 18.09 版本中使用 `BuildKit` 提供的 `Dockerfile` 新指令来更快更安全的构建 Docker 镜像
### 启用 `BuildKit` ### 启用 `BuildKit`

148
image/buildx.md Normal file
View File

@ -0,0 +1,148 @@
## 使用 `Buildx` 构建镜像
**BuildKit** 是下一代的镜像构建组件 https://github.com/moby/buildkit 开源。
**注意如果您的镜像构建使用的是云服务商提供的镜像构建服务Docker Hub 自动构建腾讯云容器服务阿里云容器服务等由于上述服务提供商的 Docker 版本低于 18.09BuildKit 无法使用将造成镜像构建失败建议使用 BuildKit 构建镜像时使用一个新的 Dockerfile 文件例如 Dockerfile.buildkit**
下面介绍如何在 Docker CE 19.03+ 版本中使用 `BuildKit` 提供的 `Dockerfile` 新指令来更快更安全的构建 Docker 镜像
### `Dockerfile` 新增指令详解
启用 `BuildKit` 之后我们可以使用下面几个新的指令来加快镜像构建为了使用 `BuildKit` 我们 **必须** 使用新的 `$ docker buildx build` 命令来构建 Docker 镜像
#### `RUN --mount=type=cache`
目前几乎所有的程序都会使用依赖管理工具例如 `Go` 中的 `go mod``Node.js` 中的 `npm` 等等当我们构建一个镜像时往往会重复的从互联网中获取依赖包难以缓存大大降低了镜像的构建效率
例如一个前端工程需要用到 `npm`
```docker
FROM node:alpine as builder
WORKDIR /app
COPY package.json /app/
RUN npm i --registry=https://registry.npm.taobao.org \
&& rm -rf ~/.npm
COPY src /app/src
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /app/dist
```
使用多阶段构建构建的镜像中只包含了目标文件夹 `dist`但仍然存在一些问题 `package.json` 文件变动时`RUN npm i && rm -rf ~/.npm` 这一层会重新执行变更多次后生成了大量的中间层镜像
为解决这个问题进一步的我们可以设想一个类似 **数据卷** 的功能在镜像构建时把 `node_modules` 文件夹挂载上去在构建完成后这个 `node_modules` 文件夹会自动卸载实际的镜像中并不包含 `node_modules` 这个文件夹这样我们就省去了每次获取依赖的时间大大增加了镜像构建效率同时也避免了生成了大量的中间层镜像
`BuildKit` 提供了 `RUN --mount=type=cache` 指令可以实现上边的设想
```docker
FROM node:alpine as builder
WORKDIR /app
COPY package.json /app/
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
--mount=type=cache,target=/root/.npm,id=npm_cache \
npm i --registry=https://registry.npm.taobao.org
COPY src /app/src
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
# --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \
npm run build
FROM nginx:alpine
# COPY --from=builder /app/dist /app/dist
# 为了更直观的说明 from source 指令这里使用 RUN 指令
RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
# --mount=type=cache,target/tmp/dist,from=my_app_dist,sharing=locked \
mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist
```
第一个 `RUN` 指令执行后`id` `my_app_npm_module` 的缓存文件夹挂载到了 `/app/node_modules` 文件夹中多次执行也不会产生多个中间层镜像
第二个 `RUN` 指令执行时需要用到 `node_modules` 文件夹`node_modules` 已经挂载命令也可以正确执行
第三个 `RUN` 指令将上一阶段产生的文件复制到指定位置`from` 指明缓存的来源这里 `builder` 表示缓存来源于构建的第一阶段`source` 指明缓存来源的文件夹
上面的 `Dockerfile` `--mount=type=cache,...` 中指令作用如下
|Option |Description|
|---------------------|-----------|
|`id` | `id` 设置一个标志以便区分缓存|
|`target` (必填项) | 缓存的挂载目标文件夹|
|`ro`,`readonly` | 只读缓存文件夹不能被写入 |
|`sharing` | `shared` `private` `locked` 值可供选择`sharing` 设置当一个缓存被多次使用时的表现由于 `BuildKit` 支持并行构建当多个步骤使用同一缓存时同一 `id`会发生冲突`shared` 表示多个步骤可以同时读写`private` 表示当多个步骤使用同一缓存时每个步骤使用不同的缓存`locked` 表示当一个步骤完成释放缓存后后一个步骤才能继续使用该缓存|
|`from` | 缓存来源构建阶段不填写时为空文件夹|
|`source` | 来源的文件夹路径|
#### `RUN --mount=type=bind`
该指令可以将一个镜像或上一构建阶段的文件挂载到指定位置
```docker
RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \
cat /docker-php-entrypoint
```
#### `RUN --mount=type=tmpfs`
该指令可以将一个 `tmpfs` 文件系统挂载到指定位置
```docker
RUN --mount=type=tmpfs,target=/temp \
mount | grep /temp
```
#### `RUN --mount=type=secret`
该指令可以将一个文件挂载到指定位置
```docker
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
cat /root/.aws/credentials
```
```bash
$ docker buildx build -t test --secret id=aws,src=$HOME/.aws/credentials .
```
#### `RUN --mount=type=ssh`
该指令可以挂载 `ssh` 密钥
```docker
FROM alpine
RUN apk add --no-cache openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh ssh git@gitlab.com | tee /hello
```
```bash
$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ docker buildx build -t test --ssh default=$SSH_AUTH_SOCK .
```
### 清理构建缓存
执行以下命令清理构建缓存
```bash
$ docker builder prune
```
### 官方文档
* https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md

View File

@ -0,0 +1,78 @@
# 使用 buildx 构建多种系统架构支持的 Docker 镜像
在之前的版本中构建多种系统架构支持的 Docker 镜像要想使用统一的名字必须使用 [`$ docker manifest`](manifest.md) 命令
Docker 19.03+ 版本中可以使用 `$ docker buildx build` 命令使用 `BuildKit` 构建镜像
该命令支持 `--platform` 参数可以同时构建支持多种系统架构的 Docker 镜像大大简化了构建步骤
## 设置环境变量
`buildx` 命令属于实验特性必须设置环境变量以使用该命令
Linux/macOS
```bash
$ export DOCKER_CLI_EXPERIMENTAL=enabled
```
Windows
```bash
$ set $env:DOCKER_CLI_EXPERIMENTAL=enabled
```
## 新建 `builder` 实例
Docker for Linux 不支持构建 `arm` 架构镜像我们可以运行一个新的容器让其支持该特性Docker 桌面版无需进行此项设置
```bash
$ docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3
```
由于 Docker 默认的 `builder` 实例不支持同时指定多个 `--platform`我们必须首先创建一个新的 `builder` 实例
```bash
$ docker buildx create --name mybuilder
$ docker buildx use mybuilder
```
## 构建镜像
新建 Dockerfile 文件
```docker
FROM --platform=$TARGETPLATFORM alpine
RUN uname -a > /os.txt
CMD cat /os.txt
```
使用 `$ docker buildx build` 命令构建镜像注意将 `myusername` 替换为自己的 Docker Hub 用户名
`--push` 参数表示将构建好的镜像推送到 Docker 仓库
```bash
$ docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t myusername/hello . --push
# 查看镜像信息
$ docker buildx imagetools inspect myusername/hello
```
在不同架构运行该镜像可以得到该架构的信息
```bash
# arm
$ docker run -it --rm myusername/hello
Linux buildkitsandbox 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 armv7l Linux
# arm64
$ docker run -it --rm myusername/hello
Linux buildkitsandbox 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 aarch64 Linux
# amd64
$ docker run -it --rm myusername/hello
Linux buildkitsandbox 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux
```

View File

@ -21,7 +21,7 @@ $ docker run --name webserver -d -p 80:80 nginx
直接用浏览器访问的话我们会看到默认的 Nginx 欢迎页面 直接用浏览器访问的话我们会看到默认的 Nginx 欢迎页面
<img src="_images/images-mac-example-nginx.png" width="80%" > ![](_images/images-mac-example-nginx.png)
现在假设我们非常不喜欢这个欢迎页面我们希望改成欢迎 Docker 的文字我们可以使用 `docker exec` 命令进入容器修改其内容 现在假设我们非常不喜欢这个欢迎页面我们希望改成欢迎 Docker 的文字我们可以使用 `docker exec` 命令进入容器修改其内容
@ -38,7 +38,7 @@ exit
现在我们再刷新浏览器的话会发现内容被改变了 现在我们再刷新浏览器的话会发现内容被改变了
<img src="_images/images-create-nginx-docker.png" width="80%" > ![](_images/images-create-nginx-docker.png)
我们修改了容器的文件也就是改动了容器的存储层我们可以通过 `docker diff` 命令看到具体的改动 我们修改了容器的文件也就是改动了容器的存储层我们可以通过 `docker diff` 命令看到具体的改动

View File

@ -0,0 +1,5 @@
FROM --platform=$TARGETPLATFORM alpine
RUN uname -a > /os.txt
CMD cat /os.txt

View File

@ -8,7 +8,7 @@
在某些情况下这个自动解压缩的功能非常有用比如官方镜像 `ubuntu` 在某些情况下这个自动解压缩的功能非常有用比如官方镜像 `ubuntu`
```Dockerfile ```docker
FROM scratch FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
... ...
@ -24,7 +24,7 @@ ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
在使用该指令的时候还可以加上 `--chown=<user>:<group>` 选项来改变文件的所属用户及所属组 在使用该指令的时候还可以加上 `--chown=<user>:<group>` 选项来改变文件的所属用户及所属组
```Dockerfile ```docker
ADD --chown=55:mygroup files* /mydir/ ADD --chown=55:mygroup files* /mydir/
ADD --chown=bin files* /mydir/ ADD --chown=bin files* /mydir/
ADD --chown=1 files* /mydir/ ADD --chown=1 files* /mydir/

View File

@ -14,13 +14,13 @@
如果使用 `shell` 格式的话实际的命令会被包装为 `sh -c` 的参数的形式进行执行比如 如果使用 `shell` 格式的话实际的命令会被包装为 `sh -c` 的参数的形式进行执行比如
```Dockerfile ```docker
CMD echo $HOME CMD echo $HOME
``` ```
在实际执行中会将其变更为 在实际执行中会将其变更为
```Dockerfile ```docker
CMD [ "sh", "-c", "echo $HOME" ] CMD [ "sh", "-c", "echo $HOME" ]
``` ```
@ -32,7 +32,7 @@ Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是
一些初学者将 `CMD` 写为 一些初学者将 `CMD` 写为
```Dockerfile ```docker
CMD service nginx start CMD service nginx start
``` ```
@ -44,6 +44,6 @@ CMD service nginx start
正确的做法是直接执行 `nginx` 可执行文件并且要求以前台形式运行比如 正确的做法是直接执行 `nginx` 可执行文件并且要求以前台形式运行比如
```Dockerfile ```docker
CMD ["nginx", "-g", "daemon off;"] CMD ["nginx", "-g", "daemon off;"]
``` ```

View File

@ -9,13 +9,13 @@
`COPY` 指令将从构建上下文目录中 `<源路径>` 的文件/目录复制到新的一层的镜像内的 `<目标路径>` 位置比如 `COPY` 指令将从构建上下文目录中 `<源路径>` 的文件/目录复制到新的一层的镜像内的 `<目标路径>` 位置比如
```Dockerfile ```docker
COPY package.json /usr/src/app/ COPY package.json /usr/src/app/
``` ```
`<源路径>` 可以是多个甚至可以是通配符其通配符规则要满足 Go [`filepath.Match`](https://golang.org/pkg/path/filepath/#Match) 规则,如: `<源路径>` 可以是多个甚至可以是通配符其通配符规则要满足 Go [`filepath.Match`](https://golang.org/pkg/path/filepath/#Match) 规则,如:
```Dockerfile ```docker
COPY hom* /mydir/ COPY hom* /mydir/
COPY hom?.txt /mydir/ COPY hom?.txt /mydir/
``` ```
@ -26,7 +26,7 @@ COPY hom?.txt /mydir/
在使用该指令的时候还可以加上 `--chown=<user>:<group>` 选项来改变文件的所属用户及所属组 在使用该指令的时候还可以加上 `--chown=<user>:<group>` 选项来改变文件的所属用户及所属组
```Dockerfile ```docker
COPY --chown=55:mygroup files* /mydir/ COPY --chown=55:mygroup files* /mydir/
COPY --chown=bin files* /mydir/ COPY --chown=bin files* /mydir/
COPY --chown=1 files* /mydir/ COPY --chown=1 files* /mydir/

View File

@ -16,7 +16,7 @@
假设我们需要一个得知自己当前公网 IP 的镜像那么可以先用 `CMD` 来实现 假设我们需要一个得知自己当前公网 IP 的镜像那么可以先用 `CMD` 来实现
```Dockerfile ```docker
FROM ubuntu:18.04 FROM ubuntu:18.04
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y curl \ && apt-get install -y curl \
@ -48,7 +48,7 @@ $ docker run myip curl -s https://ip.cn -i
这显然不是很好的解决方案而使用 `ENTRYPOINT` 就可以解决这个问题现在我们重新用 `ENTRYPOINT` 来实现这个镜像 这显然不是很好的解决方案而使用 `ENTRYPOINT` 就可以解决这个问题现在我们重新用 `ENTRYPOINT` 来实现这个镜像
```Dockerfile ```docker
FROM ubuntu:18.04 FROM ubuntu:18.04
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y curl \ && apt-get install -y curl \
@ -91,7 +91,7 @@ Connection: keep-alive
这些准备工作是和容器 `CMD` 无关的无论 `CMD` 为什么都需要事先进行一个预处理的工作这种情况下可以写一个脚本然后放入 `ENTRYPOINT` 中去执行而这个脚本会将接到的参数也就是 `<CMD>`作为命令在脚本最后执行比如官方镜像 `redis` 中就是这么做的 这些准备工作是和容器 `CMD` 无关的无论 `CMD` 为什么都需要事先进行一个预处理的工作这种情况下可以写一个脚本然后放入 `ENTRYPOINT` 中去执行而这个脚本会将接到的参数也就是 `<CMD>`作为命令在脚本最后执行比如官方镜像 `redis` 中就是这么做的
```Dockerfile ```docker
FROM alpine:3.4 FROM alpine:3.4
... ...
RUN addgroup -S redis && adduser -S -G redis redis RUN addgroup -S redis && adduser -S -G redis redis

View File

@ -16,7 +16,7 @@ ENV VERSION=1.0 DEBUG=on \
定义了环境变量那么在后续的指令中就可以使用这个环境变量比如在官方 `node` 镜像 `Dockerfile` 就有类似这样的代码 定义了环境变量那么在后续的指令中就可以使用这个环境变量比如在官方 `node` 镜像 `Dockerfile` 就有类似这样的代码
```Dockerfile ```docker
ENV NODE_VERSION 7.2.0 ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \ RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \

View File

@ -25,7 +25,7 @@
假设我们有个镜像是个最简单的 Web 服务我们希望增加健康检查来判断其 Web 服务是否在正常工作我们可以用 `curl` 来帮助判断 `Dockerfile` `HEALTHCHECK` 可以这么写 假设我们有个镜像是个最简单的 Web 服务我们希望增加健康检查来判断其 Web 服务是否在正常工作我们可以用 `curl` 来帮助判断 `Dockerfile` `HEALTHCHECK` 可以这么写
```Dockerfile ```docker
FROM nginx FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s \ HEALTHCHECK --interval=5s --timeout=3s \

View File

@ -8,7 +8,7 @@
假设我们要制作 Node.js 所写的应用的镜像我们都知道 Node.js 使用 `npm` 进行包管理所有依赖配置启动信息等会放到 `package.json` 文件里在拿到程序代码后需要先进行 `npm install` 才可以获得所有需要的依赖然后就可以通过 `npm start` 来启动应用因此一般来说会这样写 `Dockerfile` 假设我们要制作 Node.js 所写的应用的镜像我们都知道 Node.js 使用 `npm` 进行包管理所有依赖配置启动信息等会放到 `package.json` 文件里在拿到程序代码后需要先进行 `npm install` 才可以获得所有需要的依赖然后就可以通过 `npm start` 来启动应用因此一般来说会这样写 `Dockerfile`
```Dockerfile ```docker
FROM node:slim FROM node:slim
RUN mkdir /app RUN mkdir /app
WORKDIR /app WORKDIR /app
@ -24,7 +24,7 @@ CMD [ "npm", "start" ]
那么我们可不可以做一个基础镜像然后各个项目使用这个基础镜像呢这样基础镜像更新各个项目不用同步 `Dockerfile` 的变化重新构建后就继承了基础镜像的更新好吧可以让我们看看这样的结果那么上面的这个 `Dockerfile` 就会变为 那么我们可不可以做一个基础镜像然后各个项目使用这个基础镜像呢这样基础镜像更新各个项目不用同步 `Dockerfile` 的变化重新构建后就继承了基础镜像的更新好吧可以让我们看看这样的结果那么上面的这个 `Dockerfile` 就会变为
```Dockerfile ```docker
FROM node:slim FROM node:slim
RUN mkdir /app RUN mkdir /app
WORKDIR /app WORKDIR /app
@ -33,7 +33,7 @@ CMD [ "npm", "start" ]
这里我们把项目相关的构建指令拿出来放到子项目里去假设这个基础镜像的名字为 `my-node` 的话各个项目内的自己的 `Dockerfile` 就变为 这里我们把项目相关的构建指令拿出来放到子项目里去假设这个基础镜像的名字为 `my-node` 的话各个项目内的自己的 `Dockerfile` 就变为
```Dockerfile ```docker
FROM my-node FROM my-node
COPY ./package.json /app COPY ./package.json /app
RUN [ "npm", "install" ] RUN [ "npm", "install" ]
@ -46,7 +46,7 @@ COPY . /app/
`ONBUILD` 可以解决这个问题让我们用 `ONBUILD` 重新写一下基础镜像的 `Dockerfile`: `ONBUILD` 可以解决这个问题让我们用 `ONBUILD` 重新写一下基础镜像的 `Dockerfile`:
```Dockerfile ```docker
FROM node:slim FROM node:slim
RUN mkdir /app RUN mkdir /app
WORKDIR /app WORKDIR /app
@ -58,7 +58,7 @@ CMD [ "npm", "start" ]
这次我们回到原始的 `Dockerfile`但是这次将项目相关的指令加上 `ONBUILD`这样在构建基础镜像的时候这三行并不会被执行然后各个项目的 `Dockerfile` 就变成了简单地 这次我们回到原始的 `Dockerfile`但是这次将项目相关的指令加上 `ONBUILD`这样在构建基础镜像的时候这三行并不会被执行然后各个项目的 `Dockerfile` 就变成了简单地
```Dockerfile ```docker
FROM my-node FROM my-node
``` ```

View File

@ -6,7 +6,7 @@
当然 `WORKDIR` 一样`USER` 只是帮助你切换到指定用户而已这个用户必须是事先建立好的否则无法切换 当然 `WORKDIR` 一样`USER` 只是帮助你切换到指定用户而已这个用户必须是事先建立好的否则无法切换
```Dockerfile ```docker
RUN groupadd -r redis && useradd -r -g redis redis RUN groupadd -r redis && useradd -r -g redis redis
USER redis USER redis
RUN [ "redis-server" ] RUN [ "redis-server" ]
@ -14,7 +14,7 @@ RUN [ "redis-server" ]
如果以 `root` 执行的脚本在执行期间希望改变身份比如希望以某个已经建立好的用户来运行某个服务进程不要使用 `su` 或者 `sudo`这些都需要比较麻烦的配置而且在 TTY 缺失的环境下经常出错建议使用 [`gosu`](https://github.com/tianon/gosu)。 如果以 `root` 执行的脚本在执行期间希望改变身份比如希望以某个已经建立好的用户来运行某个服务进程不要使用 `su` 或者 `sudo`这些都需要比较麻烦的配置而且在 TTY 缺失的环境下经常出错建议使用 [`gosu`](https://github.com/tianon/gosu)。
```Dockerfile ```docker
# 建立 redis 用户并使用 gosu 换另一个用户执行命令 # 建立 redis 用户并使用 gosu 换另一个用户执行命令
RUN groupadd -r redis && useradd -r -g redis redis RUN groupadd -r redis && useradd -r -g redis redis
# 下载 gosu # 下载 gosu

View File

@ -7,7 +7,7 @@
之前我们说过容器运行时应该尽量保持容器存储层不发生写操作对于数据库类需要保存动态数据的应用其数据库文件应该保存于卷(volume)后面的章节我们会进一步介绍 Docker 卷的概念为了防止运行时用户忘记将动态文件所保存目录挂载为卷 `Dockerfile` 我们可以事先指定某些目录挂载为匿名卷这样在运行时如果用户不指定挂载其应用也可以正常运行不会向容器存储层写入大量数据 之前我们说过容器运行时应该尽量保持容器存储层不发生写操作对于数据库类需要保存动态数据的应用其数据库文件应该保存于卷(volume)后面的章节我们会进一步介绍 Docker 卷的概念为了防止运行时用户忘记将动态文件所保存目录挂载为卷 `Dockerfile` 我们可以事先指定某些目录挂载为匿名卷这样在运行时如果用户不指定挂载其应用也可以正常运行不会向容器存储层写入大量数据
```Dockerfile ```docker
VOLUME /data VOLUME /data
``` ```

View File

@ -2,11 +2,11 @@
我们知道使用镜像创建一个容器该镜像必须与 Docker 宿主机系统架构一致例如 `Linux x86_64` 架构的系统中只能使用 `Linux x86_64` 的镜像创建容器 我们知道使用镜像创建一个容器该镜像必须与 Docker 宿主机系统架构一致例如 `Linux x86_64` 架构的系统中只能使用 `Linux x86_64` 的镜像创建容器
> macOS 除外其使用了 [binfmt_misc](https://docs.docker.com/docker-for-mac/multi-arch/) 提供了多种架构支持,在 macOS 系统上 (x86_64) 可以运行 arm 等其他架构的镜像。 > WindowsmacOS 除外其使用了 [binfmt_misc](https://docs.docker.com/docker-for-mac/multi-arch/) 提供了多种架构支持,在 Windows、macOS 系统上 (x86_64) 可以运行 arm 等其他架构的镜像。
例如我们在 `Linux x86_64` 中构建一个 `username/test` 镜像 例如我们在 `Linux x86_64` 中构建一个 `username/test` 镜像
```Dockerfile ```docker
FROM alpine FROM alpine
CMD echo 1 CMD echo 1

View File

@ -26,7 +26,7 @@ func main(){
编写 `Dockerfile.one` 文件 编写 `Dockerfile.one` 文件
```dockerfile ```docker
FROM golang:1.9-alpine FROM golang:1.9-alpine
RUN apk --no-cache add git ca-certificates RUN apk --no-cache add git ca-certificates
@ -56,7 +56,7 @@ $ docker build -t go/helloworld:1 -f Dockerfile.one .
例如编写 `Dockerfile.build` 文件 例如编写 `Dockerfile.build` 文件
```dockerfile ```docker
FROM golang:1.9-alpine FROM golang:1.9-alpine
RUN apk --no-cache add git RUN apk --no-cache add git
@ -71,7 +71,7 @@ RUN go get -d -v github.com/go-sql-driver/mysql \
编写 `Dockerfile.copy` 文件 编写 `Dockerfile.copy` 文件
```dockerfile ```docker
FROM alpine:latest FROM alpine:latest
RUN apk --no-cache add ca-certificates RUN apk --no-cache add ca-certificates
@ -125,7 +125,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
例如编写 `Dockerfile` 文件 例如编写 `Dockerfile` 文件
```dockerfile ```docker
FROM golang:1.9-alpine as builder FROM golang:1.9-alpine as builder
RUN apk --no-cache add git RUN apk --no-cache add git
@ -172,7 +172,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
我们可以使用 `as` 来为某一阶段命名例如 我们可以使用 `as` 来为某一阶段命名例如
```dockerfile ```docker
FROM golang:1.9-alpine as builder FROM golang:1.9-alpine as builder
``` ```
@ -186,6 +186,6 @@ $ docker build --target builder -t username/imagename:tag .
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件我们也可以复制任意镜像中的文件 上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件我们也可以复制任意镜像中的文件
```dockerfile ```docker
$ COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf $ COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
``` ```

View File

@ -50,7 +50,7 @@ server {
第一阶段进行前端构建 第一阶段进行前端构建
```dockerfile ```docker
FROM node:alpine as frontend FROM node:alpine as frontend
COPY package.json /app/ COPY package.json /app/
@ -69,7 +69,7 @@ RUN cd /app \
第二阶段安装 Composer 依赖 第二阶段安装 Composer 依赖
```dockerfile ```docker
FROM composer as composer FROM composer as composer
COPY database/ /app/database/ COPY database/ /app/database/
@ -89,7 +89,7 @@ RUN cd /app \
第三阶段对以上阶段生成的文件进行整合 第三阶段对以上阶段生成的文件进行整合
```dockerfile ```docker
FROM php:7.2-fpm-alpine as laravel FROM php:7.2-fpm-alpine as laravel
ARG LARAVEL_PATH=/app/laravel ARG LARAVEL_PATH=/app/laravel
@ -113,7 +113,7 @@ RUN cd ${LARAVEL_PATH} \
### 最后一个阶段构建 NGINX 镜像 ### 最后一个阶段构建 NGINX 镜像
```dockerfile ```docker
FROM nginx:alpine as nginx FROM nginx:alpine as nginx
ARG LARAVEL_PATH=/app/laravel ARG LARAVEL_PATH=/app/laravel
@ -164,7 +164,7 @@ $ docker run -it --rm --network=laravel -p 8080:80 my/nginx
完整的 `Dockerfile` 文件如下 完整的 `Dockerfile` 文件如下
```dockerfile ```docker
FROM node:alpine as frontend FROM node:alpine as frontend
COPY package.json /app/ COPY package.json /app/

View File

@ -1,4 +1,4 @@
## 什么是 Docker # 什么是 Docker
**Docker** 最初是 `dotCloud` 公司创始人 [Solomon Hykes](https://github.com/shykes) 在法国期间发起的一个公司内部项目,它是基于 `dotCloud` 公司多年云服务技术的一次革新,并于 [2013 年 3 月以 Apache 2.0 授权协议开源][docker-soft],主要项目代码在 [GitHub](https://github.com/moby/moby) 上进行维护。`Docker` 项目后来还加入了 Linux 基金会,并成立推动 [开放容器联盟OCI](https://www.opencontainers.org/)。 **Docker** 最初是 `dotCloud` 公司创始人 [Solomon Hykes](https://github.com/shykes) 在法国期间发起的一个公司内部项目,它是基于 `dotCloud` 公司多年云服务技术的一次革新,并于 [2013 年 3 月以 Apache 2.0 授权协议开源][docker-soft],主要项目代码在 [GitHub](https://github.com/moby/moby) 上进行维护。`Docker` 项目后来还加入了 Linux 基金会,并成立推动 [开放容器联盟OCI](https://www.opencontainers.org/)。

View File

@ -1,20 +1,20 @@
## 为什么要使用 Docker # 为什么要使用 Docker
作为一种新兴的虚拟化方式`Docker` 跟传统的虚拟化方式相比具有众多的优势 作为一种新兴的虚拟化方式`Docker` 跟传统的虚拟化方式相比具有众多的优势
### 更高效的利用系统资源 ## 更高效的利用系统资源
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销`Docker` 对系统资源的利用率更高无论是应用执行速度内存损耗或者文件存储速度都要比传统虚拟机技术更高效因此相比虚拟机技术一个相同配置的主机往往可以运行更多数量的应用 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销`Docker` 对系统资源的利用率更高无论是应用执行速度内存损耗或者文件存储速度都要比传统虚拟机技术更高效因此相比虚拟机技术一个相同配置的主机往往可以运行更多数量的应用
### 更快速的启动时间 ## 更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟 `Docker` 容器应用由于直接运行于宿主内核无需启动完整的操作系统因此可以做到秒级甚至毫秒级的启动时间大大的节约了开发测试部署的时间 传统的虚拟机技术启动应用服务往往需要数分钟 `Docker` 容器应用由于直接运行于宿主内核无需启动完整的操作系统因此可以做到秒级甚至毫秒级的启动时间大大的节约了开发测试部署的时间
### 一致的运行环境 ## 一致的运行环境
开发过程中一个常见的问题是环境一致性问题由于开发环境测试环境生产环境不一致导致有些 bug 并未在开发过程中被发现 `Docker` 的镜像提供了除内核外完整的运行时环境确保了应用运行环境一致性从而不会再出现 *这段代码在我机器上没问题啊* 这类问题 开发过程中一个常见的问题是环境一致性问题由于开发环境测试环境生产环境不一致导致有些 bug 并未在开发过程中被发现 `Docker` 的镜像提供了除内核外完整的运行时环境确保了应用运行环境一致性从而不会再出现 *这段代码在我机器上没问题啊* 这类问题
### 持续交付和部署 ## 持续交付和部署
对开发和运维[DevOps](https://zh.wikipedia.org/wiki/DevOps))人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。 对开发和运维[DevOps](https://zh.wikipedia.org/wiki/DevOps))人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
@ -22,15 +22,15 @@
而且使用 [`Dockerfile`](../image/build.md) 使镜像构建透明化不仅仅开发团队可以理解应用运行环境也方便运维团队理解应用运行所需条件帮助更好的生产环境中部署该镜像 而且使用 [`Dockerfile`](../image/build.md) 使镜像构建透明化不仅仅开发团队可以理解应用运行环境也方便运维团队理解应用运行所需条件帮助更好的生产环境中部署该镜像
### 更轻松的迁移 ## 更轻松的迁移
由于 `Docker` 确保了执行环境的一致性使得应用的迁移更加容易`Docker` 可以在很多平台上运行无论是物理机虚拟机公有云私有云甚至是笔记本其运行结果是一致的因此用户可以很轻易的将在一个平台上运行的应用迁移到另一个平台上而不用担心运行环境的变化导致应用无法正常运行的情况 由于 `Docker` 确保了执行环境的一致性使得应用的迁移更加容易`Docker` 可以在很多平台上运行无论是物理机虚拟机公有云私有云甚至是笔记本其运行结果是一致的因此用户可以很轻易的将在一个平台上运行的应用迁移到另一个平台上而不用担心运行环境的变化导致应用无法正常运行的情况
### 更轻松的维护和扩展 ## 更轻松的维护和扩展
`Docker` 使用的分层存储以及镜像的技术使得应用重复部分的复用更为容易也使得应用的维护更新更加简单基于基础镜像进一步扩展镜像也变得非常简单此外`Docker` 团队同各个开源项目团队一起维护了一大批高质量的 [官方镜像](https://hub.docker.com/search/?type=image&image_filter=official),既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。 `Docker` 使用的分层存储以及镜像的技术使得应用重复部分的复用更为容易也使得应用的维护更新更加简单基于基础镜像进一步扩展镜像也变得非常简单此外`Docker` 团队同各个开源项目团队一起维护了一大批高质量的 [官方镜像](https://hub.docker.com/search/?type=image&image_filter=official),既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
### 对比传统虚拟机总结 ## 对比传统虚拟机总结
| 特性 | 容器 | 虚拟机 | | 特性 | 容器 | 虚拟机 |
| :-------- | :-------- | :---------- | | :-------- | :-------- | :---------- |