This commit is contained in:
Baohua Yang
2026-02-09 12:56:12 -08:00
parent 63377d0431
commit b44c9acd6c
228 changed files with 326 additions and 271 deletions

View File

@@ -0,0 +1,343 @@
## 16.1 Dockerfile 最佳实践
本附录是笔者对 Docker 官方文档中 [Best practices for writing Dockerfiles](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) 的理解与翻译。
### 一般性的指南和建议
#### 容器应该是短暂的
通过 `Dockerfile` 构建的镜像所启动的容器应该尽可能短暂生命周期短短暂意味着可以停止和销毁容器并且创建一个新容器并部署好所需的设置和配置工作量应该是极小的
#### 使用 `.dockerignore` 文件
使用 `Dockerfile` 构建镜像时最好是将 `Dockerfile` 放置在一个新建的空目录下然后将构建镜像所需要的文件添加到该目录中为了提高构建镜像的效率你可以在目录下新建一个 `.dockerignore` 文件来指定要忽略的文件和目录`.dockerignore` 文件的排除模式语法和 Git `.gitignore` 文件相似
#### 使用多阶段构建
`Docker 17.05` 以上版本中你可以使用 [多阶段构建](../04_image/multistage-builds.md) 来减少所构建镜像的大小
#### 避免安装不必要的包
为了降低复杂性减少依赖减小文件大小节约构建时间你应该避免安装任何不必要的包例如不要在数据库镜像中包含一个文本编辑器
#### 一个容器只运行一个进程
应该保证在一个容器中只运行一个进程将多个应用解耦到不同容器中保证了容器的横向扩展和复用例如 web 应用应该包含三个容器web应用数据库缓存
如果容器互相依赖你可以使用 [Docker 自定义网络](../network/README.md) 来把这些容器连接起来
#### 镜像层数尽可能少
你需要在 `Dockerfile` 可读性也包括长期的可维护性和减少层数之间做一个平衡
#### 将多行参数排序
将多行参数按字母顺序排序比如要安装多个包时这可以帮助你避免重复包含同一个包更新包列表时也更容易也便于 `PRs` 阅读和审查建议在反斜杠符号 `\` 之前添加一个空格以增加可读性
下面是来自 `buildpack-deps` 镜像的例子
```docker
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
```
#### 构建缓存
在镜像的构建过程中Docker 会遍历 `Dockerfile` 文件中的指令然后按顺序执行在执行每条指令之前Docker 都会在缓存中查找是否已经存在可重用的镜像如果有就使用现存的镜像不再重复创建如果你不想在构建过程中使用缓存你可以在 `docker build` 命令中使用 `--no-cache=true` 选项
但是如果你想在构建的过程中使用缓存你得明白什么时候会什么时候不会找到匹配的镜像遵循的基本规则如下
* 从一个基础镜像开始`FROM` 指令指定下一条指令将和该基础镜像的所有子镜像进行匹配检查这些子镜像被创建时使用的指令是否和被检查的指令完全一样如果不是则缓存失效
* 在大多数情况下只需要简单地对比 `Dockerfile` 中的指令和子镜像然而有些指令需要更多的检查和解释
* 对于 `ADD` `COPY` 指令镜像中对应文件的内容也会被检查每个文件都会计算出一个校验和文件的最后修改时间和最后访问时间不会纳入校验在缓存的查找过程中会将这些校验和和已存在镜像中的文件校验和进行对比如果文件有任何改变比如内容和元数据则缓存失效
* 除了 `ADD` `COPY` 指令缓存匹配过程不会查看临时容器中的文件来决定缓存是否匹配例如当执行完 `RUN apt-get -y update` 指令后容器中一些文件被更新 Docker 不会检查这些文件这种情况下只有指令字符串本身被用来匹配缓存
一旦缓存失效所有后续的 `Dockerfile` 指令都将产生新的镜像缓存不会被使用
### Dockerfile 指令
下面针对 `Dockerfile` 中各种指令的最佳编写方式给出建议
#### FROM
尽可能使用当前官方仓库作为你构建镜像的基础推荐使用 [Alpine](https://hub.docker.com/_/alpine/) 镜像,因为它被严格控制并保持最小尺寸(目前小于 5 MB但它仍然是一个完整的发行版。
#### LABEL
你可以给镜像添加标签来帮助组织镜像记录许可信息辅助自动化构建等每个标签一行 `LABEL` 开头加上一个或多个标签对下面的示例展示了各种不同的可能格式`#` 开头的行是注释内容
>注意如果你的字符串中包含空格必须将字符串放入引号中或者对空格使用转义如果字符串内容本身就包含引号必须对引号使用转义
```docker
## Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor="ACME Incorporated"
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""
```
一个镜像可以包含多个标签但建议将多个标签放入到一个 `LABEL` 指令中
```docker
## Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production="" \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"
```
关于标签可以接受的键值对参考 [Understanding object labels](https://docs.docker.com/config/labels-custom-metadata/)。关于查询标签信息,参考 [Managing labels on objects](https://docs.docker.com/config/labels-custom-metadata/)。
#### RUN
为了保持 `Dockerfile` 文件的可读性可理解性以及可维护性建议将长的或复杂的 `RUN` 指令用反斜杠 `\` 分割成多行
##### apt-get
`RUN` 指令最常见的用法是安装包用的 `apt-get`因为 `RUN apt-get` 指令会安装包所以有几个问题需要注意
不要使用 `RUN apt-get upgrade` `dist-upgrade`因为许多基础镜像中的必须包不会在一个非特权容器中升级如果基础镜像中的某个包过时了你应该联系它的维护者如果你确定某个特定的包比如 `foo`需要升级使用 `apt-get install -y foo` 就行该指令会自动升级 `foo`
永远将 `RUN apt-get update` `apt-get install` 组合成一条 `RUN` 声明例如
```docker
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo
```
`apt-get update` 放在一条单独的 `RUN` 声明中会导致缓存问题以及后续的 `apt-get install` 失败比如假设你有一个 `Dockerfile` 文件
```docker
FROM ubuntu:24.04
RUN apt-get update
RUN apt-get install -y curl
```
构建镜像后所有的层都在 Docker 的缓存中假设你后来又修改了其中的 `apt-get install` 添加了一个包
```docker
FROM ubuntu:24.04
RUN apt-get update
RUN apt-get install -y curl nginx
```
Docker 发现修改后的 `RUN apt-get update` 指令和之前的完全一样所以`apt-get update` 不会执行而是使用之前的缓存镜像因为 `apt-get update` 没有运行后面的 `apt-get install` 可能安装的是过时的 `curl` `nginx` 版本
使用 `RUN apt-get update && apt-get install -y` 可以确保你的 Dockerfiles 每次安装的都是包的最新的版本而且这个过程不需要进一步的编码或额外干预这项技术叫作 `cache busting`你也可以显示指定一个包的版本号来达到 `cache-busting`这就是所谓的固定版本例如
```docker
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo=1.3.*
```
固定版本会迫使构建过程检索特定的版本而不管缓存中有什么这项技术也可以减少因所需包中未预料到的变化而导致的失败
下面是一个 `RUN` 指令的示例模板展示了所有关于 `apt-get` 的建议
```docker
RUN apt-get update && apt-get install -y \
aufs-tools \
automake \
build-essential \
curl \
dpkg-sig \
libcap-dev \
libsqlite3-dev \
git \
redis-server \
&& rm -rf /var/lib/apt/lists/*
```
其中 `redis-server` 是示例包确保安装的是最新版本
另外清理掉 apt 缓存 `var/lib/apt/lists` 可以减小镜像大小因为 `RUN` 指令的开头为 `apt-get update`包缓存总是会在 `apt-get install` 之前刷新
> 注意官方的 Debian Ubuntu 镜像会自动运行 apt-get clean所以不需要显式的调用 apt-get clean
#### CMD
`CMD` 指令用于执行目标镜像中包含的软件可以包含参数`CMD` 大多数情况下都应该以 `CMD ["executable", "param1", "param2"...]` 的形式使用因此如果创建镜像的目的是为了部署某个服务(比如 `Apache`)你可能会执行类似于 `CMD ["apache2", "-DFOREGROUND"]` 形式的命令我们建议任何服务镜像都使用这种形式的命令
多数情况下`CMD` 都需要一个交互式的 `shell` (bash, Python, perl )例如 `CMD ["perl", "-de0"]`或者 `CMD ["PHP", "-a"]`使用这种形式意味着当你执行类似 `docker run -it python` 你会进入一个准备好的 `shell` `CMD` 应该在极少的情况下才能以 `CMD ["param", "param"]` 的形式与 `ENTRYPOINT` 协同使用除非你和你的镜像使用者都对 `ENTRYPOINT` 的工作方式十分熟悉
#### EXPOSE
`EXPOSE` 指令用于指定容器将要监听的端口因此你应该为你的应用程序使用常见的端口例如提供 `Apache` web 服务的镜像应该使用 `EXPOSE 80`而提供 `MongoDB` 服务的镜像使用 `EXPOSE 27017`
对于外部访问用户可以在执行 `docker run` 时使用一个标志来指示如何将指定的端口映射到所选择的端口
#### ENV
为了方便新程序运行你可以使用 `ENV` 来为容器中安装的程序更新 `PATH` 环境变量例如使用 `ENV PATH /usr/local/nginx/bin:$PATH` 来确保 `CMD ["nginx"]` 能正确运行
`ENV` 指令也可用于为你想要容器化的服务提供必要的环境变量比如 Postgres 需要的 `PGDATA`
最后`ENV` 也能用于设置常见的版本号比如下面的示例
```docker
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
```
类似于程序中的常量这种方法可以让你只需改变 `ENV` 指令来自动的改变容器中的软件版本
#### ADD COPY
虽然 `ADD` `COPY` 功能类似但一般优先使用 `COPY`因为它比 `ADD` 更透明`COPY` 只支持简单将本地文件拷贝到容器中 `ADD` 有一些并不明显的功能比如本地 tar 提取和远程 URL 支持因此`ADD` 的最佳用例是将本地 tar 文件自动提取到镜像中例如 `ADD rootfs.tar.xz`
如果你的 `Dockerfile` 有多个步骤需要使用上下文中不同的文件单独 `COPY` 每个文件而不是一次性的 `COPY` 所有文件这将保证每个步骤的构建缓存只在特定的文件变化时失效例如
```docker
COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/
```
如果将 `COPY . /tmp/` 放置在 `RUN` 指令之前只要 `.` 目录中任何一个文件变化都会导致后续指令的缓存失效
为了让镜像尽量小最好不要使用 `ADD` 指令从远程 URL 获取包而是使用 `curl` `wget`这样你可以在文件提取完之后删掉不再需要的文件来避免在镜像中额外添加一层比如尽量避免下面的用法
```docker
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
```
而是应该使用下面这种方法
```docker
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
```
上面使用的管道操作所以没有中间文件需要删除
对于其他不需要 `ADD` 的自动提取功能的文件或目录你应该使用 `COPY`
#### ENTRYPOINT
`ENTRYPOINT` 的最佳用处是设置镜像的主命令允许将镜像当成命令本身来运行 `CMD` 提供默认选项
例如下面的示例镜像提供了命令行工具 `s3cmd`:
```docker
ENTRYPOINT ["s3cmd"]
CMD ["--help"]
```
现在直接运行该镜像创建的容器会显示命令帮助
```bash
$ docker run s3cmd
```
或者提供正确的参数来执行某个命令
```bash
$ docker run s3cmd ls s3://mybucket
```
这样镜像名可以当成命令行的参考
`ENTRYPOINT` 指令也可以结合一个辅助脚本使用和前面命令行风格类似即使启动工具需要不止一个步骤
例如`Postgres` 官方镜像使用下面的脚本作为 `ENTRYPOINT`
```bash
#!/bin/bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
```
>注意该脚本使用了 Bash 的内置命令 exec所以最后运行的进程就是容器的 PID 1 的进程这样进程就可以接收到任何发送给容器的 Unix 信号了
该辅助脚本被拷贝到容器并在容器启动时通过 `ENTRYPOINT` 执行
```docker
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
```
该脚本可以让用户用几种不同的方式和 `Postgres` 交互
你可以很简单地启动 `Postgres`
```bash
$ docker run postgres
```
也可以执行 `Postgres` 并传递参数
```bash
$ docker run postgres postgres --help
```
最后你还可以启动另外一个完全不同的工具比如 `Bash`
```bash
$ docker run --rm -it postgres bash
```
#### VOLUME
`VOLUME` 指令用于暴露任何数据库存储文件配置文件或容器创建的文件和目录强烈建议使用 `VOLUME` 来管理镜像中的可变部分和用户可以改变的部分
#### USER
如果某个服务不需要特权执行建议使用 `USER` 指令切换到非 root 用户先在 `Dockerfile` 中使用类似 `RUN groupadd -r postgres && useradd -r -g postgres postgres` 的指令创建用户和用户组
>注意在镜像中用户和用户组每次被分配的 UID/GID 都是不确定的下次重新构建镜像时被分配到的 UID/GID 可能会不一样如果要依赖确定的 UID/GID你应该显式的指定一个 UID/GID
你应该避免使用 `sudo`因为它不可预期的 TTY 和信号转发行为可能造成的问题比它能解决的问题还多如果你真的需要和 `sudo` 类似的功能例如 root 权限初始化某个守护进程以非 root 权限执行它你可以使用 [gosu](https://github.com/tianon/gosu)。
最后为了减少层数和复杂度避免频繁地使用 `USER` 来回切换用户
#### WORKDIR
为了清晰性和可靠性你应该总是在 `WORKDIR` 中使用绝对路径另外你应该使用 `WORKDIR` 来替代类似于 `RUN cd ... && do-something` 的指令后者难以阅读排错和维护
### 官方镜像示例
这些官方镜像的 Dockerfile 都是参考典范https://github.com/docker-library/docs

75
16_appendix/16.2_debug.md Normal file
View File

@@ -0,0 +1,75 @@
## 16.2 如何调试 Docker
### 开启 Debug 模式
dockerd 配置文件 daemon.json默认位于 /etc/docker/中添加
```json
{
"debug": true
}
```
重启守护进程
```bash
$ sudo kill -SIGHUP $(pidof dockerd)
```
此时 dockerd 会在日志中输入更多信息供分析
### 检查内核日志
运行以下命令
```bash
$ sudo dmesg |grep dockerd
$ sudo dmesg |grep runc
```
### Docker 不响应时处理
可以杀死 dockerd 进程查看其堆栈调用情况
```bash
$ sudo kill -SIGUSR1 $(pidof dockerd)
```
### 重置 Docker 本地数据
*注意本操作会移除所有的 Docker 本地数据包括镜像和容器等*
$ sudo rm -rf /var/lib/docker
```
### 常见故障排查
#### 容器启动失败
如果容器启动后立即退出,可以使用 `docker logs` 查看原因。
* **Exit Code 1**: 应用程序错误。通常是配置错误或依赖缺失。
* **Exit Code 137**: OOM (Out Of Memory)。容器内存不足被内核杀掉。
* 检查宿主机内存。
* 调整容器内存限制 (`--memory`)。
* **Exit Code 127**: 命令未找到。可能是 `ENTRYPOINT``CMD` 指定的命令不存在。
#### 网络连接问题
##### 容器内部无法联网
1. 检查 Docker DNS 配置 (`/etc/docker/daemon.json`)。
2. 检查宿主机防火墙 (iptables/firewalld) 是否拦截了转发。
3. 容器内测试: `ping 8.8.8.8` (测试连通性), `nslookup google.com` (测试 DNS)。
##### 端口映射不通
1. 检查容器端口是否正确监听: `netstat -tunlp` (宿主机) 或 `docker exec <container> netstat -tunlp`
2. 确认应用监听地址是 `0.0.0.0` 而不是 `127.0.0.1`
* 如果应用监听在 `127.0.0.1`只有容器内部能访问映射到宿主机外部也无法被外部请求访问
#### 镜像拉取失败
* **connection refused**: 检查网络或代理设置
* **image not found**: 检查镜像名称和 Tag 拼写
* **EOF / timeout**: 网络不稳定尝试配置镜像加速器

View File

@@ -0,0 +1,29 @@
## 16.3 资源链接
### 官方网站
* Docker 官方主页https://www.docker.com
* Docker 官方博客https://www.docker.com/blog/
* Docker 官方文档https://docs.docker.com/
* Docker Hubhttps://hub.docker.com
* Docker 的源代码仓库https://github.com/moby/moby
* Docker 路线图 https://github.com/docker/roadmap/projects
* Docker 发布版本历史https://docs.docker.com/release-notes/
* Docker 常见问题https://docs.docker.com/engine/faq/
* Docker 远端应用 APIhttps://docs.docker.com/develop/sdk/
### 实践参考
* Dockerfile 参考https://docs.docker.com/engine/reference/builder/
* Dockerfile 最佳实践https://docs.docker.com/build/building/best-practices/
### 技术交流
* Docker 邮件列表 https://groups.google.com/forum/#!forum/docker-user
* Docker 社区 Slackhttps://dockercommunity.slack.com/
* Docker Community Discord: https://discord.gg/docker
* Docker Twitter 主页https://twitter.com/docker
### 其它
* Docker StackOverflow 问答主页https://stackoverflow.com/search?q=docker

12
16_appendix/README.md Normal file
View File

@@ -0,0 +1,12 @@
# 第十六章 附录
本章包含了 Docker 相关的参考资料常见问题解答以及最佳实践指南旨在为读者提供便捷的查阅工具
## 目录
* [**常见问题总结 (FAQ)**](faq/README.md)汇总了学习和使用 Docker 过程中的常见问题与错误解决方案
* [**热门镜像介绍**](repo/README.md)详细介绍了 Nginx, MySQL, Redis 等常用官方镜像的使用方法
* [**Docker 命令查询**](command/README.md)速查 Docker 客户端和服务端的常用命令
* [**Dockerfile 最佳实践**](16.1_best_practices.md)提供编写高效安全 Dockerfile 的指导原则
* [**如何调试 Docker**](16.2_debug.md)介绍 Docker 调试技巧和工具
* [**资源链接**](16.3_resources.md)推荐更多 Docker 相关的学习资源

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,56 @@
//dot -Tpng xx.dot -o xx.png
digraph G {
rankdir=TB;
fontname = "Microsoft YaHei";
fontsize = 14;
penwidth = 3;
compound=true;
rankdir=LR;
node [shape = record];
edge [fontname = "Arial", fontsize = 12, color="darkgreen" ];
image[label="Image",color=blue];
registry[label="Registry",color=blue];
tar[label="Tar files",color=blue];
subgraph cluster_container {
label = "Container";
style = "bold";
color = blue;
edge [fontname = "Arial", fontsize = 11, color="skyblue" ];
//node [style=filled];
run[label="Running",shape=circle, style=filled, fillcolor=green];
stop[label="Stopped",shape=circle, style=filled, fillcolor=red];
pause[label="Paused",shape=circle, style=filled, fillcolor=blue];
run->pause[label="pause"];
pause->run[label="unpause"];
run->run[label="restart"];
run->stop[label="kill"];
stop->run[label="start"];
}
run->image[label="commit",ltail=cluster_container];
image->run[label="start"];
image->tar[label="export|save"];
tar->image[label="import"];
image->registry[label="push"];
registry->image[label="pull"];
//heat[label="heat commands",color=blue];
//heatshell[label="heatclient.shell.HeatShell",color=blue];
//shell[label="{heatclient.v1.shell|+do_stack_create\l+do_stack_show\l+do_stack_update\l...\l+do_event_list\l...\l+do_resource_list\l...\l+do_resource_type_show\l...\l+do_template_show\l...\l}",color=blue];
//heatclient[label="heatclient.client.Client",color=blue];
//client[label="heatclient.v1.client.Client",color=blue];
//httpclient[label="heatclient.common.http.HTTPClient",color=blue];
//openstackservices[label="{OpenStack Services|+Nova\l+Neutron\l+Keystone\l...}",color=blue];
//{rank=same; image cluster_container}
//{rank=same; rpcproxy apimixin}
}

View File

@@ -0,0 +1,93 @@
//dot -Tpng cmd_logic.dot -o cmd_logic.png
digraph G {
rankdir=TB;
rankdir=LR;
nodesep=1;
//ranksep=1
fontname = "Microsoft YaHei";
fontsize = 28;
penwidth = 4;
compound=true;
node [shape = record];
edge [fontname = "Arial", fontsize = 20, color="darkgreen" ];
user[label="User",color=blue,shape=ellipse, style=filled, fillcolor=green];
dockerfile[label="Dockerfile",color=blue];
daemon[label="Daemon",color=blue];
image[label="Image",color=blue];
registry[label="Registry",color=blue];
tar[label="Tar files",color=blue];
network[label="Network",color=blue]
service[label="Service",color=blue]
swarm[label="Swarm",color=blue]
volume[label="Volume",color=blue]
subgraph cluster_container {
label = "Container";
labelloc = "c";
nodesep=.5;
style = "bold";
color = blue;
edge [fontname = "Arial", fontsize = 20, color="skyblue" ];
//node [style=filled];
create[label="Created",shape=circle, style=filled, fillcolor=lightblue];
run[label="Running",shape=circle, style=filled, fillcolor=green];
pause[label="Paused",shape=circle, style=filled, fillcolor=blue];
stop[label="Stopped",shape=circle, style=filled, fillcolor=red];
exit[label="Exited",shape=circle, style=filled, fillcolor=gray];
create->run[label=<<i>start</i>>];
run->pause[label="pause"];
pause->run[label="unpause"];
run->run[label="restart"];
run->stop[label="stop"];
run->exit[label="kill"];
stop->run[label="start"];
}
//dockerfile
dockerfile->image[label="build"];
//container
run->image[headlabel="commit", labeldistance=7.5, ltail=cluster_container];
run->tar[label="export",ltail=cluster_container];
run->network[label="connect | disconnect",ltail=cluster_container];
//image
image->create[label="create"];
image->run[label="run"];
image->tar[label="save"];
image->registry[label="push"];
//tar
tar->image[label="import | load"];
image->registry[label="push"];
//registry
registry->image[label="pull"];
//network
network->network[label="create | rm | ls | inspect"]
//user
user->run[label="attach | cp | diff | exec | inspect | logs | ps | rename | rm | stats | top | update | wait",lhead=cluster_container]
user->image[label="history | images | rmi | tag"]
user->daemon[label="event | info | version"]
user->registry[label="login | logout | search"]
//heat[label="heat commands",color=blue];
//heatshell[label="heatclient.shell.HeatShell",color=blue];
//shell[label="{heatclient.v1.shell|+do_stack_create\l+do_stack_show\l+do_stack_update\l...\l+do_event_list\l...\l+do_resource_list\l...\l+do_resource_type_show\l...\l+do_template_show\l...\l}",color=blue];
//heatclient[label="heatclient.client.Client",color=blue];
//client[label="heatclient.v1.client.Client",color=blue];
//httpclient[label="heatclient.common.http.HTTPClient",color=blue];
//openstackservices[label="{OpenStack Services|+Nova\l+Neutron\l+Keystone\l...}",color=blue];
//{rank=same; image registry dockerfile tar}
//{rank=same; container}
//{rank=same; user}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 KiB

View File

@@ -0,0 +1,51 @@
//dot -Tpng container_status.dot -o container_status.png
digraph G {
rankdir=TB;
rankdir=LR;
nodesep=1;
//ranksep=1
fontname = "Microsoft YaHei";
fontsize = 28;
penwidth = 4;
compound=true;
style = "bold";
color = blue;
node [shape = record];
edge [fontname = "Arial", fontsize = 20, color="darkgreen" ];
image[label="Image",color=blue];
image->create[label="create"];
image->run[label="run"];
edge [fontname = "Arial", fontsize = 20, color="skyblue" ];
//node [style=filled];
create[label="Created",shape=circle, style=filled, fillcolor=lightblue];
run[label="Running",shape=circle, style=filled, fillcolor=green];
pause[label="Paused",shape=circle, style=filled, fillcolor=blue];
stop[label="Stopped",shape=circle, style=filled, fillcolor=red];
exit[label="Exited",shape=circle, style=filled, fillcolor=gray];
create->run[label=<<i>start</i>>];
run->pause[label="pause"];
pause->run[label="unpause"];
run->run[label="restart"];
run->stop[label="stop"];
run->exit[label="kill"];
stop->run[label="start"];
//heat[label="heat commands",color=blue];
//heatshell[label="heatclient.shell.HeatShell",color=blue];
//shell[label="{heatclient.v1.shell|+do_stack_create\l+do_stack_show\l+do_stack_update\l...\l+do_event_list\l...\l+do_resource_list\l...\l+do_resource_type_show\l...\l+do_template_show\l...\l}",color=blue];
//heatclient[label="heatclient.client.Client",color=blue];
//client[label="heatclient.v1.client.Client",color=blue];
//httpclient[label="heatclient.common.http.HTTPClient",color=blue];
//openstackservices[label="{OpenStack Services|+Nova\l+Neutron\l+Keystone\l...}",color=blue];
//{rank=same; image registry dockerfile tar}
//{rank=same; container}
//{rank=same; user}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -0,0 +1,13 @@
# Docker 命令查询
## 基本语法
Docker 命令有两大类客户端命令和服务端命令前者是主要的操作接口后者用来启动 Docker Daemon
* 客户端命令基本命令格式为 `docker [OPTIONS] COMMAND [arg...]`
* 服务端命令基本命令格式为 `dockerd [OPTIONS]`
可以通过 `man docker` `docker help` 来查看这些命令
接下来的小节对这两个命令进行介绍

View File

@@ -0,0 +1,73 @@
## 客户端命令 - docker
### 客户端命令选项
* `--config=""`指定客户端配置文件默认为 `~/.docker`
* `-D=true|false`是否使用 debug 模式默认不开启
* `-H, --host=[]`指定命令对应 Docker 守护进程的监听接口可以为 unix 套接字 `unix:///path/to/socket`文件句柄 `fd://socketfd` tcp 套接字 `tcp://[host[:port]]`默认为 `unix:///var/run/docker.sock`
* `-l, --log-level="debug|info|warn|error|fatal"`指定日志输出级别
* `--tls=true|false`是否对 Docker 守护进程启用 TLS 安全机制默认为否
* `--tlscacert=/.docker/ca.pem`TLS CA 签名的可信证书文件路径
* `--tlscert=/.docker/cert.pem`TLS 可信证书文件路径
* `--tlscert=/.docker/key.pem`TLS 密钥文件路径
* `--tlsverify=true|false`启用 TLS 校验默认为否
### 客户端命令
可以通过 `docker COMMAND --help` 来查看这些命令的具体用法
* `attach`依附到一个正在运行的容器中
* `build`从一个 Dockerfile 创建一个镜像
* `commit`从一个容器的修改中创建一个新的镜像
* `cp`在容器和本地宿主系统之间复制文件中
* `create`创建一个新容器但并不运行它
* `diff`检查一个容器内文件系统的修改包括修改和增加
* `events`从服务端获取实时的事件
* `exec`在运行的容器内执行命令
* `export`导出容器内容为一个 `tar`
* `history`显示一个镜像的历史信息
* `images`列出存在的镜像
* `import`导入一个文件典型为 `tar` 路径或目录来创建一个本地镜像
* `info`显示一些相关的系统信息
* `inspect`显示一个容器的具体配置信息
* `kill`关闭一个运行中的容器 (包括进程和所有相关资源)
* `load`从一个 tar 包中加载一个镜像
* `login`注册或登录到一个 Docker 的仓库服务器
* `logout` Docker 的仓库服务器登出
* `logs`获取容器的 log 信息
* `network`管理 Docker 的网络包括查看创建删除挂载卸载等
* `node`管理 swarm 集群中的节点包括查看更新删除提升/取消管理节点等
* `pause`暂停一个容器中的所有进程
* `port`查找一个 nat 到一个私有网口的公共口
* `ps`列出主机上的容器
* `pull`从一个Docker的仓库服务器下拉一个镜像或仓库
* `push`将一个镜像或者仓库推送到一个 Docker 的注册服务器
* `rename`重命名一个容器
* `restart`重启一个运行中的容器
* `rm`删除给定的若干个容器
* `rmi`删除给定的若干个镜像
* `run`创建一个新容器并在其中运行给定命令
* `save`保存一个镜像为 tar 包文件
* `search` Docker index 中搜索一个镜像
* `service`管理 Docker 所启动的应用服务包括创建更新删除等
* `start`启动一个容器
* `stats`输出一个或多个容器的资源使用统计信息
* `stop`终止一个运行中的容器
* `swarm`管理 Docker swarm 集群包括创建加入退出更新等
* `tag`为一个镜像打标签
* `top`查看一个容器中的正在运行的进程信息
* `unpause`将一个容器内所有的进程从暂停状态中恢复
* `update`更新指定的若干容器的配置信息
* `version`输出 Docker 的版本信息
* `volume`管理 Docker volume包括查看创建删除等
* `wait`阻塞直到一个容器终止然后输出它的退出符
### 一张图总结 Docker 的命令
一张图总结 Docker 的命令 示意图如下
![Docker 命令总结](../../_images/cmd_logic.png)
### 参考
* [官方文档](https://docs.docker.com/engine/reference/commandline/cli/)

View File

@@ -0,0 +1,58 @@
## 服务端命令dockerd
### dockerd 命令选项
* `--api-cors-header=""`CORS 头部域默认不允许 CORS要允许任意的跨域访问可以指定为 "*"
* `--authorization-plugin=""`载入认证的插件
* `-b=""`将容器挂载到一个已存在的网桥上指定为 `none` 时则禁用容器的网络 `--bip` 选项互斥
* `--bip=""`让动态创建的 `docker0` 网桥采用给定的 CIDR 地址; `-b` 选项互斥
* `--cgroup-parent=""`指定 cgroup 的父组默认 fs cgroup 驱动为 `/docker`systemd cgroup 驱动为 `system.slice`
* `--cluster-store=""`构成集群 `Swarm`集群键值数据库服务地址
* `--cluster-advertise=""`构成集群时自身的被访问地址可以为 `host:port` `interface:port`
* `--cluster-store-opt=""`构成集群时键值数据库的配置选项
* `--config-file="/etc/docker/daemon.json"`daemon 配置文件路径
* `--containerd=""`containerd 文件的路径
* `-D, --debug=true|false`是否使用 Debug 模式缺省为 false
* `--default-gateway=""`容器的 IPv4 网关地址必须在网桥的子网段内
* `--default-gateway-v6=""`容器的 IPv6 网关地址
* `--default-ulimit=[]`默认的 ulimit
* `--disable-legacy-registry=true|false`是否允许访问旧版本的镜像仓库服务器
* `--dns=""`指定容器使用的 DNS 服务器地址
* `--dns-opt=""`DNS 选项
* `--dns-search=[]`DNS 搜索域
* `--exec-opt=[]`运行时的执行选项
* `--exec-root=""`容器执行状态文件的根路径默认为 `/var/run/docker`
* `--fixed-cidr=""`限定分配 IPv4 地址范围
* `--fixed-cidr-v6=""`限定分配 IPv6 地址范围
* `-G, --group=""`分配给 unix 套接字的组默认为 `docker`
* `-g, --graph=""`Docker 运行时的根路径默认为 `/var/lib/docker`
* `-H, --host=[]`指定命令对应 Docker daemon 的监听接口可以为 unix 套接字 `unix:///path/to/socket`文件句柄 `fd://socketfd` tcp 套接字 `tcp://[host[:port]]`默认为 `unix:///var/run/docker.sock`
* `--icc=true|false`是否启用容器间以及跟 daemon 所在主机的通信默认为 true
* `--insecure-registry=[]`允许访问给定的非安全仓库服务
* `--ip=""`绑定容器端口时候的默认 IP 地址缺省为 `0.0.0.0`
* `--ip-forward=true|false`是否检查启动在 Docker 主机上的启用 IP 转发服务默认开启注意关闭该选项将不对系统转发能力进行任何检查修改
* `--ip-masq=true|false`是否进行地址伪装用于容器访问外部网络默认开启
* `--iptables=true|false`是否允许 Docker 添加 iptables 规则缺省为 true
* `--ipv6=true|false`是否启用 IPv6 支持默认关闭
* `-l, --log-level="debug|info|warn|error|fatal"`指定日志输出级别
* `--label="[]"`添加指定的键值对标注
* `--log-driver="json-file|syslog|journald|gelf|fluentd|awslogs|splunk|etwlogs|gcplogs|none"`指定日志后端驱动默认为 `json-file`
* `--log-opt=[]`日志后端的选项
* `--mtu=VALUE`指定容器网络的 `mtu`
* `-p=""`指定 daemon PID 文件路径缺省为 `/var/run/docker.pid`
* `--raw-logs`输出原始未加色彩的日志信息
* `--registry-mirror=<scheme>://<host>`指定 `docker pull` 时使用的注册服务器镜像地址
* `-s, --storage-driver=""`指定使用给定的存储后端
* `--selinux-enabled=true|false`是否启用 SELinux 支持缺省值为 falseSELinux 目前尚不支持 overlay 存储驱动
* `--storage-opt=[]`驱动后端选项
* `--tls=true|false`是否对 Docker daemon 启用 TLS 安全机制默认为否
* `--tlscacert=/.docker/ca.pem`TLS CA 签名的可信证书文件路径
* `--tlscert=/.docker/cert.pem`TLS 可信证书文件路径
* `--tlscert=/.docker/key.pem`TLS 密钥文件路径
* `--tlsverify=true|false`启用 TLS 校验默认为否
* `--userland-proxy=true|false`是否使用用户态代理来实现容器间和出容器的回环通信默认为 true
* `--userns-remap=default|uid:gid|user:group|user|uid`指定容器的用户命名空间默认是创建新的 UID GID 映射到容器内进程
### 参考
* [官方文档](https://docs.docker.com/engine/reference/commandline/dockerd/)

213
16_appendix/faq/README.md Normal file
View File

@@ -0,0 +1,213 @@
# 附录一常见问题总结
## 镜像相关
### 如何批量清理临时镜像文件
可以使用 `docker image prune` 命令
### 如何查看镜像支持的环境变量
可以使用 `docker run IMAGE env` 命令
### 本地的镜像文件都存放在哪里
Docker 相关的本地资源默认存放在 `/var/lib/docker/` 目录下 `overlay2` 文件系统为例其中 `containers` 目录存放容器信息`image` 目录存放镜像信息`overlay2` 目录下存放具体的镜像层文件
### 构建 Docker 镜像应该遵循哪些原则
整体原则上尽量保持镜像功能的明确和内容的精简要点包括
* 尽量选取满足需求但较小的基础系统镜像例如大部分时候可以选择 `alpine` 镜像仅有不足六兆大小
* 清理编译生成文件安装包的缓存等临时文件
* 安装各个软件时候要指定准确的版本号并避免引入不需要的依赖
* 从安全角度考虑应用要尽量使用系统的库和依赖
* 如果安装应用时候需要配置一些特殊的环境变量在安装后要还原不需要保持的变量值
* 使用 Dockerfile 创建镜像时候要添加 .dockerignore 文件或使用干净的工作目录
更多内容请查看 [Dockerfile 最佳实践](../16.1_best_practices.md)
### 碰到网络问题无法 pull 镜像命令行指定 http\_proxy 无效
Docker 配置文件中添加 `export http_proxy="http://<PROXY_HOST>:<PROXY_PORT>"`之后重启 Docker 服务即可
## 容器相关
### 容器退出后通过 docker container ls 命令查看不到数据会丢失么
容器退出后会处于终止exited状态此时可以通过 `docker container ls -a` 查看其中的数据也不会丢失还可以通过 `docker start` 命令来启动它只有删除掉容器才会清除所有数据
### 如何停止所有正在运行的容器
可以使用 `docker stop $(docker container ls -q)` 命令
### 如何批量清理已经停止的容器
可以使用 `docker container prune` 命令
### 如何获取某个容器的 PID 信息
可以使用
```bash
docker inspect --format '{{ .State.Pid }}' <CONTAINER ID or NAME>
```
### 如何获取某个容器的 IP 地址
可以使用
```bash
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <CONTAINER ID or NAME>
```
### 如何给容器指定一个固定 IP 地址而不是每次重启容器 IP 地址都会变
使用以下命令启动容器可以使容器 IP 固定不变
```bash
$ docker network create -d bridge --subnet 172.25.0.0/16 my-net
$ docker run --network=my-net --ip=172.25.3.3 -itd --name=my-container busybox
```
### 如何临时退出一个正在交互的容器的终端而不终止它
`Ctrl-p Ctrl-q`如果按 `Ctrl-c` 往往会让容器内应用进程终止进而会终止容器
### 使用 `docker port` 命令映射容器的端口时系统报错Error: No public port '80' published for xxx
* 创建镜像时 `Dockerfile` 要通过 `EXPOSE` 指定正确的开放端口
* 容器启动时指定 `PublishAllPort = true`
### 可以在一个容器中同时运行多个应用进程么
一般并不推荐在同一个容器内运行多个应用进程如果有类似需求可以通过一些额外的进程管理机制比如 `supervisord` 来管理所运行的进程可以参考 https://docs.docker.com/config/containers/multi-service\_container/ 。
### 如何控制容器占用系统资源CPU内存的份额
在使用 `docker create` 命令创建容器或使用 `docker run` 创建并启动容器的时候可以使用 -c|--cpu-shares\[=0] 参数来调整容器使用 CPU 的权重使用 -m|--memory\[=MEMORY] 参数来调整容器使用内存的大小
## 仓库相关
### 仓库Repository注册服务器Registry注册索引Index 有何关系
首先仓库是存放一组关联镜像的集合比如同一个应用的不同版本的镜像
注册服务器是存放实际的镜像文件的地方注册索引则负责维护用户的账号权限搜索标签等的管理因此注册服务器利用注册索引来实现认证等管理
## 配置相关
### Docker 的配置文件放在哪里如何修改配置
使用 `systemd` 的系统 Ubuntu 16.04Centos 的配置文件在 `/etc/docker/daemon.json`
### 如何更改 Docker 的默认存储位置
Docker 的默认存储位置是 `/var/lib/docker`如果希望将 Docker 的本地文件存储到其他分区可以使用 Linux 软连接的方式来完成或者在启动 daemon 时通过 `-g` 参数指定或者修改配置文件 `/etc/docker/daemon.json` "data-root" 可以使用 `docker system info | grep "Root Dir"` 查看当前使用的存储位置
例如如下操作将默认存储位置迁移到 /storage/docker
```
[root@s26 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root 50G 5.3G 42G 12% /
tmpfs 48G 228K 48G 1% /dev/shm
/dev/sda1 485M 40M 420M 9% /boot
/dev/mapper/VolGroup-lv_home 222G 188M 210G 1% /home
/dev/sdb2 2.7T 323G 2.3T 13% /storage
[root@s26 ~]# service docker stop
[root@s26 ~]# cd /var/lib/
[root@s26 lib]# mv docker /storage/
[root@s26 lib]# ln -s /storage/docker/ docker
[root@s26 lib]# ls -la docker
lrwxrwxrwx. 1 root root 15 11月 17 13:43 docker -> /storage/docker
[root@s26 lib]# service docker start
```
### 使用内存和 swap 限制启动容器时候报警告"WARNING: Your kernel does not support cgroup swap limit. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded."
这是因为系统默认没有开启对内存和 swap 使用的统计功能引入该功能会带来性能的下降要开启该功能可以采取如下操作
* 编辑 `/etc/default/grub` 文件Ubuntu 系统为例配置 `GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"`
* 更新 grub`$ sudo update-grub`
* 重启系统即可
## Docker 与虚拟化
### Docker LXCLinux Container有何不同
LXC 利用 Linux 上相关技术实现了容器Docker 则在如下的几个方面进行了改进
* 移植性通过抽象容器配置容器可以实现从一个平台移植到另一个平台
* 镜像系统基于 OverlayFS 的镜像系统为容器的分发带来了很多的便利同时共同的镜像层只需要存储一份实现高效率的存储
* 版本管理类似于Git的版本管理理念用户可以更方便的创建管理镜像文件
* 仓库系统仓库系统大大降低了镜像的分发和管理的成本
* 周边工具各种现有工具配置管理云平台 Docker 的支持以及基于 Docker的 PaaSCI 等系统 Docker 的应用更加方便和多样化
### Docker Vagrant 有何不同
两者的定位完全不同
* Vagrant 类似 Boot2Docker一款运行 Docker 的最小内核是一套虚拟机的管理环境Vagrant 可以在多种系统上和虚拟机软件中运行可以在 WindowsMac 等非 Linux 平台上为 Docker 提供支持自身具有较好的包装性和移植性
* 原生的 Docker 自身只能运行在 Linux 平台上但启动和运行的性能都比虚拟机要快往往更适合快速开发和部署应用的场景
简单说Vagrant 适合用来管理虚拟机 Docker 适合用来管理应用环境
### 开发环境中 Docker Vagrant 该如何选择
Docker 不是虚拟机而是进程隔离对于资源的消耗很少但是目前需要 Linux 环境支持Vagrant 是虚拟机上做的封装虚拟机本身会消耗资源
如果本地使用的 Linux 环境推荐都使用 Docker
如果本地使用的是 macOS 或者 Windows 环境那就需要开虚拟机单一开发环境下 Vagrant 更简单多环境开发下推荐在 Vagrant 里面再使用 Docker 进行环境隔离
## 其它
### Docker 能在非 Linux 平台比如 Windows macOS 上运行么
完全可以安装方法请查看 [安装 Docker](../../install/) 一节
### 如何将一台宿主主机的 Docker 环境迁移到另外一台宿主主机
停止 Docker 服务将整个 Docker 存储文件夹复制到另外一台宿主主机然后调整另外一台宿主主机的配置即可
### 如何进入 Docker 容器的网络命名空间
Docker 在创建容器后删除了宿主主机上 `/var/run/netns` 目录中的相关的网络命名空间文件因此在宿主主机上是无法看到或访问容器的网络命名空间的
用户可以通过如下方法来手动恢复它
首先使用下面的命令查看容器进程信息比如这里的 1234
```bash
$ docker inspect --format='{{. State.Pid}} ' $container_id
1234
```
接下来 `/proc` 目录下把对应的网络命名空间文件链接到 `/var/run/netns` 目录
```bash
$ sudo ln -s /proc/1234/ns/net /var/run/netns/
```
然后在宿主主机上就可以看到容器的网络命名空间信息例如
```bash
$ sudo ip netns show
1234
```
此时用户可以通过正常的系统命令来查看或操作容器的命名空间了例如修改容器的 IP 地址信息为 `172.17.0.100/16`
```bash
$ sudo ip netns exec 1234 ifconfig eth0 172.17.0.100/16
```
### 如何获取容器绑定到本地那个 veth 接口上
Docker 容器启动后会通过 veth 接口对连接到本地网桥veth 接口命名跟容器命名毫无关系十分难以找到对应关系
最简单的一种方式是通过查看接口的索引号在容器中执行 `ip a` 命令查看到本地接口最前面的接口索引号 `205`将此值加上 1 `206`然后在本地主机执行 `ip a` 命令查找接口索引号为 `206` 的接口两者即为连接的 veth 接口对

13
16_appendix/faq/errors.md Normal file
View File

@@ -0,0 +1,13 @@
## 常见错误速查表
| 错误信息 / 现象 | 可能原因 | 解决方案 |
| :--- | :--- | :--- |
| `Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?` | Docker 服务未启动 | Linux: `sudo systemctl start docker`<br>Mac/Win: 启动 Docker Desktop |
| `permission denied while trying to connect to the Docker daemon socket` | 当前用户不在 `docker` 用户组 | `sudo usermod -aG docker $USER` (需重新登录) |
| `manifest for ... not found: manifest unknown` | 镜像 tag 不存在 | 检查 Docker Hub 该镜像是否存在该 tag或拼写是否正确 |
| `connection refused` (pull image) | 网络不通或镜像源无法访问 | 检查网络配置[镜像加速器](../../install/3.9_mirror.md) |
| `Bind for 0.0.0.0:8080 failed: port is already allocated` | 端口被占用 | 检查占用端口的进程 (`lsof -i:8080`) 并杀掉或换个端口映射 (`-p 8081:80`) |
| `exec user process caused "exec format error"` | 架构不匹配 (如在 x86 上跑 ARM 镜像) | 使用 `docker buildx` 构建多架构镜像或拉取对应架构的镜像 |
| `standard_init_linux.go:211: exec user process caused "no such file or directory"` | 找不到解释器或依赖库 | 检查 `ENTRYPOINT`/`CMD` 脚本开头的 shebang (`#!/bin/sh` vs `#!/bin/bash`)或确认二进制文件是否依赖缺失 (Alpine 常见缺少 glibc) |
| `iptables: No chain/target/match by that name` | 防火墙规则缺失或冲突 | 重启 Docker 服务重置 iptables : `sudo systemctl restart docker` |
| 容器内无法访问外网 | DNS 配置或转发问题 | 检查 `/etc/docker/daemon.json` 中的 DNS 配置 |

View File

@@ -0,0 +1,3 @@
# 热门镜像介绍
本章将介绍一些热门镜像的功能使用方法等包括 UbuntuCentOSMySQLMongoDBRedisNginxWordpressNode.js

View File

@@ -0,0 +1,32 @@
## [CentOS](https://hub.docker.com/_/centos)
### 基本信息
[CentOS](https://en.wikipedia.org/wiki/CentOS) 是流行的 Linux 发行版,其软件包大多跟 RedHat 系列保持一致。
> **重要提示**CentOS 8 已于 2021 12 31 日停止维护EOLCentOS 7 也已于 2024 6 30 **完全结束支持**Docker Hub 上的 CentOS 官方镜像**已停止更新**且存在未修复的安全漏洞
>
> 2026 年了对于任何新项目**强烈建议**使用以下生产级替代方案
> - [Rocky Linux](https://hub.docker.com/_/rockylinux)CentOS 原创始人发起的社区驱动项目,目前主流为 Rocky Linux 9。
> - [AlmaLinux](https://hub.docker.com/_/almalinux):由 CloudLinux 支持的企业级发行版,提供长期支持。
> - [CentOS Stream](https://hub.docker.com/r/centos/centos)RHEL 的上游开发分支(适合开发测试,不建议用于生产环境)。
该仓库位于 `https://hub.docker.com/_/centos`提供了 CentOS 5 ~ 8 各个版本的镜像仅作为历史归档不再更新
### 使用方法
使用 Rocky Linux 9 替代**推荐**
```bash
$ docker run --name rocky -it rockylinux:9 bash
```
使用旧版 CentOS 7**仅用于维护旧项目不推荐**
```bash
$ docker run --name centos -it centos:7 bash
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/centos 查看。

58
16_appendix/repo/minio.md Normal file
View File

@@ -0,0 +1,58 @@
## minio
**MinIO** 是一个基于 Apache License v2.0 开源协议的对象存储服务它兼容亚马逊 S3 云存储服务接口非常适合于存储大容量非结构化的数据例如图片视频日志文件备份数据和容器/虚拟机镜像等而一个对象文件可以是任意大小从几 kb 到最大 5T 不等
MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合类似 NodeJS, Redis 或者 MySQL
[官方文档](https://docs.min.io/)
### 简单使用
测试开发环境下不考虑数据存储的情况下可以使用下面的命令快速开启服务
```bash
$ docker run -d -p 9000:9000 -p 9090:9090 minio/minio server /data --console-address ':9090'
```
### 离线部署
许多生产环境是一般是没有公网资源的这就需要从有公网资源的服务器上把镜像导出然后导入到需要运行镜像的内网服务器
#### 导出镜像
在有公网资源的服务器上下载好`minio/minio`镜像
```bash
$ docker save -o minio.tar minio/minio:latest
```
> 使用docker save 的时候也可以使用image id 来导出但是那样导出的时候就会丢失原来的镜像名称推荐还是使用镜像名字+tag来导出镜像
#### 导入镜像
把压缩文件复制到内网服务器上使用下面的命令导入镜像
```bash
$ docker load minio.tar
```
#### 运行 minio
- `/mnt/data` 改成要替换的数据目录
- 替换 `MINIO_ROOT_USER` 的值
- 替换 `MINIO_ROOT_PASSWORD` 的值
- 替换 name,minio1(可选)
- 如果 90009090 端口冲突,替换端口前面的如 `9009:9000`
```bash
$ sudo docker run -d -p 9000:9000 -p 9090:9090 --name minio1 \
-e "MINIO_ROOT_USER=改成自己需要的" \
-e "MINIO_ROOT_PASSWORD=改成自己需要的" \
-v /mnt/data:/data \
--restart=always \
minio/minio server /data --console-address ':9090'
```
#### 访问 web 管理页面
http://x.x.x.x:9090

View File

@@ -0,0 +1,44 @@
## [MongoDB](https://hub.docker.com/_/mongo/)
### 基本信息
[MongoDB](https://en.wikipedia.org/wiki/MongoDB) 是开源的 NoSQL 数据库实现。
该仓库位于 `https://hub.docker.com/_/mongo/` 提供了 MongoDB 2.x ~ 4.x 各个版本的镜像
### 使用方法
默认会在 `27017` 端口启动数据库
```bash
$ docker run --name mongo -d mongo
```
使用其他应用连接到容器首先创建网络
```bash
$ docker network create my-mongo-net
```
然后启动 MongoDB 容器
```bash
$ docker run --name some-mongo -d --network my-mongo-net mongo
```
最后启动应用容器
```bash
$ docker run --name some-app -d --network my-mongo-net application-that-uses-mongo
```
或者通过 `mongo`
```bash
$ docker run -it --rm \
--network my-mongo-net \
mongo \
sh -c 'exec mongo "some-mongo:27017/test"'
```
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/mongo 查看。

46
16_appendix/repo/mysql.md Normal file
View File

@@ -0,0 +1,46 @@
## [MySQL](https://hub.docker.com/_/mysql/)
### 基本信息
[MySQL](https://en.wikipedia.org/wiki/MySQL) 是开源的关系数据库实现。
该仓库位于 `https://hub.docker.com/_/mysql/` 提供了 MySQL 5.5 ~ 8.x 各个版本的镜像
### 使用方法
默认会在 `3306` 端口启动数据库
```bash
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql
```
之后就可以使用其它应用来连接到该容器
首先创建网络
```bash
$ docker network create my-mysql-net
```
然后启动 MySQL 容器
```bash
$ docker run --name some-mysql -d --network my-mysql-net -e MYSQL_ROOT_PASSWORD=mysecretpassword mysql
```
最后启动应用容器
```bash
$ docker run --name some-app -d --network my-mysql-net application-that-uses-mysql
```
或者通过 `mysql` 命令行连接
```bash
$ docker run -it --rm \
--network my-mysql-net \
mysql \
sh -c 'exec mysql -hsome-mysql -P3306 -uroot -pmysecretpassword'
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/mysql 查看

49
16_appendix/repo/nginx.md Normal file
View File

@@ -0,0 +1,49 @@
## [Nginx](https://hub.docker.com/_/nginx/)
### 基本信息
[Nginx](https://en.wikipedia.org/wiki/Nginx) 是开源的高效的 Web 服务器实现,支持 HTTP、HTTPS、SMTP、POP3、IMAP 等协议。
该仓库位于 `https://hub.docker.com/_/nginx/` 提供了 Nginx 1.0 ~ 1.19.x 各个版本的镜像
### 使用方法
下面的命令将作为一个静态页面服务器启动
```bash
$ docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx
```
用户也可以不使用这种映射方式通过利用 Dockerfile 来直接将静态页面内容放到镜像中内容为
```docker
FROM nginx
COPY static-html-directory /usr/share/nginx/html
```
之后生成新的镜像并启动一个容器
```bash
$ docker build -t some-content-nginx .
$ docker run --name some-nginx -d some-content-nginx
```
开放端口并映射到本地的 `8080` 端口
```bash
$ docker run --name some-nginx -d -p 8080:80 some-content-nginx
```
Nginx的默认配置文件路径为 `/etc/nginx/nginx.conf`可以通过映射它来使用本地的配置文件例如
```bash
$ docker run -d \
--name some-nginx \
-p 8080:80 \
-v /path/nginx.conf:/etc/nginx/nginx.conf:ro \
nginx
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/nginx 查看。

View File

@@ -0,0 +1,41 @@
## [Node.js](https://hub.docker.com/_/node/)
### 基本信息
[Node.js](https://en.wikipedia.org/wiki/Node.js) 是基于 JavaScript 的可扩展服务端和网络软件开发平台。
该仓库位于 `https://hub.docker.com/_/node/` 提供了 Node.js 0.10 ~ 14.x 各个版本的镜像
### 使用方法
在项目中创建一个 Dockerfile
```docker
FROM node:12
## replace this with your application's default port
EXPOSE 8888
```
然后创建镜像并启动容器
```bash
$ docker build -t my-nodejs-app
$ docker run -it --rm --name my-running-app my-nodejs-app
```
也可以直接运行一个简单容器
```bash
$ docker run -it --rm \
--name my-running-script \
# -v "$(pwd)":/usr/src/myapp \
--mount type=bind,src=`$(pwd)`,target=/usr/src/myapp \
-w /usr/src/myapp \
node:12-alpine \
node your-daemon-or-script.js
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/node 查看。

19
16_appendix/repo/php.md Normal file
View File

@@ -0,0 +1,19 @@
## [PHP](https://hub.docker.com/_/php/)
### 基本信息
[PHP](https://en.wikipedia.org/wiki/Php)Hypertext Preprocessor 超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML 中,尤其适合 web 开发。
该仓库位于 `https://hub.docker.com/_/php/` 提供了 PHP 5.x ~ 8.x 各个版本的镜像
### 使用方法
下面的命令将运行一个已有的 PHP 脚本
```bash
$ docker run -it --rm -v "$PWD":/app -w /app php:alpine php your-script.php
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/php 查看。

51
16_appendix/repo/redis.md Normal file
View File

@@ -0,0 +1,51 @@
## [Redis](https://hub.docker.com/_/redis/)
### 基本信息
[Redis](https://en.wikipedia.org/wiki/Redis) 是开源的内存 Key-Value 数据库实现。
该仓库位于 `https://hub.docker.com/_/redis/` 提供了 Redis 3.x ~ 6.x 各个版本的镜像
### 使用方法
默认会在 `6379` 端口启动数据库
```bash
$ docker run --name some-redis -d -p 6379:6379 redis
```
另外还可以启用 [持久存储](https://redis.io/topics/persistence)。
```bash
$ docker run --name some-redis -d -p 6379:6379 redis redis-server --appendonly yes
```
默认数据存储位置在 `VOLUME/data`可以使用 `--volumes-from some-volume-container` `-v /docker/host/dir:/data` 将数据存放到本地
使用其他应用连接到容器首先创建网络
```bash
$ docker network create my-redis-net
```
然后启动 redis 容器
```bash
$ docker run --name some-redis -d --network my-redis-net redis
```
最后启动应用容器
```bash
$ docker run --name some-app -d --network my-redis-net application-that-uses-redis
```
或者通过 `redis-cli`
```bash
$ docker run -it --rm \
--network my-redis-net \
redis \
sh -c 'exec redis-cli -h some-redis'
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/redis 查看。

View File

@@ -0,0 +1,20 @@
## [Ubuntu](https://hub.docker.com/_/ubuntu/)
### 基本信息
[Ubuntu](https://en.wikipedia.org/wiki/Ubuntu) 是流行的 Linux 发行版,其自带软件版本往往较新一些。
该仓库位于 `https://hub.docker.com/_/ubuntu/` 提供了 Ubuntu 12.04 ~ 20.04 各个版本的镜像
### 使用方法
默认会启动一个最小化的 Ubuntu 环境
```bash
$ docker run --name some-ubuntu -it ubuntu:20.04
root@523c70904d54:/#
```
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/ubuntu 查看。

View File

@@ -0,0 +1,38 @@
## [WordPress](https://hub.docker.com/_/wordpress/)
### 基本信息
[WordPress](https://en.wikipedia.org/wiki/WordPress) 是开源的 Blog 和内容管理系统框架,它基于 PHP 和 MySQL。
该仓库位于 `https://hub.docker.com/_/wordpress/` 提供了 WordPress 4.x ~ 5.x 版本的镜像
### 使用方法
启动容器需要 MySQL 的支持默认端口为 `80`
首先创建网络
```bash
$ docker network create my-wordpress-net
```
启动 MySQL 容器
```bash
$ docker run --name some-mysql -d --network my-wordpress-net -e MYSQL_ROOT_PASSWORD=mysecretpassword mysql
```
启动 WordPress 容器
```bash
$ docker run --name some-wordpress -d --network my-wordpress-net -e WORDPRESS_DB_HOST=some-mysql -e WORDPRESS_DB_PASSWORD=mysecretpassword wordpress
```
启动 WordPress 容器时可以指定的一些环境变量包括
* `WORDPRESS_DB_HOST`: MySQL 服务的主机名
* `WORDPRESS_DB_USER`: MySQL 数据库的用户名
* `WORDPRESS_DB_PASSWORD`: MySQL 数据库的密码
* `WORDPRESS_DB_NAME`: WordPress 要使用的数据库名
### Dockerfile
请到 https://github.com/docker-library/docs/tree/master/wordpress 查看。