mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 16:37:34 +00:00
Compare commits
138
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e86b7bec | ||
|
|
9230b49b6b | ||
|
|
2185211041 | ||
|
|
f09e800020 | ||
|
|
3a9ee19d22 | ||
|
|
ea26f96297 | ||
|
|
30f26d9195 | ||
|
|
fb361bb1f0 | ||
|
|
036f0486db | ||
|
|
28c23d003e | ||
|
|
6a55219310 | ||
|
|
8f4d88e350 | ||
|
|
7f83abc53b | ||
|
|
ec0fa15835 | ||
|
|
8b9e4518c8 | ||
|
|
dae0af9ae7 | ||
|
|
10b09f35eb | ||
|
|
e17bef96d2 | ||
|
|
a3567ff6a0 | ||
|
|
9ef842ebb3 | ||
|
|
2e625a3cdf | ||
|
|
d47afa7e75 | ||
|
|
1b651e5f8c | ||
|
|
e91fe87822 | ||
|
|
bb97d5a46a | ||
|
|
1f69884c8f | ||
|
|
4f92b3aa70 | ||
|
|
58504e9316 | ||
|
|
4075330dba | ||
|
|
e6bf228066 | ||
|
|
1b15b65bc5 | ||
|
|
26da467052 | ||
|
|
7abaff237a | ||
|
|
1c4e0538d8 | ||
|
|
0b8f6e9b60 | ||
|
|
5650315cb4 | ||
|
|
e21794ebde | ||
|
|
78ca8f6d19 | ||
|
|
1ba904a9ff | ||
|
|
705d162f05 | ||
|
|
92be0050fd | ||
|
|
a20d1b19c4 | ||
|
|
9f481e88ca | ||
|
|
ef5a97fa09 | ||
|
|
3c5c5911b0 | ||
|
|
e2742313f2 | ||
|
|
2cea196860 | ||
|
|
13fc8b34f0 | ||
|
|
29742c8f74 | ||
|
|
7cae0b6bb3 | ||
|
|
10381deee4 | ||
|
|
625d209fa8 | ||
|
|
b148d9efa9 | ||
|
|
4cb91a75f3 | ||
|
|
bf3107b775 | ||
|
|
7e3f90b522 | ||
|
|
e6527ae769 | ||
|
|
9c378b1ef9 | ||
|
|
340c8c9e61 | ||
|
|
89c2690a62 | ||
|
|
c554799b08 | ||
|
|
99c56217f5 | ||
|
|
9c98e35c62 | ||
|
|
0e0afbd4d3 | ||
|
|
30f0115cb9 | ||
|
|
62f48c1417 | ||
|
|
fab4e41587 | ||
|
|
229aec2f1e | ||
|
|
8ebf284f9e | ||
|
|
a89f7285c7 | ||
|
|
15c7fe1dc2 | ||
|
|
4d1e323faf | ||
|
|
16203c5018 | ||
|
|
3d3befa16a | ||
|
|
09fd556c18 | ||
|
|
37e376d578 | ||
|
|
04fd53ea3c | ||
|
|
b1cd2f0878 | ||
|
|
e416a1be7e | ||
|
|
e406ed9185 | ||
|
|
c36c420c7e | ||
|
|
72513eb673 | ||
|
|
8ea52620cc | ||
|
|
22dd236122 | ||
|
|
98f4f7b1e5 | ||
|
|
87bb4b2ceb | ||
|
|
dad26ccb28 | ||
|
|
84a801f3ac | ||
|
|
420a5776ce | ||
|
|
b2839f735c | ||
|
|
98e299a38e | ||
|
|
aa204fb454 | ||
|
|
1e9cdeea3f | ||
|
|
515ba9f64a | ||
|
|
9abc1cbb69 | ||
|
|
839a63f5af | ||
|
|
20a3479f8a | ||
|
|
52329fee5a | ||
|
|
8093b198ce | ||
|
|
77a537df54 | ||
|
|
e414d9475b | ||
|
|
037591e5af | ||
|
|
94f74fc86e | ||
|
|
4b44d64cd8 | ||
|
|
49a85c802e | ||
|
|
2a7f7d9a3d | ||
|
|
544ede8498 | ||
|
|
54a9a6e55b | ||
|
|
27617ea619 | ||
|
|
69fc2234d0 | ||
|
|
ac92e6c536 | ||
|
|
1fc64ab875 | ||
|
|
c9c72618c3 | ||
|
|
4b93651989 | ||
|
|
b3d1508310 | ||
|
|
1d780f70c5 | ||
|
|
ff48ac79ee | ||
|
|
077e55f494 | ||
|
|
1bed644e5e | ||
|
|
da5867c921 | ||
|
|
407d508590 | ||
|
|
6fcb74bccc | ||
|
|
d81405a807 | ||
|
|
983e7c18c3 | ||
|
|
9e194b9a74 | ||
|
|
6b2ebd12ac | ||
|
|
f86e3567e8 | ||
|
|
2dacddb999 | ||
|
|
422123dd70 | ||
|
|
adee45f7bc | ||
|
|
04b81a8c05 | ||
|
|
e85ca7a11e | ||
|
|
66905627b8 | ||
|
|
aec453b9bb | ||
|
|
565b40ab0b | ||
|
|
50fe8ebbbb | ||
|
|
c84927c196 | ||
|
|
2b0c00c5e5 |
@@ -16,17 +16,24 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install Chromium and CJK fonts
|
||||
uses: browser-actions/setup-chrome@v2
|
||||
with:
|
||||
chrome-version: stable
|
||||
- name: Install CJK fonts
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y chromium-browser fonts-noto-cjk fonts-noto-cjk-extra
|
||||
sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra
|
||||
|
||||
- name: Install mdpress (latest)
|
||||
- name: Install mdpress 0.7.10
|
||||
env:
|
||||
MDPRESS_VERSION: "0.7.10"
|
||||
MDPRESS_SHA256: "17e53e455996940bbbce64c69c43b3fb543f1501e03b74cf0434074efebd2db4"
|
||||
run: |
|
||||
LATEST_TAG=$(curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ github.token }}" https://api.github.com/repos/yeasy/mdpress/releases/latest | jq -r .tag_name)
|
||||
VERSION="${LATEST_TAG#v}"
|
||||
echo "Installing mdpress $VERSION"
|
||||
curl -fsSL "https://github.com/yeasy/mdPress/releases/download/$LATEST_TAG/mdpress_${VERSION}_linux_amd64.tar.gz" -o /tmp/mdpress.tar.gz
|
||||
tar xzf /tmp/mdpress.tar.gz -C /tmp mdpress
|
||||
archive="/tmp/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz"
|
||||
echo "Installing mdpress ${MDPRESS_VERSION}"
|
||||
curl -fsSL "https://github.com/yeasy/mdPress/releases/download/v${MDPRESS_VERSION}/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz" -o "$archive"
|
||||
echo "${MDPRESS_SHA256} $archive" | sha256sum -c -
|
||||
tar xzf "$archive" -C /tmp mdpress
|
||||
sudo mv /tmp/mdpress /usr/local/bin/
|
||||
mdpress --version
|
||||
|
||||
|
||||
@@ -16,23 +16,32 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Check project rules
|
||||
run: python3 check_project_rules.py
|
||||
- name: Install Chromium and CJK fonts
|
||||
uses: browser-actions/setup-chrome@v2
|
||||
with:
|
||||
chrome-version: stable
|
||||
- name: Install CJK fonts
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y chromium-browser fonts-noto-cjk fonts-noto-cjk-extra
|
||||
- name: Install mdpress (latest)
|
||||
sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra
|
||||
- name: Install mdpress 0.7.10
|
||||
env:
|
||||
MDPRESS_VERSION: "0.7.10"
|
||||
MDPRESS_SHA256: "17e53e455996940bbbce64c69c43b3fb543f1501e03b74cf0434074efebd2db4"
|
||||
run: |
|
||||
LATEST_TAG=$(curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ github.token }}" https://api.github.com/repos/yeasy/mdpress/releases/latest | jq -r .tag_name)
|
||||
VERSION="${LATEST_TAG#v}"
|
||||
echo "Installing mdpress $VERSION"
|
||||
curl -fsSL "https://github.com/yeasy/mdPress/releases/download/$LATEST_TAG/mdpress_${VERSION}_linux_amd64.tar.gz" -o mdpress.tar.gz
|
||||
tar xzf mdpress.tar.gz
|
||||
archive="/tmp/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz"
|
||||
echo "Installing mdpress ${MDPRESS_VERSION}"
|
||||
curl -fsSL "https://github.com/yeasy/mdPress/releases/download/v${MDPRESS_VERSION}/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz" -o "$archive"
|
||||
echo "${MDPRESS_SHA256} $archive" | sha256sum -c -
|
||||
tar xzf "$archive"
|
||||
sudo mv mdpress /usr/local/bin/
|
||||
mdpress --version
|
||||
- name: Build site
|
||||
run: mdpress build --format site
|
||||
- name: Build PDF
|
||||
run: mdpress build --format pdf --output docker_practice.pdf
|
||||
- name: Build site
|
||||
run: npm run build
|
||||
- name: Upload PDF as artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
|
||||
@@ -4,6 +4,7 @@ on: pull_request
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
checks: read
|
||||
|
||||
jobs:
|
||||
dependabot:
|
||||
@@ -12,15 +13,36 @@ jobs:
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v3
|
||||
uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: Approve a PR
|
||||
|
||||
- name: Confirm required checks are configured
|
||||
if: >
|
||||
steps.metadata.outputs.package-ecosystem == 'github_actions' &&
|
||||
contains(fromJSON('["version-update:semver-patch","version-update:semver-minor"]'), steps.metadata.outputs.update-type)
|
||||
run: |
|
||||
REQUIRED=$(gh api "repos/${GITHUB_REPOSITORY}/branches/${{ github.event.pull_request.base.ref }}/protection/required_status_checks" --jq '((.contexts // []) | length) + ((.checks // []) | length)' 2>/dev/null || echo 0)
|
||||
if [ "$REQUIRED" -eq 0 ]; then
|
||||
echo "No required status checks configured on the base branch; refusing Dependabot auto-merge."
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Approve low-risk Dependabot PR
|
||||
if: >
|
||||
steps.metadata.outputs.package-ecosystem == 'github_actions' &&
|
||||
contains(fromJSON('["version-update:semver-patch","version-update:semver-minor"]'), steps.metadata.outputs.update-type)
|
||||
run: gh pr review --approve "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
- name: Enable auto-merge for Dependabot PRs
|
||||
|
||||
- name: Enable auto-merge for low-risk Dependabot PRs
|
||||
if: >
|
||||
steps.metadata.outputs.package-ecosystem == 'github_actions' &&
|
||||
contains(fromJSON('["version-update:semver-patch","version-update:semver-minor"]'), steps.metadata.outputs.update-type)
|
||||
run: gh pr merge --auto --merge "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
|
||||
@@ -23,17 +23,24 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install Chromium and CJK fonts
|
||||
uses: browser-actions/setup-chrome@v2
|
||||
with:
|
||||
chrome-version: stable
|
||||
- name: Install CJK fonts
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y chromium-browser fonts-noto-cjk fonts-noto-cjk-extra
|
||||
sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra
|
||||
|
||||
- name: Install mdpress (latest)
|
||||
- name: Install mdpress 0.7.10
|
||||
env:
|
||||
MDPRESS_VERSION: "0.7.10"
|
||||
MDPRESS_SHA256: "17e53e455996940bbbce64c69c43b3fb543f1501e03b74cf0434074efebd2db4"
|
||||
run: |
|
||||
LATEST_TAG=$(curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ github.token }}" https://api.github.com/repos/yeasy/mdpress/releases/latest | jq -r .tag_name)
|
||||
VERSION="${LATEST_TAG#v}"
|
||||
echo "Installing mdpress $VERSION"
|
||||
curl -fsSL "https://github.com/yeasy/mdPress/releases/download/$LATEST_TAG/mdpress_${VERSION}_linux_amd64.tar.gz" -o /tmp/mdpress.tar.gz
|
||||
tar xzf /tmp/mdpress.tar.gz -C /tmp mdpress
|
||||
archive="/tmp/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz"
|
||||
echo "Installing mdpress ${MDPRESS_VERSION}"
|
||||
curl -fsSL "https://github.com/yeasy/mdPress/releases/download/v${MDPRESS_VERSION}/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz" -o "$archive"
|
||||
echo "${MDPRESS_SHA256} $archive" | sha256sum -c -
|
||||
tar xzf "$archive" -C /tmp mdpress
|
||||
sudo mv /tmp/mdpress /usr/local/bin/
|
||||
mdpress --version
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ node_modules/
|
||||
package-lock.json
|
||||
|
||||
docker-compose.override.yml
|
||||
06_repository/demo/auth/nginx.htpasswd
|
||||
|
||||
# Editor configs
|
||||
.obsidian/
|
||||
@@ -26,6 +27,7 @@ Docker -- *_site/
|
||||
|
||||
# Check scripts
|
||||
check*.py
|
||||
!check_project_rules.py
|
||||
find*.py
|
||||
fix*.py
|
||||
format*.py
|
||||
|
||||
@@ -172,7 +172,7 @@ registry.example.com/myproject/myapp:v1.2.3
|
||||
|
||||
## 简写(使用 Docker Hub)
|
||||
|
||||
nginx:1.25
|
||||
nginx:1.28
|
||||
ubuntu:24.04
|
||||
|
||||
## 省略标签(默认使用 latest)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 2.3 仓库
|
||||
|
||||
> **版本说明**:本节示例基于 Docker v29.x 和常见镜像版本编写。示例中的版本号(如 `nginx:1.25`、`mysql:8.0`、`mysql:5.7` 等)为演示用途。实际使用时请访问 [Docker Hub 官方页面](https://hub.docker.com) 或相应镜像的发布页确认最新可用版本和标签。
|
||||
> **版本说明**:本节示例基于 Docker v29.x 和常见镜像版本编写。示例中的版本号(如 `nginx:1.28`、`mysql:8.4`、`mysql:5.7` 等)为演示用途。实际使用时请访问 [Docker Hub 官方页面](https://hub.docker.com) 或相应镜像的发布页确认最新可用版本和标签。
|
||||
|
||||
Docker Registry 是镜像分发和管理的核心组件。本节将介绍 Registry 的基本概念、公共和私有服务的选择,以及镜像的安全管理。
|
||||
|
||||
@@ -25,8 +25,8 @@ flowchart TB
|
||||
subgraph RepoNginx ["Repository(仓库): nginx"]
|
||||
direction LR
|
||||
N1(":latest (tag)")
|
||||
N2(":1.25 (tag)")
|
||||
N3(":1.24 (tag)")
|
||||
N2(":1.28 (tag)")
|
||||
N3(":1.26 (tag)")
|
||||
N4(":alpine (tag)")
|
||||
N5("...")
|
||||
N1 ~~~ N2 ~~~ N3 ~~~ N4 ~~~ N5
|
||||
@@ -50,7 +50,7 @@ flowchart TB
|
||||
|------|------|------|
|
||||
| **Registry** | 存储镜像的服务 | Docker Hub、ghcr.io |
|
||||
| **Repository (仓库)** | 同一软件的镜像集合 | `nginx`、`mysql`、`mycompany/myapp` |
|
||||
| **Tag (标签)** | 仓库内的版本标识 | `latest`、`1.25`、`alpine` |
|
||||
| **Tag (标签)** | 仓库内的版本标识 | `latest`、`1.28`、`alpine` |
|
||||
|
||||
#### 镜像的完整名称
|
||||
|
||||
@@ -73,7 +73,7 @@ registry.example.com/mycompany/myapp:v1.2.3
|
||||
|
||||
## Docker Hub 官方镜像(省略 registry 和用户名)
|
||||
|
||||
nginx:1.25
|
||||
nginx:1.28
|
||||
ubuntu:24.04
|
||||
|
||||
## Docker Hub 用户镜像
|
||||
@@ -131,7 +131,7 @@ Google 的 Container Registry 已废弃并完成下线,当前应优先使用 A
|
||||
|
||||
由于网络原因,在国内直接访问 Docker Hub 可能会很慢。可以配置 **镜像加速器** (Registry Mirror) 来加速下载。配置示例如下:
|
||||
|
||||
```json
|
||||
```jsonc
|
||||
// /etc/docker/daemon.json
|
||||
{
|
||||
"registry-mirrors": [
|
||||
@@ -217,7 +217,7 @@ $ docker login registry.example.com # 登录其他 Registry
|
||||
|
||||
## 拉取镜像
|
||||
|
||||
$ docker pull nginx:1.25
|
||||
$ docker pull nginx:1.28
|
||||
|
||||
## 标记镜像(准备推送)
|
||||
|
||||
@@ -255,15 +255,15 @@ someuser/myapp # ⚠️ 需要评估
|
||||
|
||||
#### 镜像签名
|
||||
|
||||
当前更推荐使用 Sigstore / Notation 体系进行镜像签名与验证。`Docker Content Trust (DCT)` 已于 2025 年 8 月 8 日开始停用,官方 Docker 镜像已停止 DCT 签名,2028 年 3 月 31 日将完全删除此功能,不建议作为新项目方案。
|
||||
当前更推荐使用 Sigstore / Notation 体系进行镜像签名与验证。`Docker Content Trust (DCT)` 已进入弃用阶段:2025 年 8 月 8 日起最早的 DCT 签名证书开始过期,2025 年 9 月 30 日起不能在新 Registry 启用 DCT,2028 年 3 月 31 日将完全删除此功能。不建议作为新项目方案。
|
||||
|
||||
> 注意:Cosign 默认会把签名推送回镜像所在仓库,请使用你有推送权限的镜像地址。
|
||||
|
||||
```bash
|
||||
## 准备一个你有写权限的镜像地址
|
||||
$ export IMAGE=<你的仓库名>/nginx:1.27
|
||||
$ docker pull nginx:1.27
|
||||
$ docker tag nginx:1.27 $IMAGE
|
||||
$ export IMAGE=<你的仓库名>/nginx:1.28
|
||||
$ docker pull nginx:1.28
|
||||
$ docker tag nginx:1.28 $IMAGE
|
||||
$ docker push $IMAGE
|
||||
|
||||
## 生成签名密钥(会生成 cosign.key / cosign.pub)
|
||||
|
||||
@@ -91,7 +91,7 @@ $ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin do
|
||||
在真正执行前,建议先用 `--dry-run` 预览脚本动作:
|
||||
|
||||
```bash
|
||||
$ curl -fsSL get.docker.com -o get-docker.sh
|
||||
$ curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
$ sudo sh ./get-docker.sh --dry-run
|
||||
|
||||
# 若需要测试频道:
|
||||
|
||||
@@ -81,7 +81,7 @@ $ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin do
|
||||
在真正执行前,建议先用 `--dry-run` 预览脚本动作:
|
||||
|
||||
```bash
|
||||
$ curl -fsSL get.docker.com -o get-docker.sh
|
||||
$ curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
$ sudo sh ./get-docker.sh --dry-run
|
||||
|
||||
# 若需要测试频道:
|
||||
|
||||
@@ -39,7 +39,7 @@ $ sudo dnf remove docker \
|
||||
|
||||
### 3.3.2 使用 dnf 安装
|
||||
|
||||
使用 dnf 包管理器安装是推荐的方式,便于后续的更行和管理。
|
||||
使用 dnf 包管理器安装是推荐的方式,便于后续的更新和管理。
|
||||
|
||||
执行以下命令安装依赖包:
|
||||
|
||||
@@ -91,7 +91,7 @@ $ sudo dnf -y install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING>
|
||||
在真正执行前,建议先用 `--dry-run` 预览脚本动作:
|
||||
|
||||
```bash
|
||||
$ curl -fsSL get.docker.com -o get-docker.sh
|
||||
$ curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
$ sudo sh ./get-docker.sh --dry-run
|
||||
|
||||
# 若需要测试频道:
|
||||
|
||||
@@ -88,7 +88,7 @@ Docker 官方提醒:如果主机使用 `ufw` 或 `firewalld` 管理防火墙
|
||||
在真正执行前,建议先用 `--dry-run` 预览脚本动作:
|
||||
|
||||
```bash
|
||||
$ curl -fsSL get.docker.com -o get-docker.sh
|
||||
$ curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
$ sudo sh ./get-docker.sh --dry-run
|
||||
|
||||
# 若需要测试频道:
|
||||
|
||||
@@ -114,7 +114,7 @@ $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugi
|
||||
在真正执行前,建议先用 `--dry-run` 预览脚本动作:
|
||||
|
||||
```bash
|
||||
$ curl -fsSL get.docker.com -o get-docker.sh
|
||||
$ curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
$ sudo sh ./get-docker.sh --dry-run
|
||||
|
||||
# 若需要测试频道:
|
||||
|
||||
@@ -90,9 +90,11 @@ $ sudo dnf versionlock clear
|
||||
##### 挂载 ISO 镜像搭建本地 File 源
|
||||
|
||||
```bash
|
||||
## 删除其他网络源
|
||||
## 备份其他网络源
|
||||
|
||||
$ sudo rm -f /etc/yum.repos.d/*
|
||||
$ repo_backup="/etc/yum.repos.d/backup-$(date +%Y%m%d%H%M%S)"
|
||||
$ sudo mkdir -p "$repo_backup"
|
||||
$ sudo find /etc/yum.repos.d -maxdepth 1 -type f -name '*.repo' -exec mv {} "$repo_backup"/ \;
|
||||
|
||||
## 挂载光盘或者iso镜像
|
||||
|
||||
@@ -106,7 +108,7 @@ $ sudo tee /etc/yum.repos.d/local-base.repo <<EOF
|
||||
name=local_base
|
||||
baseurl=file:///mnt
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
gpgcheck=1
|
||||
EOF
|
||||
```
|
||||
```bash
|
||||
@@ -156,7 +158,9 @@ $ sudo createrepo_c /var/www/html/docker-ce/
|
||||
##### DNF 客户端设置
|
||||
|
||||
```bash
|
||||
$ sudo rm -f /etc/yum.repos.d/*
|
||||
$ repo_backup="/etc/yum.repos.d/backup-$(date +%Y%m%d%H%M%S)"
|
||||
$ sudo mkdir -p "$repo_backup"
|
||||
$ sudo find /etc/yum.repos.d -maxdepth 1 -type f -name '*.repo' -exec mv {} "$repo_backup"/ \;
|
||||
$ sudo tee /etc/yum.repos.d/local-files.repo <<EOF
|
||||
[local_base]
|
||||
name=local_base
|
||||
@@ -165,7 +169,7 @@ name=local_base
|
||||
|
||||
baseurl=http://x.x.x.x/base
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
gpgcheck=1
|
||||
proxy=_none_
|
||||
[docker-ce-stable]
|
||||
name=docker-ce-stable
|
||||
@@ -174,7 +178,7 @@ name=docker-ce-stable
|
||||
|
||||
baseurl=http://x.x.x.x/docker-ce
|
||||
enabled=1
|
||||
gpgcheck=0
|
||||
gpgcheck=1
|
||||
proxy=_none_
|
||||
EOF
|
||||
|
||||
|
||||
+20
-1
@@ -72,6 +72,25 @@ $ docker stop webserver
|
||||
$ docker rm webserver
|
||||
```
|
||||
|
||||
### 3.7.4 镜像加速
|
||||
### 3.7.4 替代容器运行时
|
||||
|
||||
Docker Desktop 并非 macOS 上运行容器的唯一选择。以下两个工具也广泛使用,各有侧重:
|
||||
|
||||
| 特性 | Docker Desktop | OrbStack | Colima |
|
||||
|------|---------------|-----------|--------|
|
||||
| 启动速度 | 较慢(约 10–30 秒) | 极快(约 2 秒) | 中等(约 5–10 秒) |
|
||||
| 空闲内存占用 | 4–6 GB | 200–300 MB | 约 400 MB |
|
||||
| 图形界面 | 完整 GUI | 轻量 GUI | 仅命令行 |
|
||||
| Apple Silicon | 支持 | 原生优化 | 支持 |
|
||||
| 商业许可 | 大型企业需付费 | 个人免费,商业付费 | MIT 开源 |
|
||||
| Kubernetes | 内置 | 内置 | 通过 k3s 支持 |
|
||||
|
||||
**[OrbStack](https://orbstack.dev/)**:以极低的资源占用和接近原生的 I/O 性能著称。对于 Apple Silicon 机型上需要频繁构建镜像的开发者,体验提升尤为明显。个人和教育用途免费。
|
||||
|
||||
**[Colima](https://github.com/abiosoft/colima)**:完全开源的命令行方案,底层基于 Lima 虚拟机。适合偏好终端工作流、不需要 GUI 的开发者,或企业中希望避免商业许可限制的团队。
|
||||
|
||||
> 上述三种工具均兼容标准的 `docker` CLI 命令。从 Docker Desktop 切换到 OrbStack 或 Colima 时,已有的镜像和容器配置通常可以平滑迁移。
|
||||
|
||||
### 3.7.5 镜像加速
|
||||
|
||||
如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
> **版本号最佳实践**
|
||||
>
|
||||
> - **永远指定版本号**:避免使用 `latest` 标签,应指定具体的版本(如 `ubuntu:24.04`、`nginx:1.27`),以确保镜像内容稳定一致。
|
||||
> - **永远指定版本号**:避免使用 `latest` 标签,应指定具体的版本(如 `ubuntu:24.04`、`nginx:1.28`),以确保镜像内容稳定一致。
|
||||
> - **在生产环境使用摘要**:优先使用镜像摘要(SHA256)而非标签,如 `nginx@sha256:abc123...`,因为摘要不可变。
|
||||
> - **定期评估依赖**:即使指定了版本号,仍应定期检查依赖的基础镜像是否有安全更新。
|
||||
|
||||
@@ -160,7 +160,7 @@ root@e7009c6ce357:/# exit
|
||||
|
||||
从 Docker Hub 下载可能较慢。可以配置镜像加速器:
|
||||
|
||||
```json
|
||||
```jsonc
|
||||
// /etc/docker/daemon.json (Linux)
|
||||
// ~/.docker/daemon.json (Docker Desktop)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
现在让我们以定制一个 Web 服务器为例子,来讲解镜像是如何构建的。
|
||||
|
||||
> **版本提示**:以下示例中 `nginx` 镜像使用默认 `latest` 标签。生产环境建议指定具体版本号(如 `nginx:1.27`),以避免镜像更新带来的不兼容性。
|
||||
> **版本提示**:以下示例中 `nginx` 镜像使用默认 `latest` 标签。生产环境建议指定具体版本号(如 `nginx:1.28`),以避免镜像更新带来的不兼容性。
|
||||
|
||||
```bash
|
||||
$ docker run --name webserver -d -p 8080:80 nginx
|
||||
@@ -89,11 +89,11 @@ sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214
|
||||
$ docker image ls nginx
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
nginx v2 07e334659748 9 seconds ago 181.5 MB
|
||||
nginx 1.27 05a60462f8ba 12 days ago 181.5 MB
|
||||
nginx 1.30 05a60462f8ba 12 days ago 181.5 MB
|
||||
nginx latest e43d811ce2f4 4 weeks ago 181.5 MB
|
||||
```
|
||||
|
||||
> **版本说明**:上面示例中 `nginx:1.27` 代表 1.27 系列的最新 patch 版本。在实际应用中应根据需求选择确切的版本号,而不是盲目使用 `latest`。
|
||||
> **版本说明**:上面示例中 `nginx:1.30` 代表 1.30 系列的最新 patch 版本。在实际应用中应根据需求选择确切的版本号,而不是盲目使用 `latest`。
|
||||
|
||||
我们还可以用 `docker history` 具体查看镜像内的历史记录。例如先执行 `docker history nginx:v2`,再对比 `docker history nginx:latest`,就能看到我们刚刚提交出来的新层。
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ $ touch Dockerfile
|
||||
```
|
||||
其内容为:
|
||||
|
||||
> **版本提示**:下面示例中 `FROM nginx` 使用的是 `latest` 标签。在实际应用中应使用明确的版本号(如 `FROM nginx:1.27`),以确保 Dockerfile 的可重现性和稳定性。
|
||||
> **版本提示**:下面示例中 `FROM nginx` 使用的是 `latest` 标签。在实际应用中应使用明确的版本号(如 `FROM nginx:1.28`),以确保 Dockerfile 的可重现性和稳定性。
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
@@ -40,7 +40,7 @@ RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
|
||||
|
||||
> **版本号最佳实践**:在 `FROM` 指令中 **务必指定具体版本号**(如 `FROM ubuntu:24.04` 或 `FROM python:3.12-slim`)而非 `FROM ubuntu` 或 `FROM python:latest`。这样可以确保 Dockerfile 在不同时间、不同环境下构建出的镜像内容一致,避免因基础镜像更新导致的不可预期的变化。
|
||||
|
||||
在 [Docker Hub](https://hub.docker.com/search?q=&type=image&image_filter=official) 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 [`nginx`](https://hub.docker.com/_/nginx/)、[`redis`](https://hub.docker.com/_/redis/)、[`mongo`](https://hub.docker.com/_/mongo/)、[`mysql`](https://hub.docker.com/_/mysql/)、[`httpd`](https://hub.docker.com/_/httpd/)、[`php`](https://hub.docker.com/_/php/)、[`tomcat`](https://hub.docker.com/_/tomcat/) 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 [`node`](https://hub.docker.com/_/node)、[`openjdk`](https://hub.docker.com/_/openjdk/)、[`python`](https://hub.docker.com/_/python/)、[`ruby`](https://hub.docker.com/_/ruby/)、[`golang`](https://hub.docker.com/_/golang/) 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。
|
||||
在 [Docker Hub](https://hub.docker.com/search?q=&type=image&image_filter=official) 上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 [`nginx`](https://hub.docker.com/_/nginx/)、[`redis`](https://hub.docker.com/_/redis/)、[`mongo`](https://hub.docker.com/_/mongo/)、[`mysql`](https://hub.docker.com/_/mysql/)、[`httpd`](https://hub.docker.com/_/httpd/)、[`php`](https://hub.docker.com/_/php/)、[`tomcat`](https://hub.docker.com/_/tomcat/) 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 [`node`](https://hub.docker.com/_/node)、[`eclipse-temurin`](https://hub.docker.com/_/eclipse-temurin/)、[`python`](https://hub.docker.com/_/python/)、[`ruby`](https://hub.docker.com/_/ruby/)、[`golang`](https://hub.docker.com/_/golang/) 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。
|
||||
|
||||
如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,如 [`ubuntu`](https://hub.docker.com/_/ubuntu/)、[`debian`](https://hub.docker.com/_/debian/)、[`centos`](https://hub.docker.com/_/centos/)、[`fedora`](https://hub.docker.com/_/fedora/)、[`alpine`](https://hub.docker.com/_/alpine/) 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。
|
||||
|
||||
@@ -98,7 +98,7 @@ Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
|
||||
Removing intermediate container 9cdc27646c7b
|
||||
Successfully built 44aa4490ce2c
|
||||
```
|
||||
从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 `Step 2` 中,如同我们之前所说的那样,`RUN` 指令启动了一个容器 `9cdc27646c7b`,执行了所要求的命令,并最后提交了这一层 `44aa4490ce2c`,随后删除了所用到的这个容器 `9cdc27646c7b`。
|
||||
从命令的输出结果中,我们可以清晰地看到镜像的构建过程。在 `Step 2` 中,如同我们之前所说的那样,`RUN` 指令启动了一个容器 `9cdc27646c7b`,执行了所要求的命令,并最后提交了这一层 `44aa4490ce2c`,随后删除了所用到的这个容器 `9cdc27646c7b`。
|
||||
|
||||
这里我们使用了 `docker build` 命令进行镜像构建。其格式为:
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
比如我们想要创建一个 [OpenVZ](https://openvz.org) 的 Ubuntu 16.04 [模板](https://wiki.openvz.org/Download/template/precreated)的镜像:
|
||||
|
||||
> **版本提示**:示例中的 Ubuntu 16.04 (Xenial) 已于 2021 年 4 月停止支持。如果用于生产环境,建议更新至 Ubuntu 22.04 LTS 或更新版本。
|
||||
> **版本提示**:`noble` 对应 Ubuntu 24.04 LTS。实际用于生产环境时,应选择仍在安全维护期内的发行版,并按团队的基础镜像更新策略定期重建。
|
||||
|
||||
```bash
|
||||
$ docker import \
|
||||
|
||||
@@ -60,7 +60,7 @@ Docker 镜像的每一层都有一个唯一的 ID,这个 ID 是根据该层的
|
||||
|
||||
Docker 使用联合文件系统 (Union FS) 与写时复制思路来实现这种分层挂载。传统的实现方式常见于 `overlay2`、`aufs`、`btrfs`、`zfs` 等存储驱动;而在 Docker Engine 29.0 及之后的全新安装中,默认镜像后端已经变为 containerd image store,它使用 snapshotter 来管理这些层。
|
||||
|
||||
> **版本背景**:Docker Engine 29.0(发布于 2024 年 2 月)是一个重要版本分界点,引入了 containerd image store 作为默认镜像存储后端。这对镜像管理、OCI 合规性和供应链安全都有深远影响。如果你的 Docker 版本低于 29.0,镜像存储仍使用传统的 classic store 路径。
|
||||
> **版本背景**:Docker Engine 29.0.0 发布于 2025 年 11 月 10 日,是一个重要版本分界点。Docker Engine 29.0 及之后的全新安装默认使用 containerd image store;从更早版本升级的 daemon 会继续使用 legacy graph driver,直到显式启用 containerd image store。Docker Desktop 4.34 及之后也默认启用 containerd image store,实际环境仍应以当前配置为准。
|
||||
|
||||
虽然底层实现细节不同,但它们都遵循上述的 **分层 + CoW** 模型;因此,无论你看到的是 `overlay2` 还是 containerd snapshotter,理解镜像层、容器层和写时复制的方式都是一样重要的。
|
||||
|
||||
|
||||
@@ -126,14 +126,14 @@ $ docker run -d -p 80:80 nginx:latest
|
||||
|
||||
## 数据库
|
||||
|
||||
$ docker run -d -p 3306:3306 mysql:8.0
|
||||
$ docker run -d -p 3306:3306 mysql:8.4
|
||||
|
||||
## 缓存服务
|
||||
|
||||
$ docker run -d -p 6379:6379 redis:latest
|
||||
```
|
||||
|
||||
> **版本说明**:示例使用常见的标签如 `latest` 或稳定大版本号如 `mysql:8.0`。具体版本可根据需求调整,生产环境建议明确指定版本号(如 `mysql:8.0.35`)而非使用 `latest`。
|
||||
> **版本说明**:示例使用常见的标签如 `latest` 或稳定大版本号如 `mysql:8.4`。具体版本可根据需求调整,生产环境建议明确指定版本号(如 `mysql:8.4.4`)而非使用 `latest`。
|
||||
|
||||
#### 2. 调试时先用前台模式
|
||||
|
||||
@@ -196,9 +196,9 @@ $ docker logs -t myapp
|
||||
|
||||
3. **以交互模式调试**:
|
||||
```bash
|
||||
# /bin/sh 覆盖镜像原本的启动命令,避免容器再次崩溃退出
|
||||
# 进入 shell 后可手动执行原启动命令,定位具体报错原因
|
||||
$ docker run -it myimage:v1.0.0 /bin/sh
|
||||
# 进入容器手动执行命令,查找问题
|
||||
|
||||
```
|
||||
|
||||
#### Q:容器在后台运行但无法访问服务
|
||||
|
||||
@@ -212,7 +212,7 @@ FROM node:22-alpine
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
> **版本说明**:示例使用 `node:22-alpine`,这是一个精简的 Node.js 22 版本镜像。可根据需求替换为其他版本(如 `node:20-alpine`、`node:latest`)。
|
||||
> **版本说明**:示例使用 `node:22-alpine`,这是一个精简的 Node.js 22 版本镜像。可根据需求替换为其他版本(如 `node:24-alpine`、`node:latest`)。
|
||||
|
||||
#### Q:容器无法停止
|
||||
|
||||
|
||||
@@ -249,10 +249,11 @@ $ docker exec myapp python manage.py migrate
|
||||
$ docker exec -it myapp bash
|
||||
OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found
|
||||
|
||||
## 解决方案:使用调试容器
|
||||
## 解决方案:使用调试容器(需要 Docker Desktop Pro/Team/Business 订阅)
|
||||
|
||||
$ docker debug myapp
|
||||
```
|
||||
> **注意**:`docker debug` 是 Docker Desktop 4.33+ 提供的功能,需要 Pro、Team 或 Business 订阅。它会附加一个包含常用调试工具(vim、curl、htop 等)的工具箱到目标容器,即使目标镜像基于 `scratch` 也能使用。
|
||||
---
|
||||
|
||||
### 5.4.7 常见问题
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
|
||||
本章示例涉及多个 Docker 镜像,遵循以下版本号最佳实践:
|
||||
|
||||
- **官方镜像**(如 `ubuntu`、`nginx`、`mysql`):使用具体大版本号(如 `ubuntu:24.04`、`mysql:8.0`)而非 `latest`,确保示例的可重复性
|
||||
- **官方镜像**(如 `ubuntu`、`nginx`、`mysql`):使用具体大版本号(如 `ubuntu:24.04`、`mysql:8.4`)而非 `latest`,确保示例的可重复性
|
||||
- **镜像标签约定**:
|
||||
- `latest` 或 `v1.0.0` 等:带标签的自定义镜像,示例中指定具体版本
|
||||
- `24.04`、`8.0`:官方镜像的稳定版本分支
|
||||
- 生产环境建议:指定精确版本号(如 `nginx:1.24.0`、`mysql:8.0.35`)而非仅大版本号
|
||||
- `24.04`、`8.4`:官方镜像的稳定版本分支
|
||||
- 生产环境建议:指定确切版本号(如 `nginx:1.28.0`、`mysql:8.4.4`)而非仅大版本号
|
||||
|
||||
* [启动容器](5.1_run.md)
|
||||
* [守护态运行](5.2_daemon.md)
|
||||
|
||||
@@ -67,15 +67,15 @@ $ docker push username/myapp:v1
|
||||
|
||||
#### 镜像拉取限制
|
||||
|
||||
Docker Hub 对不同类型用户实施拉取速率限制(2025 年 4 月起更新):
|
||||
Docker Hub 对不同类型用户实施拉取速率限制(基于 6 小时周期):
|
||||
|
||||
| 用户类型 | 限制 |
|
||||
|---------|------|
|
||||
| **匿名用户** (未登录) | 每小时 10 次请求 |
|
||||
| **免费账户** (已登录) | 每小时 100 次请求 |
|
||||
| **匿名用户** (未登录) | 每 6 小时 100 次请求 |
|
||||
| **免费账户** (已登录) | 每 6 小时 200 次请求 |
|
||||
| **Pro/Team/Business 账户** | 无限制(公平使用政策) |
|
||||
|
||||
> **注意**:2025 年 4 月前的旧限制为匿名用户每 6 小时 100 次、免费账户每 6 小时 200 次。新政策大幅收紧了匿名拉取额度,建议在 CI/CD 环境中始终配置 `docker login`。
|
||||
> **注意**:Docker 曾计划于 2025 年 4 月调整拉取限制策略,但在 2025 年 2 月宣布取消该计划。目前付费订阅用户享有无限制拉取额度,匿名用户和免费账户的限制保持不变。建议在 CI/CD 环境中始终配置 `docker login` 以获得更高的拉取额度。
|
||||
|
||||
#### 滥用限流
|
||||
|
||||
@@ -107,10 +107,11 @@ Docker Hub 对不同类型用户实施拉取速率限制(2025 年 4 月起更
|
||||
> **⚠️ 警告**:绝不要在脚本或 CI/CD 系统中,直接使用 `-p` 参数传递密码或 Token (类似 `docker login -p xxx`)!这会导致凭证直接暴露在系统的命令历史、进程列表和终端输出中。
|
||||
|
||||
1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token (PAT)。
|
||||
2. 将 Token 通过标准输入 (stdin) 安全传递给 Docker:
|
||||
2. 将 Token 保存在权限受限的本地文件或 CI secret 中,再通过标准输入 (stdin) 传递给 Docker,避免把真实 Token 写进脚本、命令历史或日志:
|
||||
|
||||
```bash
|
||||
$ echo "dckr_pat_xxxxxxx" | docker login --username username --password-stdin
|
||||
$ chmod 600 "$HOME/.dockerhub-token"
|
||||
$ cat "$HOME/.dockerhub-token" | docker login --username username --password-stdin
|
||||
```
|
||||
|
||||
#### 3. 关注镜像漏洞
|
||||
|
||||
@@ -70,10 +70,14 @@ $ openssl x509 -req -days 750 -in "site.csr" -sha256 \
|
||||
-CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
|
||||
-out "docker.domain.com.crt" -extfile "site.cnf" -extensions server
|
||||
```
|
||||
|
||||
配套 demo 中的 [`ssl/README.md`](demo/ssl/README.md) 只保留本地生成证书的占位说明,真实私钥和证书不应提交到仓库。
|
||||
这样已经拥有了 `docker.domain.com` 的网站 SSL 私钥 `docker.domain.com.key` 和 SSL 证书 `docker.domain.com.crt` 及 CA 根证书 `root-ca.crt`。
|
||||
|
||||
新建 `ssl` 文件夹并将 `docker.domain.com.key` `docker.domain.com.crt` `root-ca.crt` 这三个文件移入,删除其他文件。
|
||||
|
||||
> **安全提示**:这些私钥和证书应在本地或受控部署环境中生成,不要提交进 Git 仓库。示例目录只保留占位说明,运行前请按上面的步骤重新生成。
|
||||
|
||||
### 6.3.2 配置私有仓库
|
||||
|
||||
私有仓库默认的配置文件位于 `/etc/docker/registry/config.yml`,我们先在本地编辑 `config.yml`,之后挂载到容器中。
|
||||
@@ -99,7 +103,7 @@ auth:
|
||||
realm: basic-realm
|
||||
path: /etc/docker/registry/auth/nginx.htpasswd
|
||||
http:
|
||||
addr: :443
|
||||
addr: :5000
|
||||
host: https://docker.domain.com
|
||||
headers:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
@@ -126,6 +130,9 @@ $ docker run --rm \
|
||||
-Bbn username password > auth/nginx.htpasswd
|
||||
```
|
||||
> 将上面的 `username` `password` 替换为你自己的用户名和密码。
|
||||
>
|
||||
> **安全提示**:上述命令会将密码明文暴露在 shell 历史记录和进程列表中。生产环境建议使用交互式方式输入密码(不带 `-b` 参数),或通过环境变量/文件传入。
|
||||
> 配套 demo 的 [`auth/README.md`](demo/auth/README.md) 仅说明本地生成步骤,生成的 `auth/nginx.htpasswd` 已被忽略,不应提交。
|
||||
|
||||
> **版本说明**:使用 `httpd:2.4-alpine` 基于 Apache 2.4 的精简镜像。如需其他版本,可替换为 `httpd:latest` 或指定具体版本号如 `httpd:2.4.58-alpine`。
|
||||
|
||||
@@ -138,7 +145,7 @@ services:
|
||||
registry:
|
||||
image: registry:2
|
||||
ports:
|
||||
- "443:443"
|
||||
- "443:5000"
|
||||
volumes:
|
||||
- ./:/etc/docker/registry
|
||||
- registry-data:/var/lib/registry
|
||||
@@ -147,6 +154,8 @@ volumes:
|
||||
registry-data:
|
||||
```
|
||||
|
||||
本书配套的 `06_repository/demo/` 也采用同样约定:容器内 registry 监听 `:5000`,宿主机通过 `443:5000` 暴露 HTTPS 服务。这样可以避免在容器内占用特权端口,同时仍让客户端使用 `https://docker.domain.com` 访问。
|
||||
|
||||
> **版本说明**:Compose 配置中明确指定 `registry:2` 版本。生产环境建议固定版本号(如 `registry:2.8.3`)而非使用 `latest`,以保证部署的可重复性。
|
||||
|
||||
### 6.3.5 修改 Hosts 文件
|
||||
|
||||
@@ -80,7 +80,7 @@ server {
|
||||
ssl_certificate_key key/example.key;
|
||||
|
||||
ssl_session_timeout 5m;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Generated Authentication File
|
||||
|
||||
Run the `htpasswd` command in section 6.3.3 to generate `nginx.htpasswd` locally before starting the demo registry.
|
||||
|
||||
Do not commit generated password hashes.
|
||||
@@ -1,2 +0,0 @@
|
||||
username:$2y$05$TRWvCC6ilpKpY3ICifw32Ok3.8SpG3etq8O5WGdCm9wvyDhtSbRgy
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!README.md
|
||||
@@ -0,0 +1,5 @@
|
||||
# Generated TLS Files
|
||||
|
||||
Run the certificate steps in section 6.3.1 to generate `docker.domain.com.key`, `docker.domain.com.crt`, and `root-ca.crt` locally before starting the demo registry.
|
||||
|
||||
Do not commit generated private keys or certificates.
|
||||
@@ -1,35 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF/zCCA+egAwIBAgIJAMbgVbFo7I6IMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
|
||||
BAYTAkNOMQ8wDQYDVQQIDAZTaGFueGkxDzANBgNVBAcMBkRhdG9uZzEaMBgGA1UE
|
||||
CgwRWW91ciBDb21wYW55IE5hbWUxLTArBgNVBAMMJFlvdXIgQ29tcGFueSBOYW1l
|
||||
IERvY2tlciBSZWdpc3RyeSBDQTAeFw0xNzEyMTExMTI2NTRaFw0xOTEyMzExMTI2
|
||||
NTRaMGcxCzAJBgNVBAYTAkNOMQ8wDQYDVQQIDAZTaGFueGkxDzANBgNVBAcMBkRh
|
||||
dG9uZzEaMBgGA1UECgwRWW91ciBDb21wYW55IE5hbWUxGjAYBgNVBAMMEWRvY2tl
|
||||
ci5kb21haW4uY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1Hbm
|
||||
1tZvAeC8J54pQLHTVCtrICQ8KFTLOZakPHSWox8iQ4i2fkZaSccvE/51LIFnCM1y
|
||||
yZv88ILucqitG4zvuhDG+cU8w1vRbWf3xfGCCsHyn6LKBHR0Kk6+WRIBZTdRSsW8
|
||||
ZvpL2Y7eBNAUkC2oeaOJEOQ8D50b3u5jhAFmXuAcTiZh90Ve4JBKZV8dGs8L81vO
|
||||
vb7tqvJrEvCNKuZO7mEcjXkgiwUdP3pkZYa0tPOV5UrLH/oEvgPDJfXrNntCY1+A
|
||||
+CBQ7Sq3S2YpNJN7VnK6SboRi7xpOEgQOXwNVJWm/5YBvnbAztNXKcE2q2wREL9T
|
||||
ulUJCqo2h6NRaGYPfiLZIUHEJ7vQitRBRDpkxcX8XJX3Jm7weRPXLDOG8RN3FzPD
|
||||
TGL2ZDTWKDIQ20OhYEmENInKkpC2bYpwMzNvBA7AJN6MCYHXl4VP/Df0pPtMM/Di
|
||||
ZX+68ng3RQXT5VzDYURIH2wP5kcTL0irsNr+L7lHD+5mA1VErdQsh6AHWjrwMrSM
|
||||
egJpLP11rK4J+P/HHnqsBEi5XZI/hvRmwD7gwskRqXdDMHaWnoIIpPO3TeNYQUjD
|
||||
xaV5KUQuWVME5Ihuy03FPMChXXB0WF+tclPJxjQyDkwEVL+6d8i5yCPUBS2gBSBy
|
||||
pQQINFH4hOcx2e9Lujx7dOWfidjX3xssC9bEe60CAwEAAaOBmjCBlzAfBgNVHSME
|
||||
GDAWgBTS1B3CPFKA/HcI0cdE8YD4zG143DAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM
|
||||
MAoGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIFoDAiBgNVHREEGzAZghFkb2NrZXIu
|
||||
ZG9tYWluLmNvbYcEfwAAATAdBgNVHQ4EFgQUSanj6Cs4KVEKaK6/+VA/fNwNg4Ew
|
||||
DQYJKoZIhvcNAQELBQADggIBAKYtI1WKAL4FoSgH6sTZakw6h90uebrxm9ojeZTA
|
||||
k0ues8bGTu3w3dsphd9J0V27oz/dGjkwoIzy4QMYC4h6epKVadWfDhnHUPUT1JIC
|
||||
nGl7qFR539CSPzW+J1mVAGTZ1QONVxe6rFEDRXTsm9oUNq9LUB6a9EBO/9O0x2o7
|
||||
SZVUJd2WfMGAhqYjKCtMt+8kQgPxayok5IwWLBf03nluoF09Xu1WbY3f9wGNrzQp
|
||||
ulNlLzkU3f7+dVgF4lvIbr4MPWSQL2A0RYYjqWuwvUlXggtR+Nl6ldotDe7Ae18V
|
||||
KhQPJzM4muHjRY5dLkzQIIAQifxNprZCYiurUCAmOyOcHYMt5RuiVUPlB/2hoP/E
|
||||
tuFqq66v0qsE4mCfmJrRq+Yjfgcqsg1quRpjWh9DWOGa9HUeYFkLEKOgXybxVHJQ
|
||||
ktYba34ZFfBJUMcbZRYrRH6R4zu4LpRiyiXm29F5ml9tarThDZB5g5DJ6BTEt3Zw
|
||||
+qQHsIAcmHZvJPKEZmM6883gxbGQQ1Xt7iDrp94YRXMguBMbJwEsqI7w+25BHija
|
||||
Hp4gctdoBvkQBYpXoEsn8wnguofqJt/JhVgu0EQXR4j3U0uI+Oo9ODHFb5t2T26w
|
||||
EifwcLH+NyUNmUQH45lxaCzb+tqFlP7cbHsdPniaS4AtmBYwKNJMjcrgxnZPtfy1
|
||||
7zJA
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,51 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -82,9 +82,9 @@ RUN pwd # 输出 /app
|
||||
|
||||
```docker
|
||||
## 构建阶段
|
||||
## 建议使用 node:20 或 node: 等具体版本标签,避免使用 latest
|
||||
## 建议使用 node:22 或 node: 等具体版本标签,避免使用 latest
|
||||
|
||||
FROM node:20 AS builder
|
||||
FROM node:22 AS builder
|
||||
WORKDIR /build
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
@@ -105,8 +105,8 @@ COPY --from=builder /build/dist .
|
||||
#### 1. 尽早设置 WORKDIR
|
||||
|
||||
```docker
|
||||
# 建议使用 node:20 等主/次版本号标签
|
||||
FROM node:20
|
||||
# 建议使用 node:22 等主/次版本号标签
|
||||
FROM node:22
|
||||
WORKDIR /app # 尽早设置
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
@@ -35,7 +35,7 @@ flowchart LR
|
||||
#### 创建并切换用户
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
FROM node:22-alpine
|
||||
|
||||
## 1. 创建用户和组
|
||||
|
||||
@@ -173,7 +173,7 @@ $ docker run -u root myimage
|
||||
切换用户后,确保应用有权访问文件:
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
FROM node:22-alpine
|
||||
|
||||
## 创建用户
|
||||
|
||||
@@ -229,14 +229,14 @@ USER 1000:1000
|
||||
```docker
|
||||
## 构建阶段可以用 root
|
||||
|
||||
FROM node:20 AS builder
|
||||
FROM node:22 AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install && npm run build
|
||||
|
||||
## 生产阶段用非 root
|
||||
|
||||
FROM node:20-alpine
|
||||
FROM node:22-alpine
|
||||
RUN adduser -D appuser
|
||||
WORKDIR /app
|
||||
COPY --from=builder --chown=appuser:appuser /app/dist .
|
||||
|
||||
@@ -34,7 +34,7 @@ Starting ──成功──> Healthy ──失败N次──> Unhealthy
|
||||
#### Web 服务检查
|
||||
|
||||
```docker
|
||||
# 注:nginx 镜像推荐使用具体的版本标签(如 nginx:1.25-alpine)
|
||||
# 注:nginx 镜像推荐使用具体的版本标签(如 nginx:1.28-alpine)
|
||||
FROM nginx
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ ONBUILD <其它指令>
|
||||
**基础镜像 (my-node-base)**:
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
FROM node:22-alpine
|
||||
WORKDIR /app
|
||||
|
||||
## 这些指令将在子镜像构建时执行
|
||||
@@ -126,7 +126,7 @@ ONBUILD COPY dist/ /usr/share/nginx/html/
|
||||
建议在镜像标签中添加 `-onbuild` 后缀,明确告知使用者该镜像包含触发器。
|
||||
|
||||
```bash
|
||||
node:20-onbuild
|
||||
node:22-onbuild
|
||||
python:3.12-onbuild
|
||||
```
|
||||
|
||||
|
||||
@@ -14,12 +14,20 @@ Dockerfile 中的常用指令包括:
|
||||
|
||||
- **FROM**: 指定基础镜像,必须是第一条指令
|
||||
- **RUN**: 在镜像中执行命令,用于安装软件包等
|
||||
- **WORKDIR**: 设置工作目录
|
||||
- **COPY/ADD**: 复制文件到镜像中
|
||||
- **EXPOSE**: 声明容器监听的端口
|
||||
- **ENV**: 设置环境变量
|
||||
- **ENTRYPOINT**: 容器启动时的入口点
|
||||
- **COPY**: 复制文件到镜像中
|
||||
- **ADD**: 更高级的复制文件(支持 URL 和自动解压)
|
||||
- **CMD**: 容器默认执行的命令
|
||||
- **ENTRYPOINT**: 容器启动时的入口点
|
||||
- **ENV**: 设置环境变量
|
||||
- **ARG**: 构建时的参数变量
|
||||
- **VOLUME**: 定义匿名卷挂载点
|
||||
- **EXPOSE**: 声明容器监听的端口
|
||||
- **WORKDIR**: 设置工作目录
|
||||
- **USER**: 指定运行容器时的用户
|
||||
- **HEALTHCHECK**: 配置容器健康检查
|
||||
- **ONBUILD**: 设置触发器指令,在子镜像构建时执行
|
||||
- **LABEL**: 为镜像添加元数据标签
|
||||
- **SHELL**: 指定 RUN 等指令使用的 shell
|
||||
|
||||
### 最佳实践建议
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ WORKDIR /go/src/github.com/go/helloworld/
|
||||
COPY app.go .
|
||||
|
||||
RUN go mod init helloworld \
|
||||
&& go get -d -v github.com/go-sql-driver/mysql \
|
||||
&& go get 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
|
||||
|
||||
@@ -62,13 +62,14 @@ WORKDIR /go/src/github.com/go/helloworld
|
||||
|
||||
COPY app.go .
|
||||
|
||||
RUN go get -d -v github.com/go-sql-driver/mysql \
|
||||
RUN go mod init helloworld \
|
||||
&& go get github.com/go-sql-driver/mysql \
|
||||
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
|
||||
```
|
||||
编写 `Dockerfile.copy` 文件
|
||||
|
||||
```docker
|
||||
FROM alpine:latest
|
||||
FROM alpine:3
|
||||
|
||||
RUN apk --no-cache add ca-certificates
|
||||
|
||||
@@ -125,19 +126,20 @@ RUN apk --no-cache add git
|
||||
|
||||
WORKDIR /go/src/github.com/go/helloworld/
|
||||
|
||||
RUN go get -d -v github.com/go-sql-driver/mysql
|
||||
RUN go mod init helloworld \
|
||||
&& go get 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 as prod
|
||||
FROM alpine:3 as prod
|
||||
|
||||
RUN apk --no-cache add ca-certificates
|
||||
|
||||
WORKDIR /root/
|
||||
|
||||
COPY --from=0 /go/src/github.com/go/helloworld/app .
|
||||
COPY --from=builder /go/src/github.com/go/helloworld/app .
|
||||
|
||||
CMD ["./app"]
|
||||
```
|
||||
@@ -158,6 +160,15 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
|
||||
```
|
||||
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。
|
||||
|
||||
> **Go Modules 最佳实践**:上述示例为简化演示在 Dockerfile 中临时执行 `go mod init`。在实际项目中,通常已在代码仓库中维护好 `go.mod` 和 `go.sum` 文件。推荐的 Dockerfile 写法是先拷贝这两个文件并执行 `go mod download` 以利用 Docker 层缓存,再拷贝源码并构建:
|
||||
>
|
||||
> ```docker
|
||||
> COPY go.mod go.sum ./
|
||||
> RUN go mod download
|
||||
> COPY . .
|
||||
> RUN go build -o app .
|
||||
> ```
|
||||
|
||||
### 7.17.4 只构建某一阶段的镜像
|
||||
|
||||
我们可以使用 `as` 来为某一阶段命名,例如
|
||||
@@ -173,8 +184,8 @@ $ docker build --target builder -t username/imagename:tag .
|
||||
|
||||
### 7.17.5 构建时从其他镜像复制文件
|
||||
|
||||
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
|
||||
上面例子中我们使用 `COPY --from=builder /go/src/github.com/go/helloworld/app .` 通过已命名阶段(`as builder`)从上一阶段的镜像中复制文件(命名引用比 `--from=0` 这种位置索引更易读,也是当前官方推荐的最佳实践);我们也可以复制任意镜像中的文件。
|
||||
|
||||
```docker
|
||||
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
|
||||
COPY --from=nginx:1.28-alpine /etc/nginx/nginx.conf /nginx.conf
|
||||
```
|
||||
|
||||
@@ -60,8 +60,8 @@ server {
|
||||
第一阶段进行前端构建。
|
||||
|
||||
```docker
|
||||
# 注:node 镜像推荐使用具体的版本标签(如 node:20-alpine)
|
||||
FROM node:alpine as frontend
|
||||
# 注:node 镜像推荐使用具体的版本标签(如 node:22-alpine)
|
||||
FROM node:22-alpine as frontend
|
||||
|
||||
COPY package.json /app/
|
||||
|
||||
@@ -83,7 +83,7 @@ RUN set -x ; cd /app \
|
||||
|
||||
```docker
|
||||
# 注:composer 镜像推荐使用具体的版本标签(如 composer:2.x)
|
||||
FROM composer as composer
|
||||
FROM composer:2 as composer
|
||||
|
||||
COPY database/ /app/database/
|
||||
COPY composer.json composer.lock /app/
|
||||
@@ -128,8 +128,8 @@ RUN set -x ; cd ${LARAVEL_PATH} \
|
||||
### 7.18.5 最后一个阶段构建 NGINX 镜像
|
||||
|
||||
```docker
|
||||
# 注:nginx 镜像推荐使用具体的版本标签(如 nginx:1.25-alpine)
|
||||
FROM nginx:alpine as nginx
|
||||
# 注:nginx 镜像推荐使用具体的版本标签(如 nginx:1.28-alpine)
|
||||
FROM nginx:1.28-alpine as nginx
|
||||
|
||||
ARG LARAVEL_PATH=/app/laravel
|
||||
|
||||
@@ -179,8 +179,8 @@ $ docker run -dit --rm --network=laravel -p 8080:80 my/nginx
|
||||
完整的 `Dockerfile` 文件如下。
|
||||
|
||||
```docker
|
||||
# 注:生产环境推荐使用具体的版本标签,如 node:20-alpine、composer:2.x、php:8.3-fpm-alpine、nginx:1.25-alpine
|
||||
FROM node:alpine as frontend
|
||||
# 注:生产环境推荐使用具体的版本标签,如 node:22-alpine、composer:2.x、php:8.3-fpm-alpine、nginx:1.28-alpine
|
||||
FROM node:22-alpine as frontend
|
||||
|
||||
COPY package.json /app/
|
||||
|
||||
@@ -195,7 +195,7 @@ RUN set -x ; cd /app \
|
||||
&& mkdir -p public \
|
||||
&& npm run production
|
||||
|
||||
FROM composer as composer
|
||||
FROM composer:2 as composer
|
||||
|
||||
COPY database/ /app/database/
|
||||
COPY composer.json composer.lock /app/
|
||||
@@ -229,7 +229,7 @@ RUN set -x ; cd ${LARAVEL_PATH} \
|
||||
&& chmod -R 777 storage \
|
||||
&& php artisan package:discover
|
||||
|
||||
FROM nginx:alpine as nginx
|
||||
FROM nginx:1.28-alpine as nginx
|
||||
|
||||
ARG LARAVEL_PATH=/app/laravel
|
||||
|
||||
|
||||
@@ -158,9 +158,11 @@ RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
|
||||
```docker
|
||||
RUN --mount=type=secret,id=mysecret \
|
||||
cat /run/secrets/mysecret
|
||||
my-private-tool --token-file /run/secrets/mysecret
|
||||
```
|
||||
|
||||
不要在构建命令中 `cat`、`echo` 或打印密钥内容;应把 `/run/secrets/<id>` 路径交给真正消费密钥的工具。
|
||||
|
||||
#### 3. Heredoc 语法
|
||||
|
||||
BuildKit 支持使用 heredoc 语法编写多行脚本,无需行末反斜杠 `\` 连接:
|
||||
|
||||
@@ -178,7 +178,7 @@ ADD app.tar.gz /app/
|
||||
```docker
|
||||
## 构建阶段
|
||||
|
||||
FROM node:20 AS builder
|
||||
FROM node:22 AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
这是 Dockerfile 使用中最常见的困惑之一。简单的答案是:
|
||||
|
||||
- **CMD**:定义容器的”默认命令”。如果用户在 `docker run` 时提供命令,CMD 会被覆盖
|
||||
- **ENTRYPOINT**:定义容器的”入口脚本”。通常用于启动应用的某个特定部分
|
||||
- **CMD**:定义容器的“默认命令”。如果用户在 `docker run` 时提供命令,CMD 会被覆盖
|
||||
- **ENTRYPOINT**:定义容器的“入口脚本”。通常用于启动应用的某个特定部分
|
||||
|
||||
**决策树**:
|
||||
|
||||
@@ -31,9 +31,9 @@ CMD 有三种格式:
|
||||
|
||||
| 格式 | 语法 | 推荐程度 |
|
||||
|------|------|---------|
|
||||
| **exec 格式**| `CMD [“可执行文件”, “参数1”, “参数2”]` | ✅**推荐** |
|
||||
| **exec 格式**| `CMD ["可执行文件", "参数1", "参数2"]` | ✅**推荐** |
|
||||
| **shell 格式** | `CMD 命令 参数1 参数2` | ⚠️ 简单场景 |
|
||||
| **参数格式** | `CMD [“参数1”, “参数2”]` | 配合 ENTRYPOINT |
|
||||
| **参数格式** | `CMD ["参数1", "参数2"]` | 配合 ENTRYPOINT |
|
||||
|
||||
#### exec 格式:推荐
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
| 格式 | 语法 | 推荐程度 |
|
||||
|------|------|---------|
|
||||
| **exec 格式**| `ENTRYPOINT [“可执行文件”, “参数1”]` | ✅**推荐** |
|
||||
| **exec 格式**| `ENTRYPOINT ["可执行文件", "参数1"]` | ✅**推荐** |
|
||||
| **shell 格式** | `ENTRYPOINT 命令 参数` | ⚠️ 不推荐 |
|
||||
|
||||
```docker
|
||||
|
||||
@@ -89,6 +89,8 @@ const dbUrl = process.env.DATABASE_URL;
|
||||
| `LABEL` | `LABEL version=$VERSION` |
|
||||
| `FROM` | `FROM node:$NODE_VERSION` |
|
||||
|
||||
> **注意**:`FROM` 是上表中的特例——它只能引用在第一条 `FROM` 之前用 `ARG` 声明的变量,**无法**使用 `ENV` 定义的环境变量(`ENV` 要进入构建阶段后才生效)。其余指令才能引用 `ENV` 环境变量。
|
||||
|
||||
---
|
||||
|
||||
### 7.6.5 运行时覆盖
|
||||
@@ -158,15 +160,15 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
```docker
|
||||
## ✅ 好:版本集中管理
|
||||
|
||||
ENV NGINX_VERSION=1.25 \
|
||||
NODE_VERSION=20 \
|
||||
ENV NGINX_VERSION=1.30 \
|
||||
NODE_VERSION=22 \
|
||||
PYTHON_VERSION=3.12
|
||||
|
||||
RUN apt-get install nginx=${NGINX_VERSION}
|
||||
|
||||
## ❌ 差:版本分散在各处
|
||||
|
||||
RUN apt-get install nginx=1.25
|
||||
RUN apt-get install nginx=1.30
|
||||
```
|
||||
|
||||
#### 2. 不要存储敏感信息
|
||||
|
||||
@@ -93,14 +93,14 @@ RUN echo "Node version: $NODE_VERSION"
|
||||
```docker
|
||||
ARG BASE_VERSION=alpine
|
||||
|
||||
FROM node:20-${BASE_VERSION} AS builder
|
||||
FROM node:22-${BASE_VERSION} AS builder
|
||||
|
||||
## 需要重新声明
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
RUN echo "Building with Node $NODE_VERSION"
|
||||
|
||||
FROM node:20-${BASE_VERSION}
|
||||
FROM node:22-${BASE_VERSION}
|
||||
|
||||
## 每个阶段都需要重新声明
|
||||
|
||||
@@ -125,8 +125,8 @@ $ docker build --build-arg ALPINE_VERSION=3.19 .
|
||||
#### 2. 设置软件版本
|
||||
|
||||
```docker
|
||||
# 使用次版本号 (1.25) 而非完整版本号 (1.25.0),以便自动更新到最新补丁版本
|
||||
ARG NGINX_VERSION=1.25
|
||||
# 使用次版本号 (1.30) 而非完整版本号 (1.30.0),以便自动更新到最新补丁版本
|
||||
ARG NGINX_VERSION=1.30
|
||||
|
||||
RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -xz
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ flowchart LR
|
||||
#### 定义单个卷
|
||||
|
||||
```docker
|
||||
FROM mysql:8.0
|
||||
FROM mysql:8.4
|
||||
VOLUME /var/lib/mysql
|
||||
```
|
||||
|
||||
@@ -63,7 +63,7 @@ VOLUME ["/data", "/logs", "/config"]
|
||||
如果运行时未指定挂载,Docker 会自动创建匿名卷:
|
||||
|
||||
```bash
|
||||
$ docker run mysql:8.0
|
||||
$ docker run mysql:8.4
|
||||
$ docker volume ls
|
||||
DRIVER VOLUME NAME
|
||||
local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
@@ -74,7 +74,7 @@ local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
```bash
|
||||
## 使用命名卷替代匿名卷
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.4
|
||||
```
|
||||
|
||||
#### 3. 可被 Bind Mount 覆盖
|
||||
@@ -82,7 +82,7 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
```bash
|
||||
## 使用宿主机目录替代
|
||||
|
||||
$ docker run -v /my/data:/var/lib/mysql mysql:8.0
|
||||
$ docker run -v /my/data:/var/lib/mysql mysql:8.4
|
||||
```
|
||||
---
|
||||
|
||||
@@ -145,7 +145,7 @@ VOLUME /app/uploads
|
||||
```bash
|
||||
## 查看镜像定义的 VOLUME
|
||||
|
||||
$ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
|
||||
$ docker inspect mysql:8.4 --format '{{json .Config.Volumes}}' | jq
|
||||
{
|
||||
"/var/lib/mysql": {}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ volumes:
|
||||
```bash
|
||||
## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
|
||||
|
||||
$ docker run --rm mysql:8.0
|
||||
$ docker run --rm mysql:8.4
|
||||
|
||||
## 容器停止后,数据丢失!
|
||||
|
||||
@@ -205,7 +205,7 @@ $ docker run --rm mysql:8.0
|
||||
**解决**:始终使用命名卷
|
||||
|
||||
```bash
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.4
|
||||
```
|
||||
---
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ docker build -t my-image:1.0 .
|
||||
本章中的 Dockerfile 示例使用的基础镜像标签遵循以下原则:
|
||||
|
||||
- **通用标签**(如 `ubuntu:24.04`、`alpine`、`nginx`):保持原样,无需修改
|
||||
- **基础镜像版本号**(如 `node:20`、`python:3.12`):使用主或次版本号而非完整版本号(patch),这样可以自动获取最新的补丁版本,确保获得安全更新
|
||||
- **基础镜像版本号**(如 `node:22`、`python:3.12`):使用主或次版本号而非完整版本号(patch),这样可以自动获取最新的补丁版本,确保获得安全更新
|
||||
- **避免**:不建议使用 `latest` 标签和完整的 patch 版本号(如 `20.10.0`)作为基础镜像,因为这会导致构建的不可重现性或安全风险
|
||||
|
||||
读者在使用这些示例时,应根据实际生产环境需求选择合适的版本号。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:alpine as frontend
|
||||
FROM node:22-alpine as frontend
|
||||
|
||||
COPY package.json /app/
|
||||
|
||||
@@ -13,7 +13,7 @@ RUN set -x ; cd /app \
|
||||
&& mkdir -p public \
|
||||
&& npm run production
|
||||
|
||||
FROM composer as composer
|
||||
FROM composer:2 as composer
|
||||
|
||||
COPY database/ /app/database/
|
||||
COPY composer.json /app/
|
||||
@@ -47,7 +47,7 @@ RUN set -x ; cd ${LARAVEL_PATH} \
|
||||
&& chmod -R 777 storage \
|
||||
&& php artisan package:discover
|
||||
|
||||
FROM nginx:alpine as nginx
|
||||
FROM nginx:1.30-alpine as nginx
|
||||
|
||||
ARG LARAVEL_PATH=/app/laravel
|
||||
|
||||
|
||||
@@ -21,6 +21,21 @@
|
||||
| **LABEL** | 添加元数据 | 推荐 OCI 标准标签,替代 MAINTAINER |
|
||||
| **SHELL** | 更改默认 shell | 推荐 `["/bin/bash", "-o", "pipefail", "-c"]` |
|
||||
|
||||
### 生产镜像快速检查清单
|
||||
|
||||
在将镜像推向生产之前,建议逐条过一遍以下清单:
|
||||
|
||||
- [ ] 基础镜像选择了最小化版本(如 `alpine`、`distroless`)
|
||||
- [ ] 使用了[多阶段构建](7.17_multistage_builds.md),最终镜像不含编译工具链
|
||||
- [ ] 以非 root 用户运行(`USER` 指令)
|
||||
- [ ] `COPY` 优先于 `ADD`,且仅复制必要文件
|
||||
- [ ] `RUN` 指令合并了 `apt-get update && install && rm -rf /var/lib/apt/lists/*`
|
||||
- [ ] 设置了 `HEALTHCHECK`
|
||||
- [ ] 使用了 `.dockerignore` 排除 `.git`、`node_modules` 等无关文件
|
||||
- [ ] 镜像标签使用了具体版本号或 commit hash,而非 `latest`
|
||||
|
||||
> 更完整的编写指南见[附录:Dockerfile 最佳实践](../appendix/best_practices.md)。
|
||||
|
||||
### 延伸阅读
|
||||
|
||||
- [使用 Dockerfile 定制镜像](../04_image/4.5_build.md):Dockerfile 入门
|
||||
|
||||
@@ -238,7 +238,7 @@ $ docker run -u $(id -u):$(id -g) ...
|
||||
在 Docker Desktop 上,Bind Mount 性能通常不如 Volume,因为数据需要在宿主机文件系统和 Linux VM 之间同步:
|
||||
|
||||
```bash
|
||||
## 使用 :cached 或 :delegated 提高性能(macOS)
|
||||
## 使用 :cached 或 :delegated 提高性能(macOS,仅 Docker Desktop 4.5 及更早版本)
|
||||
|
||||
$ docker run -v /host/path:/container/path:cached myapp
|
||||
```
|
||||
@@ -248,6 +248,8 @@ $ docker run -v /host/path:/container/path:cached myapp
|
||||
| `:delegated` | 容器权威,宿主机读取可能延迟 |
|
||||
| `:consistent` | 默认,完全一致 (最慢)|
|
||||
|
||||
> **注意**:Docker Desktop 4.6+ 默认使用 VirtioFS 文件共享引擎,上述 `:cached`/`:delegated` 选项已被静默忽略。如需优化文件同步性能,请参考 Docker Desktop 的 [Synchronized file shares](https://docs.docker.com/desktop/synchronized-file-sharing/) 功能。
|
||||
|
||||
---
|
||||
|
||||
### 8.2.9 最佳实践
|
||||
|
||||
@@ -21,10 +21,11 @@ ghi789... none null local
|
||||
| **none** | 禁用网络 | 完全隔离的容器 |
|
||||
| **overlay** | 跨主机网络 | Docker Swarm 集群 |
|
||||
| **macvlan** | 容器拥有独立 MAC 地址 | 需要直接接入物理网络 |
|
||||
| **ipvlan** | 容器共享父接口 MAC,独享 IP | 同网段大量容器、对 MAC 数量受限的网络 |
|
||||
|
||||
### 9.2.2 Bridge 网络:默认
|
||||
|
||||
Bridge 是 Docker 默认使用的网络模式。Docker 启动时会自动创建 `docker0` 虚拟网桥,所有未指定网络的容器都会连接到这个网桥上。
|
||||
Bridge 是 Docker 默认使用的网络模式。在原生 Linux Docker Engine 上,Docker 启动时通常会创建 `docker0` 虚拟网桥,未指定网络的容器会连接到这个网桥上。Docker Desktop 运行在虚拟机内,宿主机上不会直接看到 `docker0`,也不能假设宿主机可直接访问每个容器 IP。
|
||||
|
||||
核心组件如下:
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
容器的网络访问规则如下:
|
||||
|
||||
- **容器之间**:可以通过 IP 或容器名 (自定义网络) 互通。
|
||||
- **宿主机访问容器**:可以通过容器 IP 访问。
|
||||
- **宿主机访问容器**:原生 Linux 环境下可按网络配置访问容器 IP;Docker Desktop 上不能依赖容器 IP,应通过端口映射、容器名(容器间)或 `host.docker.internal` 等机制访问。
|
||||
- **外部网络访问容器**:❌ 默认无法直接访问。
|
||||
|
||||
为了让外部 (如你的浏览器、其他局域网机器) 访问容器内的服务,我们需要将容器的端口 **映射** 到宿主机的端口。
|
||||
|
||||
@@ -8,7 +8,7 @@ Overlay 网络在现有网络基础上建立虚拟网络,允许容器跨宿主
|
||||
|
||||
#### Overlay 网络工作原理
|
||||
|
||||
Overlay 网络通过隧道封装技术(通常是 VXLAN)将容器网络流量封装在宿主机物理网络的 UDP 数据包中传输。
|
||||
Overlay 网络通过隧道封装技术(通常是 VXLAN)将容器网络流量封装在宿主机物理网络的 UDP 数据包中传输。Docker overlay 网络默认使用 `4789/udp` 作为数据通道端口,同时 Swarm 控制面与节点通信还需要相应开放 `2377/tcp`、`7946/tcp` 和 `7946/udp`。
|
||||
|
||||
```text
|
||||
容器 A (192.168.0.2)
|
||||
|
||||
@@ -15,7 +15,7 @@ BuildKit 引入了多项新指令,旨在优化构建缓存和安全性。以
|
||||
要使用最新的 Dockerfile 语法特性,建议在 Dockerfile 开头添加语法指令:
|
||||
|
||||
```docker
|
||||
## syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
```
|
||||
这将使用最新的稳定版语法解析器,确保你可以使用所有最新特性。
|
||||
@@ -51,7 +51,7 @@ COPY --from=builder /app/dist /app/dist
|
||||
`BuildKit` 提供了 `RUN --mount=type=cache` 指令,可以实现上边的设想。
|
||||
|
||||
```docker
|
||||
## syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:alpine as builder
|
||||
|
||||
@@ -105,7 +105,7 @@ RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
|
||||
该指令可以将一个镜像 (或上一构建阶段) 的文件挂载到指定位置。
|
||||
|
||||
```docker
|
||||
## syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \
|
||||
cat /docker-php-entrypoint
|
||||
@@ -116,7 +116,7 @@ RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoin
|
||||
该指令可以将一个 `tmpfs` 文件系统挂载到指定位置。
|
||||
|
||||
```docker
|
||||
## syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
RUN --mount=type=tmpfs,target=/temp \
|
||||
mount | grep /temp
|
||||
@@ -127,10 +127,10 @@ RUN --mount=type=tmpfs,target=/temp \
|
||||
该指令可以将一个文件 (例如密钥) 挂载到指定位置。
|
||||
|
||||
```docker
|
||||
## syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
|
||||
cat /root/.aws/credentials
|
||||
test -s /root/.aws/credentials && echo "credentials mounted"
|
||||
```
|
||||
```bash
|
||||
$ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .
|
||||
@@ -141,7 +141,7 @@ $ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .
|
||||
该指令可以挂载 `ssh` 密钥。
|
||||
|
||||
```docker
|
||||
## syntax=docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM alpine
|
||||
RUN apk add --no-cache openssh-client
|
||||
|
||||
@@ -13,6 +13,17 @@ $ docker buildx build .
|
||||
```
|
||||
Buildx 使用 [BuildKit 引擎](10.1_buildkit.md)进行构建,支持许多新的功能,具体参考 [Buildkit](10.1_buildkit.md) 一节。
|
||||
|
||||
需要注意的是,默认 `docker` driver 会把构建结果加载到本地镜像存储;使用 `docker-container`、remote、cloud 等 builder 时,如未指定 `--load`、`--push` 或 `--output`,结果通常只保留在构建缓存中。
|
||||
|
||||
#### 构建前检查
|
||||
|
||||
Buildx 0.15 起支持构建检查:常规构建会默认检查 Dockerfile 与构建参数;如果只想做检查而不真正构建,可以使用 `--check`:
|
||||
|
||||
```bash
|
||||
$ docker buildx build --check .
|
||||
```
|
||||
这适合作为 CI 的快速门禁:普通构建中的检查告警默认不会让构建失败,但 `--check` 发现问题会以非零状态退出;需要把告警提升为错误时,可在 Dockerfile 顶部配合 `# check=error=true`。
|
||||
|
||||
#### 使用 `bake`
|
||||
|
||||
`docker buildx bake` 是一个高级构建命令,支持从 HCL、JSON 或 Compose 文件中定义构建目标,实现复杂的流水线构建。
|
||||
@@ -39,7 +50,7 @@ $ docker buildx build --sbom=true -t myimage .
|
||||
> **⚠️ 注意与失败模式**:
|
||||
> 要使 SBOM (或其它 attestation 元数据) 成功附着并可见,对底层的存储格式有前置要求:默认的 classic image store 不支持 manifest list/index 这种存放 attestation 的结构。
|
||||
>
|
||||
> 如果只简单运行上述命令,你可能会面临 **”命令成功执行,但本地镜像中看不到 SBOM”** 的体会落差。
|
||||
> 如果只简单运行上述命令,你可能会面临 **“命令成功执行,但本地镜像中看不到 SBOM”** 的体会落差。
|
||||
>
|
||||
> **正确的解决路径有两条**:
|
||||
> 1. **推送到远端仓库**:使用 `docker buildx build --sbom=true --push -t myimage:tag` 时,SBOM 会正确保存到远端仓库。远端 OCI 兼容的镜像仓库能够完整存储这些元数据。
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 [Moby BuildKit](10.1_buildkit.md) 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。
|
||||
|
||||
> Buildx 需要 Docker v19.03+ (Docker 19.03 及以上版本)。在较新版本中已更常用且功能更完整。
|
||||
> Buildx 需要 Docker v23.0+(该版本起 BuildKit 成为默认构建引擎)。推荐使用 Docker v28 及以上版本以获得最完整的 Buildx 功能支持。
|
||||
|
||||
## 本章内容
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ Docker Buildx 是 Docker 构建系统的重要进化,提供了高效、安全
|
||||
| **缓存挂载** | `RUN --mount=type=cache` 加速依赖安装 |
|
||||
| **Secret 挂载** | `RUN --mount=type=secret` 安全传递密钥 |
|
||||
| **buildx build** | 替代 `docker build`,支持更多构建功能 |
|
||||
| **构建检查** | `--check` 可在不执行构建的情况下检查 Dockerfile 与构建参数 |
|
||||
| **多架构构建** | `--platform` 参数一键构建多种架构镜像 |
|
||||
| **Manifest List** | 多架构镜像的索引文件 |
|
||||
| **SBOM** | 通过 `--sbom=true` 生成软件物料清单 |
|
||||
|
||||
@@ -19,7 +19,7 @@ $ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
|
||||
```bash
|
||||
$ docker compose version
|
||||
Docker Compose version v5.x
|
||||
Docker Compose version v5.x.x
|
||||
```
|
||||
|
||||
### 11.2.3 卸载
|
||||
|
||||
@@ -42,7 +42,7 @@ if __name__ == "__main__":
|
||||
|
||||
```docker
|
||||
FROM python:3.12-alpine
|
||||
ADD . /code
|
||||
COPY . /code
|
||||
WORKDIR /code
|
||||
RUN pip install redis flask
|
||||
CMD ["python", "app.py"]
|
||||
|
||||
@@ -46,7 +46,7 @@ docker compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
|
||||
|
||||
* `-p, --project-name NAME` 指定项目名称,默认将使用所在目录名称作为项目名。
|
||||
|
||||
* `--verbose` 输出更多调试信息。
|
||||
* `--verbose` 输出更多调试信息。(**已弃用**:在 Docker Compose V2 中,请改用 `docker --log-level debug compose ...` 或设置环境变量 `COMPOSE_DEBUG=1`。)
|
||||
|
||||
* `-v, --version` 打印版本并退出。
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ services:
|
||||
redis:
|
||||
image: redis
|
||||
healthcheck:
|
||||
test: [“CMD”, “redis-cli”, “ping”]
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
@@ -158,7 +158,7 @@ services:
|
||||
db:
|
||||
image: postgres
|
||||
healthcheck:
|
||||
test: [“CMD-SHELL”, “pg_isready -U postgres”]
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
@@ -411,14 +411,13 @@ ports:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
|
||||
mysql:
|
||||
image: mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
|
||||
secrets:
|
||||
- db_root_password
|
||||
- my_other_secret
|
||||
mysql:
|
||||
image: mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
|
||||
secrets:
|
||||
- db_root_password
|
||||
- my_other_secret
|
||||
|
||||
secrets:
|
||||
db_root_password:
|
||||
@@ -490,7 +489,7 @@ volumes:
|
||||
```yaml
|
||||
services:
|
||||
my_src:
|
||||
image: mysql:8.0
|
||||
image: mysql:8.4
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
|
||||
@@ -524,7 +523,7 @@ domainname: your_website.com
|
||||
hostname: test
|
||||
mac_address: 08-00-27-00-0C-0A
|
||||
```
|
||||
允许容器中运行一些特权命令。
|
||||
允许容器中运行一些特权命令。`privileged: true` 会显著扩大容器对宿主机设备和 Linux capability 的访问范围,生产环境应优先使用更窄的 `cap_add`、`devices` 或只读挂载;更多说明见 [内核能力机制](../18_security/18.4_kernel_capability.md)。
|
||||
|
||||
```yaml
|
||||
privileged: true
|
||||
|
||||
@@ -106,6 +106,11 @@ services:
|
||||
POSTGRES_PASSWORD: password
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
web:
|
||||
build: .
|
||||
@@ -115,7 +120,8 @@ services:
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DATABASE_URL: postgres://postgres:password@db:5432/myapp_development
|
||||
|
||||
@@ -128,7 +134,7 @@ volumes:
|
||||
|--------|------|
|
||||
| `rm -f tmp/pids/server.pid` | 清理上次异常退出留下的 PID 文件 |
|
||||
| `volumes: .:/myapp` | 挂载代码目录,支持热更新 |
|
||||
| `depends_on: db` | 确保数据库先启动 |
|
||||
| `depends_on` + `condition` | 等待数据库健康检查通过后再启动 |
|
||||
| `DATABASE_URL` | Rails 12-factor 风格的数据库配置 |
|
||||
|
||||
### 11.7.6 步骤 4:生成 Rails 项目
|
||||
|
||||
@@ -13,7 +13,10 @@ WordPress 是全球最流行的内容管理系统 (CMS)。使用 Docker Compose
|
||||
```bash
|
||||
wordpress/
|
||||
├── compose.yaml
|
||||
├── .env # 环境变量(敏感信息)
|
||||
├── .env # 非敏感环境变量(如版本、端口)
|
||||
├── secrets/ # 本地密钥文件,生产环境应由密钥管理系统提供
|
||||
│ ├── db_root_password.txt
|
||||
│ └── db_password.txt
|
||||
└── nginx/ # 可选:反向代理配置
|
||||
└── nginx.conf
|
||||
```
|
||||
@@ -21,27 +24,30 @@ wordpress/
|
||||
|
||||
### 11.8.2 编写 `compose.yaml`
|
||||
|
||||
这是一个生产可用的最小化配置:
|
||||
这是一个可运行的单机最小配置,不是完整生产安全基线。正式部署前应固定镜像版本、放在反向代理/TLS 后面、限制公开端口、配置备份与监控,并按 WordPress 与插件生命周期做升级测试。
|
||||
|
||||
```yaml
|
||||
services:
|
||||
# 数据库服务
|
||||
|
||||
db:
|
||||
image: mysql:8.0
|
||||
image: mysql:8.4
|
||||
container_name: wordpress_db
|
||||
restart: always
|
||||
command:
|
||||
# 使用原生密码认证(旧版 WP 兼容性)
|
||||
# 启用原生密码认证(MySQL 8.4 默认禁用,旧版 WP 兼容性需要)
|
||||
|
||||
- --default-authentication-plugin=mysql_native_password
|
||||
- --mysql-native-password=ON
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_unicode_ci
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
|
||||
MYSQL_DATABASE: wordpress
|
||||
MYSQL_USER: wordpress
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
MYSQL_PASSWORD_FILE: /run/secrets/db_password
|
||||
secrets:
|
||||
- db_root_password
|
||||
- db_password
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
@@ -50,16 +56,20 @@ services:
|
||||
# WordPress 服务
|
||||
|
||||
wordpress:
|
||||
# 示例保留 latest 以便读者快速体验;生产环境请固定到经过测试的明确版本标签
|
||||
image: wordpress:latest
|
||||
container_name: wordpress_app
|
||||
restart: always
|
||||
ports:
|
||||
- "8000:80"
|
||||
# 本机调试入口;生产环境请通过反向代理发布 HTTPS
|
||||
- "127.0.0.1:8000:80"
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db:3306
|
||||
WORDPRESS_DB_USER: wordpress
|
||||
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
|
||||
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
|
||||
WORDPRESS_DB_NAME: wordpress
|
||||
secrets:
|
||||
- db_password
|
||||
volumes:
|
||||
- wp_data:/var/www/html
|
||||
# 增加上传文件大小限制
|
||||
@@ -76,20 +86,29 @@ volumes:
|
||||
|
||||
networks:
|
||||
wp_net:
|
||||
|
||||
secrets:
|
||||
db_root_password:
|
||||
file: ./secrets/db_root_password.txt
|
||||
db_password:
|
||||
file: ./secrets/db_password.txt
|
||||
```
|
||||
---
|
||||
|
||||
### 11.8.3 配置文件详解
|
||||
|
||||
#### 1. 环境变量文件 .env
|
||||
#### 1. 密钥文件
|
||||
|
||||
为了安全,不要在 `compose.yaml` 中直接写密码。创建 `.env` 文件:
|
||||
不要把数据库密码写入 `compose.yaml`、`.env`、命令行或 Git。Compose 官方建议敏感值使用 secrets;本地练习可用只读密钥文件模拟:
|
||||
|
||||
```ini
|
||||
DB_ROOT_PASSWORD=somestrongrootpassword
|
||||
DB_PASSWORD=somestronguserpassword
|
||||
```bash
|
||||
mkdir -p secrets
|
||||
printf '%s\n' 'somestrongrootpassword' > secrets/db_root_password.txt
|
||||
printf '%s\n' 'somestronguserpassword' > secrets/db_password.txt
|
||||
chmod 600 secrets/*.txt
|
||||
```
|
||||
Compose 会自动读取此同级目录下的文件。
|
||||
|
||||
把 `secrets/` 加入 `.gitignore`。生产环境应改用平台密钥管理能力,而不是把真实密码放在项目目录。
|
||||
|
||||
#### 2. 数据持久化
|
||||
|
||||
@@ -192,7 +211,7 @@ WordPress 支持 Redis 缓存以提高性能。
|
||||
1. 检查 `docker compose logs wordpress`
|
||||
2. 确认 `.env` 中的密码与 YAML 文件引用一致
|
||||
3. 确认 `WORDPRESS_DB_HOST` 也是 `db` (服务名)
|
||||
4. MySQL 8.0 可能需要几秒钟启动,WordPress 会自动重试,稍等片刻即可。
|
||||
4. MySQL 8.4 可能需要几秒钟启动,WordPress 会自动重试,稍等片刻即可。
|
||||
|
||||
#### Q:无法上传大文件
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
services:
|
||||
|
||||
db:
|
||||
image: mysql:8.0
|
||||
image: mysql:8.4
|
||||
command:
|
||||
- --default_authentication_plugin=mysql_native_password
|
||||
- --mysql-native-password=ON
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_unicode_ci
|
||||
volumes:
|
||||
|
||||
@@ -75,7 +75,7 @@ flowchart TD
|
||||
E["退出"]
|
||||
|
||||
U -->|1. REST API| D
|
||||
K -->|2. gRPC| C
|
||||
D -->|2. gRPC| C
|
||||
C -->|3. 准备镜像和 Bundle| B
|
||||
C -->|4. 启动 Shim| S
|
||||
S -->|5. 执行| R
|
||||
|
||||
@@ -198,7 +198,7 @@ $ docker run --rm --cpus=1 stress --cpu 4
|
||||
|
||||
#### Docker 对 cgroups v2 的支持
|
||||
|
||||
Docker 19.03+ 默认优先使用 cgroups v2(如果系统支持),提供更好的性能和资源隔离。如果需要明确控制或回退到 v1,可以通过 Docker 守护进程配置文件 `/etc/docker/daemon.json` 修改 `cgroup-driver` 参数:
|
||||
Docker 20.10+ 开始支持 cgroups v2(如果系统支持),提供更好的性能和资源隔离。如果需要明确控制或回退到 v1,可以通过 Docker 守护进程配置文件 `/etc/docker/daemon.json` 修改 `cgroup-driver` 参数:
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ flowchart TD
|
||||
每个 Dockerfile 指令创建一层,只有变化的层需要重建:
|
||||
|
||||
```docker
|
||||
FROM node:20 # 层1:基础镜像
|
||||
FROM node:22 # 层1:基础镜像
|
||||
COPY package.json ./ # 层2:依赖定义
|
||||
RUN npm install # 层3:安装依赖
|
||||
COPY . . # 层4:应用代码
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
### 13.2.1 节点
|
||||
|
||||
在 `Kubernetes` 中,节点是实际工作的点,节点可以是虚拟机或者物理机器,依赖于一个集群环境。每个节点都有一些必要的服务以运行容器组,并且它们都可以通过主节点来管理。必要服务包括 Docker,kubelet 和代理服务。
|
||||
在 `Kubernetes` 中,节点是实际工作的点,节点可以是虚拟机或者物理机器,依赖于一个集群环境。每个节点都有一些必要的组件以运行容器组,并且它们都可以通过控制平面来管理。必要组件包括 kubelet、容器运行时(如 containerd 或 CRI-O)和 kube-proxy;Docker 不再是 Kubernetes 节点的默认基线运行时。
|
||||
|
||||
#### 容器状态
|
||||
|
||||
@@ -29,13 +29,11 @@
|
||||
|
||||
主机 IP 需要云平台来查询,`Kubernetes` 把它作为状态的一部分来保存。如果 `Kubernetes` 没有运行在云平台上,节点 ID 就是必需的。IP 地址可以变化,并且可以包含多种类型的 IP 地址,如公共 IP,私有 IP,动态 IP,ipv6 等等。
|
||||
|
||||
##### 节点周期
|
||||
|
||||
通常来说节点有 `Pending`,`Running`,`Terminated` 三个周期,如果 Kubernetes 发现了一个节点并且其可用,那么 Kubernetes 就把它标记为 `Pending`。然后在某个时刻,Kubernetes 将会标记其为 `Running`。节点的结束周期称为 `Terminated`。一个已经 `Terminated` 的节点不会接受和调度任何请求,并且已经在其上运行的容器组也会删除。
|
||||
|
||||
##### 节点状态
|
||||
|
||||
节点的状态主要是用来描述处于 `Running` 的节点。当前可用的有 `NodeReachable` 和 `NodeReady`。以后可能会增加其他状态。`NodeReachable` 表示集群可达。`NodeReady` 表示 kubelet 返回 Status Ok 并且 HTTP 状态检查健康。
|
||||
注:`Pending` / `Running` / `Succeeded` / `Failed` / `Unknown` 是 **Pod 的生命周期阶段**(`pod.status.phase`),不是节点状态。节点本身没有 `Terminated` 状态。
|
||||
|
||||
节点的状态通过一组条件(Conditions)来描述。主要条件包括 `Ready`(kubelet 健康且可以接收 Pod)、`MemoryPressure`(内存不足)、`DiskPressure`(磁盘不足)和 `PIDPressure`(进程数过多)等。其中 `Ready` 条件最为关键:值为 `True` 表示节点健康可调度,`False` 表示节点异常,`Unknown` 表示节点控制器超过一定时间未收到心跳。被标记为 `Unknown` 较长时间的节点,其上的 Pod 会被驱逐重新调度到其他节点。
|
||||
|
||||
#### 节点管理
|
||||
|
||||
@@ -166,7 +164,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.30
|
||||
image: nginx:1.28
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
@@ -200,7 +198,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: mysql:8.0
|
||||
image: mysql:8.4
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/mysql
|
||||
|
||||
@@ -62,6 +62,7 @@ Ingress 资源仍可正常使用,但建议新项目直接采用 Gateway API。
|
||||
* **PVC (Persistent Volume Claim)**:用户申请存储的声明。
|
||||
* **PV (Persistent Volume)**:实际的存储资源 (NFS,AWS EBS,Ceph 等)。
|
||||
* **StorageClass**:定义存储类,支持动态创建 PV。
|
||||
* **VolumeAttributesClass**:Kubernetes 1.34 起 GA,用于在 CSI 驱动支持 `ModifyVolume` 时动态调整卷属性,例如性能等级或服务质量参数。
|
||||
|
||||
### 13.4.4 Horizontal Pod Autoscaling
|
||||
|
||||
@@ -91,7 +92,7 @@ spec:
|
||||
### 13.4.5 ConfigMap 与 Secret
|
||||
|
||||
* **ConfigMap**:存储非机密的配置数据 (配置文件、环境变量)。
|
||||
* **Secret**:存储机密数据 (密码、Token、证书),在 Etcd 中加密存储。
|
||||
* **Secret**:存储机密数据 (密码、Token、证书)。Secret 值默认只是 Base64 编码并存入 etcd;生产环境应显式启用 etcd 静态加密或 KMS。
|
||||
|
||||
通过将配置与镜像分离,保证了容器的可移植性。
|
||||
|
||||
@@ -114,3 +115,7 @@ metadata:
|
||||
pod-security.kubernetes.io/enforce: baseline
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
```
|
||||
|
||||
### 13.4.7 Sidecar Containers
|
||||
|
||||
Kubernetes 1.33 起 Sidecar Containers 进入 GA。它们通过 `initContainers` 中带 `restartPolicy: Always` 的容器表达,既保留 init container 的启动顺序,又会在主容器生命周期内持续运行。对于旧集群或不需要启动顺序控制的场景,仍可使用普通多容器 Pod。
|
||||
|
||||
@@ -31,7 +31,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.30
|
||||
image: nginx:1.28
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
@@ -73,7 +73,7 @@ kubectl get svc nginx-service
|
||||
|
||||
### 13.5.4 步骤 3:模拟滚动更新
|
||||
|
||||
修改 `nginx-deployment.yaml`,将镜像版本改为 `nginx:1.30-alpine`。
|
||||
修改 `nginx-deployment.yaml`,将镜像版本改为 `nginx:1.28-alpine`。
|
||||
|
||||
```bash
|
||||
kubectl apply -f nginx-deployment.yaml
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
Kubernetes 的最小调度单位是 `Pod`。一个 `Pod` 由一组紧密协作的容器构成,它们共享网络命名空间、IP 以及部分存储资源,也可以根据需要对 Pod 进行端口映射。
|
||||
|
||||
如果你已经熟悉 Docker,可以用以下对照来理解 Kubernetes 的核心概念:Docker 中的“容器”对应 Kubernetes 的 `Pod`(一个或多个容器的组合);`docker-compose.yml` 的角色类似于 Kubernetes 的 `Deployment` + `Service` 声明;`docker run` 的端口映射和网络配置,在 Kubernetes 中由 `Service` 和 `Ingress` 接管。掌握这些映射关系,有助于从单机 Docker 平滑过渡到集群编排。
|
||||
|
||||
本章将分为 5 节介绍 `Kubernetes`:
|
||||
|
||||
* [简介](13.1_intro.md)
|
||||
|
||||
@@ -138,12 +138,14 @@ $ sysctl --system
|
||||
|
||||
为了让 kubelet 正确运行,我们需要对其进行一些必要的配置。
|
||||
|
||||
#### 修改 `kubelet.service`
|
||||
#### 修改 `kubelet.service`(可选:IPVS 模式)
|
||||
|
||||
> **注意**:kube-proxy 的 IPVS 模式已在 Kubernetes 1.35 中被标记为弃用;Kubernetes 1.36 文档仍将其列为已弃用模式,并推荐迁移到 nftables。新部署应使用默认的 iptables 模式或 nftables 模式(Kubernetes 1.33+ 稳定)。以下 IPVS 配置仅供旧环境参考。
|
||||
|
||||
`/etc/systemd/system/kubelet.service.d/10-proxy-ipvs.conf` 写入以下内容
|
||||
|
||||
```bash
|
||||
# 启用 ipvs 相关内核模块
|
||||
# 启用 ipvs 相关内核模块(已弃用,建议迁移至 nftables)
|
||||
|
||||
[Service]
|
||||
ExecStartPre=-/sbin/modprobe ip_vs
|
||||
@@ -172,21 +174,20 @@ $ sudo kubeadm init \
|
||||
--image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
|
||||
--pod-network-cidr 10.244.0.0/16 \
|
||||
--cri-socket unix:///run/containerd/containerd.sock \
|
||||
--v 5 \
|
||||
--ignore-preflight-errors=all
|
||||
--v 5
|
||||
```
|
||||
|
||||
* `--pod-network-cidr 10.244.0.0/16` 参数与后续 CNI 插件有关,这里以 `flannel` 为例,若后续部署其他类型的网络插件请更改此参数。
|
||||
|
||||
> 执行可能出现错误,例如缺少依赖包,根据提示安装即可。
|
||||
> 若 `kubeadm` 预检失败,应按提示修复缺失依赖、内核参数、swap 或运行时配置。实验环境确需忽略预检时,只忽略明确理解且可接受的单项检查,不建议使用 `--ignore-preflight-errors=all`。
|
||||
|
||||
执行成功会输出
|
||||
|
||||
```bash
|
||||
...
|
||||
[addons] Applied essential addon: CoreDNS
|
||||
I1116 12:35:13.270407 86677 request.go:538] Throttling request took 181.409184ms, request: POST:https://192.168.199.100:6443/api/v1/namespaces/kube-system/serviceaccounts
|
||||
I1116 12:35:13.470292 86677 request.go:538] Throttling request took 186.088112ms, request: POST:https://192.168.199.100:6443/api/v1/namespaces/kube-system/configmaps
|
||||
I1116 12:35:13.270407 86677 request.go:538] Throttling request took 181.409184ms, request: POST:https://<CONTROL_PLANE_HOST>:6443/api/v1/namespaces/kube-system/serviceaccounts
|
||||
I1116 12:35:13.470292 86677 request.go:538] Throttling request took 186.088112ms, request: POST:https://<CONTROL_PLANE_HOST>:6443/api/v1/namespaces/kube-system/configmaps
|
||||
[addons] Applied essential addon: kube-proxy
|
||||
|
||||
Your Kubernetes control-plane has initialized successfully!
|
||||
@@ -203,8 +204,8 @@ Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
|
||||
|
||||
Then you can join any number of worker nodes by running the following on each as root:
|
||||
|
||||
kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
|
||||
kubeadm join <CONTROL_PLANE_HOST>:6443 --token <TOKEN> \
|
||||
--discovery-token-ca-cert-hash sha256:<DISCOVERY_TOKEN_CA_CERT_HASH>
|
||||
```
|
||||
|
||||
#### node 工作节点
|
||||
@@ -216,12 +217,14 @@ $ systemctl enable containerd
|
||||
|
||||
$ systemctl start containerd
|
||||
|
||||
$ kubeadm join 192.168.199.100:6443 \
|
||||
--token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe \
|
||||
$ kubeadm join <CONTROL_PLANE_HOST>:6443 \
|
||||
--token <TOKEN> \
|
||||
--discovery-token-ca-cert-hash sha256:<DISCOVERY_TOKEN_CA_CERT_HASH> \
|
||||
--cri-socket unix:///run/containerd/containerd.sock
|
||||
```
|
||||
|
||||
其中 `<CONTROL_PLANE_HOST>`、`<TOKEN>` 和 `<DISCOVERY_TOKEN_CA_CERT_HASH>` 应使用你自己的 `kubeadm init` 输出,不要复用示例值。
|
||||
|
||||
### 14.1.7 查看服务
|
||||
|
||||
所有服务启动后,通过 `crictl` 查看本地实际运行的容器。这些服务大概分为三类:主节点服务、工作节点服务和其它服务。
|
||||
@@ -271,9 +274,9 @@ $ kubectl get node -o yaml | grep CIDR
|
||||
podCIDRs:
|
||||
```
|
||||
```bash
|
||||
# 注意:v0.28.2 为编写本文档时的最新版本,请根据需要替换为当前版本
|
||||
# 注意:以下以 v0.28.4 为示例;安装前请到 releases 页面核验当前版本
|
||||
# 参见 https://github.com/flannel-io/flannel/releases
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.2/Documentation/kube-flannel.yml
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.4/Documentation/kube-flannel.yml
|
||||
```
|
||||
|
||||
### 14.1.10 master 节点默认不能运行 pod
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
```bash
|
||||
# 安装 cri-dockerd
|
||||
# 注意:v0.3.24 为编写本文档时的最新版本,请根据需要替换为当前版本
|
||||
# 注意:以下以 v0.4.3 为示例;安装前请到 releases 页面核验当前版本和校验值
|
||||
# 参见 https://github.com/Mirantis/cri-dockerd/releases
|
||||
|
||||
$ cd /tmp
|
||||
$ wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.24/cri-dockerd-0.3.24.amd64.tgz
|
||||
$ tar xzvf cri-dockerd-0.3.24.amd64.tgz
|
||||
$ wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.3/cri-dockerd-0.4.3.amd64.tgz
|
||||
$ tar xzvf cri-dockerd-0.4.3.amd64.tgz
|
||||
$ sudo mv cri-dockerd/cri-dockerd /usr/local/bin/
|
||||
|
||||
# 下载并安装 systemd service 文件
|
||||
@@ -54,12 +54,12 @@ $ sudo /usr/local/bin/cri-dockerd --version
|
||||
|
||||
```bash
|
||||
# 安装 cri-dockerd
|
||||
# 注意:v0.3.24 为编写本文档时的最新版本,请根据需要替换为当前版本
|
||||
# 注意:以下以 v0.4.3 为示例;安装前请到 releases 页面核验当前版本和校验值
|
||||
# 参见 https://github.com/Mirantis/cri-dockerd/releases
|
||||
|
||||
$ cd /tmp
|
||||
$ wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.24/cri-dockerd-0.3.24.amd64.tgz
|
||||
$ tar xzvf cri-dockerd-0.3.24.amd64.tgz
|
||||
$ wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.4.3/cri-dockerd-0.4.3.amd64.tgz
|
||||
$ tar xzvf cri-dockerd-0.4.3.amd64.tgz
|
||||
$ sudo mv cri-dockerd/cri-dockerd /usr/local/bin/
|
||||
|
||||
# 下载并安装 systemd service 文件
|
||||
@@ -169,12 +169,14 @@ $ sysctl --system
|
||||
|
||||
为了让 kubelet 正确运行,我们需要对其进行一些必要的配置。
|
||||
|
||||
#### 修改 `kubelet.service`
|
||||
#### 修改 `kubelet.service`(可选:IPVS 模式)
|
||||
|
||||
> **注意**:kube-proxy 的 IPVS 模式已在 Kubernetes 1.35 中被标记为弃用;Kubernetes 1.36 文档仍将其列为已弃用模式,并推荐迁移到 nftables。新部署应使用默认的 iptables 模式或 nftables 模式(Kubernetes 1.33+ 稳定)。以下 IPVS 配置仅供旧环境参考。
|
||||
|
||||
`/etc/systemd/system/kubelet.service.d/10-proxy-ipvs.conf` 写入以下内容
|
||||
|
||||
```bash
|
||||
# 启用 ipvs 相关内核模块
|
||||
# 启用 ipvs 相关内核模块(已弃用,建议迁移至 nftables)
|
||||
|
||||
[Service]
|
||||
ExecStartPre=-/sbin/modprobe ip_vs
|
||||
@@ -198,22 +200,21 @@ $ sudo systemctl daemon-reload
|
||||
$ sudo kubeadm init --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
|
||||
--pod-network-cidr 10.244.0.0/16 \
|
||||
--cri-socket unix:///var/run/cri-dockerd.sock \
|
||||
--v 5 \
|
||||
--ignore-preflight-errors=all
|
||||
--v 5
|
||||
```
|
||||
|
||||
* `--cri-socket unix:///var/run/cri-dockerd.sock` 参数指定使用 cri-dockerd 作为容器运行时接口。
|
||||
* `--pod-network-cidr 10.244.0.0/16` 参数与后续 CNI 插件有关,这里以 `flannel` 为例,若后续部署其他类型的网络插件请更改此参数。
|
||||
|
||||
> 执行可能出现错误,例如缺少依赖包,根据提示安装即可。
|
||||
> 若 `kubeadm` 预检失败,应按提示修复缺失依赖、内核参数、swap 或运行时配置。实验环境确需忽略预检时,只忽略明确理解且可接受的单项检查,不建议使用 `--ignore-preflight-errors=all`。
|
||||
|
||||
执行成功会输出
|
||||
|
||||
```bash
|
||||
...
|
||||
[addons] Applied essential addon: CoreDNS
|
||||
I1116 12:35:13.270407 86677 request.go:538] Throttling request took 181.409184ms, request: POST:https://192.168.199.100:6443/api/v1/namespaces/kube-system/serviceaccounts
|
||||
I1116 12:35:13.470292 86677 request.go:538] Throttling request took 186.088112ms, request: POST:https://192.168.199.100:6443/api/v1/namespaces/kube-system/configmaps
|
||||
I1116 12:35:13.270407 86677 request.go:538] Throttling request took 181.409184ms, request: POST:https://<CONTROL_PLANE_HOST>:6443/api/v1/namespaces/kube-system/serviceaccounts
|
||||
I1116 12:35:13.470292 86677 request.go:538] Throttling request took 186.088112ms, request: POST:https://<CONTROL_PLANE_HOST>:6443/api/v1/namespaces/kube-system/configmaps
|
||||
[addons] Applied essential addon: kube-proxy
|
||||
|
||||
Your Kubernetes control-plane has initialized successfully!
|
||||
@@ -230,8 +231,8 @@ Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
|
||||
|
||||
Then you can join any number of worker nodes by running the following on each as root:
|
||||
|
||||
kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
|
||||
kubeadm join <CONTROL_PLANE_HOST>:6443 --token <TOKEN> \
|
||||
--discovery-token-ca-cert-hash sha256:<DISCOVERY_TOKEN_CA_CERT_HASH>
|
||||
```
|
||||
|
||||
#### node 工作节点
|
||||
@@ -239,10 +240,13 @@ kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
在 **另一主机** 重复 **部署** 小节以前的步骤,安装配置好 kubelet。根据提示,加入到集群。
|
||||
|
||||
```bash
|
||||
$ kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
|
||||
$ kubeadm join <CONTROL_PLANE_HOST>:6443 --token <TOKEN> \
|
||||
--discovery-token-ca-cert-hash sha256:<DISCOVERY_TOKEN_CA_CERT_HASH> \
|
||||
--cri-socket unix:///var/run/cri-dockerd.sock
|
||||
```
|
||||
|
||||
其中 `<CONTROL_PLANE_HOST>`、`<TOKEN>` 和 `<DISCOVERY_TOKEN_CA_CERT_HASH>` 应使用你自己的 `kubeadm init` 输出,不要复用示例值。
|
||||
|
||||
### 14.2.7 查看服务
|
||||
|
||||
所有服务启动后,查看本地实际运行的 Docker 容器。这些服务大概分为三类:主节点服务、工作节点服务和其它服务。
|
||||
@@ -288,9 +292,9 @@ $ kubectl get node -o yaml | grep CIDR
|
||||
podCIDRs:
|
||||
```
|
||||
```bash
|
||||
# 注意:v0.28.2 为编写本文档时的最新版本,请根据需要替换为当前版本
|
||||
# 注意:以下以 v0.28.4 为示例;安装前请到 releases 页面核验当前版本
|
||||
# 参见 https://github.com/flannel-io/flannel/releases
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.2/Documentation/kube-flannel.yml
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.4/Documentation/kube-flannel.yml
|
||||
```
|
||||
|
||||
### 14.2.10 master 节点默认不能运行 pod
|
||||
|
||||
@@ -17,7 +17,7 @@ K3s 的安装非常简单,官方提供了便捷的安装脚本。
|
||||
|
||||
#### 脚本安装
|
||||
|
||||
K3s 提供了极为便捷的安装脚本:
|
||||
K3s 提供了极为便捷的安装脚本。该命令会从网络下载脚本并直接交给 `sh` 执行,生产环境建议先下载审查脚本内容,并按官方文档固定版本或安装参数:
|
||||
|
||||
```bash
|
||||
curl -sfL https://get.k3s.io | sh -
|
||||
|
||||
@@ -29,14 +29,20 @@ $ kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-pro
|
||||
|
||||
### 14.7.3 登录
|
||||
|
||||
创建管理员服务账户并获取登录令牌:
|
||||
为历史 Dashboard 创建只读服务账户并获取短期登录令牌。不要为 Dashboard 创建 `cluster-admin` 绑定;如果确实需要临时管理员权限,应走单独的 break-glass 审批和审计流程。
|
||||
|
||||
```bash
|
||||
$ kubectl create sa dashboard-admin -n kubernetes-dashboard
|
||||
$ kubectl create sa dashboard-readonly -n kubernetes-dashboard
|
||||
|
||||
$ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
|
||||
$ kubectl create clusterrole dashboard-readonly \
|
||||
--verb=get,list,watch \
|
||||
--resource=pods,deployments,services,configmaps,namespaces,nodes
|
||||
|
||||
$ kubectl create token dashboard-admin -n kubernetes-dashboard
|
||||
$ kubectl create clusterrolebinding dashboard-readonly \
|
||||
--clusterrole=dashboard-readonly \
|
||||
--serviceaccount=kubernetes-dashboard:dashboard-readonly
|
||||
|
||||
$ kubectl create token dashboard-readonly -n kubernetes-dashboard --duration=1h
|
||||
```
|
||||
|
||||
将输出的令牌粘贴到登录页面,即可登录。
|
||||
|
||||
@@ -193,10 +193,10 @@ $ kubectl label pods -l app=nginx version=v1
|
||||
|
||||
```bash
|
||||
# 添加注解
|
||||
$ kubectl annotate pod my-pod description=”Production pod”
|
||||
$ kubectl annotate pod my-pod description="Production pod"
|
||||
|
||||
# 修改注解
|
||||
$ kubectl annotate pod my-pod description=”Staging pod” --overwrite
|
||||
$ kubectl annotate pod my-pod description="Staging pod" --overwrite
|
||||
|
||||
# 删除注解
|
||||
$ kubectl annotate pod my-pod description-
|
||||
@@ -240,8 +240,10 @@ $ kubectl config set-context --current --namespace=my-namespace
|
||||
# 显示集群信息
|
||||
$ kubectl cluster-info
|
||||
|
||||
# 显示完整的集群状态(包括所有组件)
|
||||
# 显示完整的集群状态(注:componentstatuses 自 1.19 起已弃用,建议使用下方替代命令)
|
||||
$ kubectl get componentstatuses
|
||||
# 推荐替代:
|
||||
$ kubectl get --raw='/readyz?verbose'
|
||||
```
|
||||
|
||||
### 14.8.15 version
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
你可以使用以下几种方式部署 Kubernetes,接下来的小节会对各种方式进行详细介绍。
|
||||
|
||||
* [使用 kubeadm 部署 (CRI 使用 containerd)](14.1_kubeadm.md)
|
||||
* Kubernetes 也支持 CRI-O 等符合 CRI 的运行时;本文以 containerd 为主线。
|
||||
* [使用 kubeadm 部署 (使用 Docker)](14.2_kubeadm-docker.md)
|
||||
* [在 Docker Desktop 使用](14.3_docker-desktop.md)
|
||||
* [Kind - Kubernetes IN Docker](14.4_kind.md)
|
||||
@@ -12,3 +13,8 @@
|
||||
* [一步步部署 Kubernetes 集群](14.6_systemd.md)
|
||||
* [部署 Dashboard](14.7_dashboard.md)
|
||||
* [Kubernetes 命令行 kubectl](14.8_kubectl.md)
|
||||
|
||||
除了上述方式,企业生产环境中还有两个常见的部署工具值得关注:
|
||||
|
||||
* **[KubeKey](https://github.com/kubesphere/kubekey)**:KubeSphere 社区开源的集群部署工具(CNCF 认证),支持一条命令从裸机部署到高可用集群,内置对 containerd 和多 Linux 发行版的适配,适合需要快速搭建私有化 Kubernetes 的团队。
|
||||
* **[RKE2](https://docs.rke2.io/)**:SUSE Rancher 出品的安全加固型 Kubernetes 发行版,默认启用 CIS 基准合规、SELinux 支持和 etcd 自动快照,适合对安全审计有严格要求的企业场景。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 15.1 简介
|
||||
|
||||
> **版本说明:** 本章内容基于 etcd 3.5 系列版本编写(当前最新为 v3.5.x)。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本信息。
|
||||
> **版本说明:** 本章内容基于 etcd 3.5 系列版本编写。官方维护最新两个次版本(当前为 3.5 和 3.6)。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本信息。
|
||||
|
||||
如图 15-1 所示,etcd 项目使用该标识。
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
`etcd` 基于 `Go` 语言实现,因此,用户可以从[项目主页](https://github.com/etcd-io/etcd)下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 `Docker` 镜像文件来体验。
|
||||
|
||||
> 注意:etcd 官方仅维护最新两个次版本(当前为 3.5 和 3.6)。本章示例基于 etcd `3.5.x` 版本编写。etcd 3.6.x 可用于新部署。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本。
|
||||
> 注意:etcd 官方仅维护最新两个次版本(当前为 3.5 和 3.6)。etcd 3.4 已于 2026 年 5 月结束支持(EOL),仍在使用 3.4 的用户应尽快升级。本章示例基于 etcd `3.5.x` 版本编写。etcd 3.6.x 可用于新部署。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本。
|
||||
|
||||
### 15.2.1 二进制文件方式下载
|
||||
|
||||
@@ -51,7 +51,7 @@ $ ETCDCTL_API=3 etcdctl member list
|
||||
$ ETCDCTL_API=3 etcdctl put testkey "hello world"
|
||||
OK
|
||||
|
||||
$ etcdctl get testkey
|
||||
$ ETCDCTL_API=3 etcdctl get testkey
|
||||
testkey
|
||||
hello world
|
||||
```
|
||||
@@ -96,5 +96,5 @@ $ brew install etcd
|
||||
|
||||
$ etcd
|
||||
|
||||
$ etcdctl member list
|
||||
$ ETCDCTL_API=3 etcdctl member list
|
||||
```
|
||||
|
||||
@@ -111,9 +111,11 @@ hello
|
||||
```
|
||||
支持的选项为
|
||||
|
||||
`--sort` 对结果进行排序
|
||||
`--sort-by` 指定排序字段(CREATE / KEY / MODIFY / VALUE / VERSION)
|
||||
|
||||
`--consistent` 将请求发给主节点,保证获取内容的一致性
|
||||
`--order` 指定排序顺序(ASCEND / DESCEND)
|
||||
|
||||
`--consistency` 指定一致性级别(`l` 线性一致,`s` 串行)
|
||||
|
||||
#### del
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3.6"
|
||||
services:
|
||||
|
||||
node1:
|
||||
image: quay.io/coreos/etcd:v3.5.17
|
||||
image: quay.io/coreos/etcd:v3.5.29
|
||||
volumes:
|
||||
- node1-data:/etcd-data
|
||||
expose:
|
||||
@@ -34,7 +34,7 @@ services:
|
||||
- docker-etcd
|
||||
|
||||
node2:
|
||||
image: quay.io/coreos/etcd:v3.5.17
|
||||
image: quay.io/coreos/etcd:v3.5.29
|
||||
volumes:
|
||||
- node2-data:/etcd-data
|
||||
networks:
|
||||
@@ -66,7 +66,7 @@ services:
|
||||
- docker-etcd
|
||||
|
||||
node3:
|
||||
image: quay.io/coreos/etcd:v3.5.17
|
||||
image: quay.io/coreos/etcd:v3.5.29
|
||||
volumes:
|
||||
- node3-data:/etcd-data
|
||||
networks:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
| 特性 | Google GKE | AWS EKS | Azure AKS |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **版本更新** | 最快,通常是 K8s 新特性的首发地 | 相对保守,注重稳定性 | 跟随社区,更新速度适中 |
|
||||
| **控制平面管理** | 全托管,自动升级,$0.10/h(有 Free Tier 抵扣)| 托管,$0.10/h | 全托管,控制平面免费 |
|
||||
| **控制平面管理** | 全托管,自动升级,$0.10/h(有 Free Tier 抵扣)| 托管,$0.10/h | 全托管;Free 层适合开发/测试,Standard/Premium 层默认包含 Uptime SLA |
|
||||
| **节点管理** | GKE Autopilot 模式完全托管节点 | Managed Node Groups 简化管理 | Virtual Machine Scale Sets |
|
||||
| **网络模型** | VPC-native, 性能优秀 | AWS VPC CNI, Pod 直接获取 VPC IP | Azure CNI (消耗 IP 多) 或 Kubenet |
|
||||
| **集成度** | 与 GCP 数据分析、AI 服务集成紧密 | 与 AWS IAM, ALB, CloudWatch 集成深度高 | 与 Active Directory, Azure DevOps 集成好 |
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Skopeo 是一个由 Red Hat 赞助开源的命令行工具,它可以在不需要运行容器守护进程(如 Docker Daemon)的前提下,对容器镜像进行极其高效的操作和管理,包括:检查、复制、删除和签名等操作。
|
||||
|
||||
Skopeo 最大的特点是其可以在”不将镜像拉取到本地”的情况下,直接在远端 Registry(镜像仓库)之间完成检查和搬运,从而大幅度节省带宽和磁盘空间。这也是它在容器运维和分发领域非常受欢迎的原因。
|
||||
Skopeo 最大的特点是其可以在“不将镜像拉取到本地”的情况下,直接在远端 Registry(镜像仓库)之间完成检查和搬运,从而大幅度节省带宽和磁盘空间。这也是它在容器运维和分发领域非常受欢迎的原因。
|
||||
|
||||
### 17.5.2 核心特性
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
Kubernetes 作为一个容器编排系统,为了屏蔽底层不同容器运行时的实现差异,引入了 CRI(Container Runtime Interface)标准。
|
||||
|
||||
- 早期版本中,Kubernetes 默认使用 docker 作为运行时,通过一个名为 `dockershim` 的桥接组件对接 Docker,Docker 再对接 containerd。
|
||||
- 随着 containerd 原生支持了 CRI 插件,Kubernetes 开始直接与 containerd 通信,去掉了 `dockershim` 和 `dockerd` 的中间层。这就是为什么从 Kubernetes 1.24+ 开始”弃用 Docker”引发了广泛关注,实际上 Kubernetes 只是弃用 `dockershim`,底层依然在使用从 Docker 基因中诞生的 containerd。参见 [Kubernetes 官方文档](https://kubernetes.io/docs/setup/production-environment/container-runtimes/#containerd)。
|
||||
- 随着 containerd 原生支持了 CRI 插件,Kubernetes 开始直接与 containerd 通信,去掉了 `dockershim` 和 `dockerd` 的中间层。这就是为什么从 Kubernetes 1.24+ 开始“弃用 Docker”引发了广泛关注,实际上 Kubernetes 只是弃用 `dockershim`,底层可以使用 containerd、CRI-O 等符合 CRI 的运行时。参见 [Kubernetes 官方文档](https://kubernetes.io/docs/setup/production-environment/container-runtimes/)。
|
||||
- containerd 2.0+ 移除了已弃用的 CRI v1alpha2 接口,仅保留 CRI v1(Kubernetes 1.26+ 仅支持 CRI v1)。如果集群中仍有依赖 CRI v1alpha2 的组件,升级 containerd 2.x 前需先完成迁移。containerd 2.3+ 是 2.x 系列首个 LTS 版本,支持从 1.7 LTS 直接升级,生产环境推荐使用。详见 [containerd 发布说明](https://github.com/containerd/containerd/releases)。
|
||||
|
||||
### 17.6.3 为什么直接使用 containerd?
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
尽管这种方式在性能和启动速度上拥有巨大优势,但也带来了一个显著的缺点:**隔离性(Isolation)不足**。如果某个容器内的恶意进程利用了宿主机内核的漏洞完成了越狱(Privilege Escalation),它将对整个宿主机以及其上运行的所有其他容器造成毁灭性威胁。
|
||||
|
||||
如果在公有云环境(多租户场景)或运行不可信的第三方代码时,共享内核显然是不够安全的。为了解决这一问题,社区推出了”安全容器(Secure Containers/Sandboxed Containers)”的概念。安全容器的核心理念是:提供类似虚拟机的强隔离性,同时保持类似容器的轻量、快速启动和标准化管理。
|
||||
如果在公有云环境(多租户场景)或运行不可信的第三方代码时,共享内核显然是不够安全的。为了解决这一问题,社区推出了“安全容器(Secure Containers/Sandboxed Containers)”的概念。安全容器的核心理念是:提供类似虚拟机的强隔离性,同时保持类似容器的轻量、快速启动和标准化管理。
|
||||
|
||||
### 17.7.2 什么是 Kata Containers?
|
||||
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
# 第十七章 容器其它生态
|
||||
|
||||
> **版本说明**:本章介绍的工具和运行时(Podman、Buildah、Skopeo、containerd、Kata Containers、gVisor、WasmEdge 等)都保持活跃的开发。建议:
|
||||
> **版本说明(核验日期:2026-05-16)**:本章介绍的工具和运行时(Podman、Buildah、Skopeo、containerd、Kata Containers、gVisor、WasmEdge 等)都保持活跃的开发。建议:
|
||||
> - 查阅各项目官方文档获取最新版本
|
||||
> - 在生产环境使用前验证版本兼容性
|
||||
> - 关注官方发布说明了解重大变更
|
||||
|
||||
本章将介绍 Docker 和 Kubernetes 之外的容器生态技术。
|
||||
|
||||
同时,Docker 自身的生态也在向云构建、AI 本地推理和企业级桌面安全扩展。当前需要额外关注:
|
||||
|
||||
* **Docker Model Runner**:在 Docker Desktop / Docker Engine 中管理、运行和服务本地 AI 模型,支持 OpenAI 与 Ollama 兼容 API,并可将 GGUF、Safetensors 等模型文件作为 OCI Artifact 管理。
|
||||
* **Docker Build Cloud**:通过远程 BuildKit 和共享构建缓存加速本地与 CI 构建,适合多平台镜像和团队共享缓存场景。
|
||||
* **Docker Offload**:把容器构建和运行卸载到云端,适合 VDI、受限本机或不支持嵌套虚拟化的开发环境。
|
||||
* **Hardened Docker Desktop / Enhanced Container Isolation (ECI)**:通过更强的命名空间隔离、敏感挂载保护和系统调用限制降低桌面容器逃逸风险。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [Fedora CoreOS 简介](17.1_coreos_intro.md)
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
## Fedora CoreOS
|
||||
|
||||
`CoreOS` 是一个专门为安全和大规模运行容器化工作负载而构建的新 Fedora 版本,它继承了 Fedora Atomic Host 和 CoreOS Container Linux 的优势。
|
||||
|
||||
`CoreOS` 的安装文件和运行依赖非常小,它提供了精简的 Linux 系统。它使用 Linux 容器在更高的抽象层来管理你的服务,而不是通过常规的包管理工具 `yum` 或 `apt` 来安装包。
|
||||
|
||||
同时,`CoreOS` 几乎可以运行在任何平台:`VirtualBox` `Amazon EC2` `QEMU/KVM` `VMware` `Bare Metal` 和 `OpenStack` 等。
|
||||
@@ -14,7 +14,7 @@ Docker 守护进程在启动容器时,会在后台为容器创建一套独立
|
||||
|
||||
尽管命名空间提供了很好的隔离性,但我们必须认识到:**所有的容器依然共享同一个宿主机的 Linux 内核**。
|
||||
|
||||
这意味着,一旦宿主机的内核存在提权漏洞(如著名的 Dirty COW 漏洞),攻击者有可能通过突破 Namespace 的限制,直接在内核层面执行恶意代码,从而实现”容器逃逸”。
|
||||
这意味着,一旦宿主机的内核存在提权漏洞(如著名的 Dirty COW 漏洞),攻击者有可能通过突破 Namespace 的限制,直接在内核层面执行恶意代码,从而实现“容器逃逸”。
|
||||
|
||||
> [!WARNING]
|
||||
> 为了缓解内核漏洞带来的威胁,生产环境务必保持宿主机 Linux 内核的及时修补与更新,或者借助诸如 gVisor、Kata Containers 等提供了独立内核的安全容器技术。同时,需要及时修补容器运行时(如 runC)的漏洞。2025 年 11 月披露的一系列 runC 容器逃逸漏洞(CVE-2025-31133、CVE-2025-52565、CVE-2025-52881)就表明,即使内核保持更新,运行时层的缺陷仍然可能导致容器隔离被突破。
|
||||
|
||||
@@ -50,13 +50,13 @@ dockerd \
|
||||
|
||||
### 18.3.3 Rootless 模式:非特权运行
|
||||
|
||||
为了从根本上解决“拥有 Docker socket 就是 root”的问题,Docker 在近年推出了 **Rootless 模式**。
|
||||
为了从根本上解决“拥有 Docker socket 就是 root”的问题,Docker 自 19.03 版本(2019 年)起提供了 **Rootless 模式**。
|
||||
|
||||
Rootless 模式允许在完全局限于非 `root` 用户的环境中运行 Docker 守护进程(`dockerd`)和容器。该模式利用了现代 Linux 内核的 User Namespace 技术和非特权网络命名空间实现。
|
||||
|
||||
#### 配置运行 Rootless Docker
|
||||
|
||||
要在非 root 环境中运行 Docker,只需要简单几步:
|
||||
要在非 root 环境中运行 Docker,需要先满足宿主机条件:安装 `newuidmap` / `newgidmap`,并在 `/etc/subuid` 与 `/etc/subgid` 中为该用户分配足够的 subordinate UID/GID。若系统级 Docker daemon 仍在运行,命令行也仍可能连到 rootful socket,因此应明确切换 Docker context 或 `DOCKER_HOST`。
|
||||
|
||||
1. 安装必要的依赖(通常是 `uidmap` 工具包以便系统支持 `newuidmap` 和 `newgidmap`):
|
||||
```bash
|
||||
@@ -68,9 +68,11 @@ $ sudo apt-get install uidmap
|
||||
$ su - testuser
|
||||
```
|
||||
|
||||
3. 运行 Docker 官方提供的 Rootless 安装脚本:
|
||||
3. 下载并检查 Docker 官方提供的 Rootless 安装脚本,确认来源和内容后再执行:
|
||||
```bash
|
||||
$ curl -fsSL https://get.docker.com/rootless | sh
|
||||
$ curl -fsSL https://get.docker.com/rootless -o install-rootless-docker.sh
|
||||
$ less install-rootless-docker.sh
|
||||
$ sh install-rootless-docker.sh
|
||||
```
|
||||
|
||||
4. 配置环境变量指向新创建的私有 socket:
|
||||
@@ -80,6 +82,9 @@ $ docker version
|
||||
```
|
||||
安装并暴露相应的配置后,该用户的环境将能独立启动属于他自己的 Docker Daemon。即使由于某些未知 0-Day 漏洞使得攻击者突破了容器,他们也只会受限于 `testuser` 这个非特权用户所在的有限系统环境内。
|
||||
|
||||
> [!NOTE]
|
||||
> Rootless 模式不是无条件替代 rootful Docker。端口绑定、网络、cgroup、存储驱动和系统服务自启动能力都受发行版、内核与 systemd 用户服务配置影响;生产环境应先验证具体工作负载,并用 `loginctl enable-linger <user>` 等方式显式配置开机自启动。
|
||||
|
||||
### 18.3.4 授权插件(Authorization Plugin)与访问策略
|
||||
|
||||
在企业环境中,对 Docker 守护进程的访问控制往往不仅限于文件系统权限,还需要更细粒度的授权策略。**Authorization Plugin** 机制允许在 API 层级对请求进行拦截和审批。
|
||||
@@ -110,4 +115,4 @@ $ docker version
|
||||
|
||||
### 18.3.5 结语
|
||||
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。而一旦基础系统条件允许,**毫不犹豫地在生产环境启用 Rootless 模式** 将是一项划算的安全加固选择。
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。在基础系统、网络和存储约束都验证通过后,Rootless 模式是一项值得优先评估的安全加固选择。
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
一个普通的 Linux 内核提供了 300 多个系统调用,而一个正常运行的容器化应用(例如 Nginx 服务)通常只会用到几十个调用,这就给攻击者留下了大量的闲置入口点来进行内核层的缓冲区溢出攻击。
|
||||
|
||||
Docker 默认启用了 Seccomp 并利用预置的 [默认配置文件](https://github.com/moby/moby/blob/master/profiles/seccomp/default.json) 将可以利用的系统调用缩减到了不足一半(默认禁用了 44 个危险的统调用,比如修改时区或重启系统)。
|
||||
Docker 默认启用了 Seccomp,并使用预置的 [默认配置文件](https://docs.docker.com/engine/security/seccomp/) 作为 allowlist:默认拒绝未显式允许的系统调用,并额外允许常见应用所需的调用。Docker 官方文档将其描述为默认禁用约 44 个系统调用(内核与 Docker 版本不同会有差异),例如与内核模块、系统重启或特权命名空间操作相关的调用。
|
||||
|
||||
如果你对应用的系统调用特征了如指掌,你可以为容器定制专属规则。
|
||||
|
||||
@@ -44,8 +44,8 @@ chmod: /etc/passwd: Operation not permitted
|
||||
|
||||
在开启了上述机制的机器上:
|
||||
|
||||
- **AppArmor**: Docker 为所有启动的应用加载了一个默认的 `docker-default` 模板文件,如果你的某些异常写行为(比如往特殊的内核心脏目录写入配置)不在 AppArmor 许可列表之上,即使拥有物理 Root,写入同样失败。
|
||||
- **SELinux**: 所有的 Docker 操作强制附加特殊上下文标识标签。就算把主机的 `/` 绑定给了黑客的某服务,黑客对不属于 Docker 可见的标签的文件进行读写尝试亦会被阻止。
|
||||
- **AppArmor**: 在启用 AppArmor 的系统上,Docker 默认为容器加载 `docker-default` profile;如果需要自定义策略,先用 `apparmor_parser` 加载 profile,再通过 `--security-opt apparmor=<profile>` 指定。
|
||||
- **SELinux**: 在启用 SELinux 集成的系统上,容器与挂载目录需要正确的 SELinux label。绑定挂载时常用 `:z` 表示多个容器共享,`:Z` 表示该挂载只给单个容器使用;不要对 `/home`、`/usr` 等系统目录随意使用 `:Z`,否则可能破坏宿主机标签。
|
||||
|
||||
如果想为某些受信任应用施加特定的外部强化文件策略,可以通过如下方法指派规则表:
|
||||
|
||||
@@ -53,6 +53,10 @@ chmod: /etc/passwd: Operation not permitted
|
||||
$ docker run --rm -it \
|
||||
--security-opt apparmor=custom-nginx-profile \
|
||||
nginx
|
||||
|
||||
$ docker run --rm -it \
|
||||
-v "$PWD/html":/usr/share/nginx/html:Z \
|
||||
nginx
|
||||
```
|
||||
|
||||
### 18.5.3 容器镜像漏洞静态扫描
|
||||
|
||||
@@ -20,7 +20,9 @@ Trivy 是由 Aqua Security 开发的开源漏洞扫描器,以其轻量级、
|
||||
|
||||
```bash
|
||||
# 安装 Trivy
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh -o install-trivy.sh
|
||||
less install-trivy.sh # 先审阅脚本内容
|
||||
sudo sh install-trivy.sh -b /usr/local/bin
|
||||
|
||||
# 扫描本地镜像
|
||||
trivy image nginx:latest
|
||||
@@ -58,7 +60,9 @@ Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。
|
||||
|
||||
```bash
|
||||
# 安装 Grype
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh -o install-grype.sh
|
||||
less install-grype.sh
|
||||
sudo sh install-grype.sh -b /usr/local/bin
|
||||
|
||||
# 扫描镜像
|
||||
grype docker:nginx:latest
|
||||
@@ -77,7 +81,7 @@ Snyk 提供了商业级的安全扫描服务,特别适合企业环境。
|
||||
|
||||
**特点:**
|
||||
|
||||
- 支持开源漏洞和许可证扫描
|
||||
- 支持开源漏洞、许可证扫描和修复建议
|
||||
- 与多个 Git 平台深度集成(GitHub、GitLab、Bitbucket)
|
||||
- 提供修复建议和自动化修复 PR
|
||||
- 支持 Kubernetes 部署后安全监控
|
||||
@@ -114,7 +118,7 @@ $ docker scout quickview myapp:latest
|
||||
| Docker 集成 | ✓(原生) | 需安装 | 需安装 | 需安装 |
|
||||
| 零依赖 | ✗ | ✓ | ✗ | ✗ |
|
||||
| 离线模式 | ✗ | ✓ | ✓ | ✗ |
|
||||
| 许可证扫描 | ✓ | ✗ | ✓ | ✓ |
|
||||
| 许可证扫描 | ✓ | ✓ | ✓ | ✓ |
|
||||
| 自动修复建议 | ✓ | ✗ | ✗ | ✓ |
|
||||
| 开源免费 | 部分 | ✓ | ✓ | 部分 |
|
||||
| IDE 集成 | ✓ | ✓ | ✓ | ✓ |
|
||||
@@ -130,7 +134,9 @@ Syft 是 Anchore 推出的专业 SBOM 生成工具。
|
||||
**安装:**
|
||||
|
||||
```bash
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh -o install-syft.sh
|
||||
less install-syft.sh
|
||||
sudo sh install-syft.sh -b /usr/local/bin
|
||||
```
|
||||
**生成 SBOM:**
|
||||
|
||||
@@ -234,8 +240,9 @@ cosign generate-key-pair
|
||||
**签名镜像:**
|
||||
|
||||
```bash
|
||||
# 使用私钥签名(推送到仓库前)
|
||||
cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
|
||||
# 先推送镜像,再使用不可变 digest 签名
|
||||
IMAGE_DIGEST="myregistry.com/myapp@sha256:<digest>"
|
||||
cosign sign --key cosign.key "$IMAGE_DIGEST"
|
||||
|
||||
# 系统会提示输入私钥密码
|
||||
```
|
||||
@@ -243,7 +250,7 @@ cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
|
||||
|
||||
```bash
|
||||
# 使用公钥验证
|
||||
cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
|
||||
cosign verify --key cosign.pub "$IMAGE_DIGEST"
|
||||
|
||||
# 输出结果示例
|
||||
# Verification successful!
|
||||
@@ -260,10 +267,10 @@ cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
|
||||
|
||||
```bash
|
||||
# 在 GitHub Actions 等 CI 中无需存储密钥
|
||||
cosign sign --yes myregistry.com/myapp:v1.0.0
|
||||
cosign sign --yes "$IMAGE_DIGEST"
|
||||
|
||||
# 验证时自动使用 OIDC 令牌验证身份
|
||||
cosign verify myregistry.com/myapp:v1.0.0 \
|
||||
cosign verify "$IMAGE_DIGEST" \
|
||||
--certificate-identity https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main \
|
||||
--certificate-oidc-issuer https://token.actions.githubusercontent.com
|
||||
```
|
||||
@@ -272,16 +279,13 @@ cosign verify myregistry.com/myapp:v1.0.0 \
|
||||
|
||||
> **注意:DCT 退役时间线**
|
||||
>
|
||||
> Docker 已宣布[退役 Content Trust](https://www.docker.com/blog/retiring-docker-content-trust/)。关键节点:
|
||||
> - 2025 年 8 月起:最早一批 DCT 签名证书开始过期
|
||||
> - 2025 年 9 月 30 日起:新注册表不可再启用 DCT
|
||||
> - **2028 年 3 月 31 日**:DCT 完全移除,所有 DCT 数据永久删除
|
||||
> Docker 已宣布[退役 Content Trust](https://www.docker.com/blog/retiring-docker-content-trust/),Docker Official Images 的部分 DCT 签名证书自 2025 年 8 月起已陆续过期;完整退役节奏应以 Docker 官方公告和你所使用的 registry 服务商文档为准。不要把云厂商特定日期直接当作 Docker 全局时间线。
|
||||
>
|
||||
> 建议新项目直接使用上文介绍的 **Cosign (Sigstore)** 进行镜像签名;现有 DCT 用户应尽早制定迁移计划。
|
||||
> 新项目应优先使用上文介绍的 **Cosign (Sigstore)** 或 registry 原生签名/证明能力;现有 DCT 用户应先盘点依赖、验证替代方案,再制定迁移计划。
|
||||
|
||||
Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的传统签名解决方案。
|
||||
|
||||
**启用 DCT:**
|
||||
**历史用法示例(不建议新项目采用):**
|
||||
|
||||
```bash
|
||||
# 在环境中启用 DCT
|
||||
@@ -301,8 +305,8 @@ docker push --disable-content-trust myregistry.com/myapp:v1.0.0
|
||||
# 首次推送时会提示创建 Delegation Key
|
||||
# 密钥存储在 ~/.docker/trust/private/root_keys/ 和 ~/.docker/trust/private/tuf_keys/
|
||||
|
||||
# 查看签名信息
|
||||
docker inspect --format='{{.RepoDigests}}' myregistry.com/myapp:v1.0.0
|
||||
# 查看 DCT/Notary 信任数据;RepoDigests 只是内容摘要,不等于签名验证
|
||||
docker trust inspect --pretty myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
### 18.6.4 供应链安全最佳实践
|
||||
@@ -316,27 +320,20 @@ RUN apt-get update && apt-get install -y curl
|
||||
|
||||
# ✓ 推荐:固定基础镜像版本和摘要
|
||||
FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e6e0e14...(完整 64 位哈希)
|
||||
RUN apt-get update && apt-get install -y curl=7.68.0-1ubuntu1
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
#### 2. 构建时扫描
|
||||
|
||||
在 Dockerfile 中集成安全扫描:
|
||||
在 CI/CD 构建阶段集成安全扫描,避免在 Dockerfile 里从分支 URL 下载并执行远程安装脚本:
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.26-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# 使用 Trivy 扫描源代码
|
||||
RUN apk add --no-cache curl && \
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin && \
|
||||
trivy fs . --exit-code 1 --severity HIGH,CRITICAL
|
||||
|
||||
RUN go build -o app .
|
||||
|
||||
FROM alpine:3.17@sha256:abcd1234...(请替换为实际完整的 64 位摘要哈希)
|
||||
COPY --from=builder /app/app /app
|
||||
```bash
|
||||
docker run --rm \
|
||||
-v "$PWD:/work" \
|
||||
-w /work \
|
||||
aquasec/trivy:latest \
|
||||
fs . --exit-code 1 --severity HIGH,CRITICAL
|
||||
```
|
||||
|
||||
#### 3. 运行时镜像扫描策略
|
||||
@@ -417,6 +414,7 @@ jobs:
|
||||
contents: read
|
||||
packages: write
|
||||
security-events: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -425,7 +423,11 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Build Docker image
|
||||
- name: Install Cosign
|
||||
if: github.event_name == 'push'
|
||||
uses: sigstore/cosign-installer@v3
|
||||
|
||||
- name: Build Docker image for scan
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
@@ -434,8 +436,8 @@ jobs:
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
- name: Run Trivy vulnerability scan
|
||||
# 安全提醒:2026 年 3 月 Trivy GitHub Actions 遭受供应链攻击,
|
||||
# 75 个版本标签被劫持。务必使用不可变的 commit SHA 引用,而非可变标签。
|
||||
# 安全提醒:2026 年 3 月 19 日 Trivy GitHub Actions 遭受供应链攻击,
|
||||
# 76 个版本标签被劫持。务必使用不可变的 commit SHA 引用,而非可变标签。
|
||||
# 使用前请到 https://github.com/aquasecurity/trivy-action/releases 核实 SHA 对应正确版本。
|
||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
|
||||
with:
|
||||
@@ -462,25 +464,27 @@ jobs:
|
||||
name: sbom
|
||||
path: sbom-cyclonedx.json
|
||||
|
||||
- name: Sign image with Cosign
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
- name: Login to Registry and Push
|
||||
if: github.event_name == 'push'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
if: github.event_name == 'push'
|
||||
id: build-push
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
- name: Sign image with Cosign
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-push.outputs.digest }}
|
||||
```
|
||||
|
||||
#### GitLab CI 工作流示例
|
||||
@@ -489,8 +493,8 @@ jobs:
|
||||
stages:
|
||||
- build
|
||||
- scan
|
||||
- sign
|
||||
- push
|
||||
- sign
|
||||
|
||||
variables:
|
||||
REGISTRY: registry.gitlab.com
|
||||
@@ -498,52 +502,57 @@ variables:
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
image: docker:<version>-cli@sha256:<docker-cli-digest>
|
||||
services:
|
||||
- docker:dind
|
||||
- name: docker:<version>-dind@sha256:<docker-dind-digest>
|
||||
script:
|
||||
- docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
|
||||
- docker save $IMAGE_NAME:$CI_COMMIT_SHA > image.tar
|
||||
|
||||
scan:trivy:
|
||||
stage: scan
|
||||
image: aquasec/trivy:latest
|
||||
image: aquasec/trivy:<version>@sha256:<trivy-digest>
|
||||
script:
|
||||
- trivy image --severity HIGH,CRITICAL --exit-code 1 docker-archive://image.tar
|
||||
allow_failure: false
|
||||
|
||||
scan:grype:
|
||||
stage: scan
|
||||
image: anchore/grype:latest
|
||||
image: anchore/grype:<version>@sha256:<grype-digest>
|
||||
script:
|
||||
- grype docker-archive://image.tar
|
||||
|
||||
generate:sbom:
|
||||
stage: scan
|
||||
image: anchore/syft:latest
|
||||
image: anchore/syft:<version>@sha256:<syft-digest>
|
||||
script:
|
||||
- syft docker-archive://image.tar -o cyclonedx > sbom.xml
|
||||
artifacts:
|
||||
reports:
|
||||
sbom: sbom.xml
|
||||
|
||||
sign:
|
||||
stage: sign
|
||||
image: gcr.io/projectsigstore/cosign:latest
|
||||
push:
|
||||
stage: push
|
||||
image: docker:<version>-cli@sha256:<docker-cli-digest>
|
||||
services:
|
||||
- name: docker:<version>-dind@sha256:<docker-dind-digest>
|
||||
script:
|
||||
- cosign sign --key $COSIGN_KEY $IMAGE_NAME:$CI_COMMIT_SHA
|
||||
- docker load < image.tar
|
||||
- echo "$REGISTRY_PASSWORD" | docker login --username "$REGISTRY_USER" --password-stdin "$REGISTRY"
|
||||
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
|
||||
- DIGEST=$(docker buildx imagetools inspect "$IMAGE_NAME:$CI_COMMIT_SHA" --format '{{.Manifest.Digest}}')
|
||||
- echo "$IMAGE_NAME@$DIGEST" > image-digest.txt
|
||||
artifacts:
|
||||
paths:
|
||||
- image-digest.txt
|
||||
only:
|
||||
- main
|
||||
|
||||
push:
|
||||
stage: push
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
sign:
|
||||
stage: sign
|
||||
image: gcr.io/projectsigstore/cosign:<version>@sha256:<cosign-digest>
|
||||
script:
|
||||
- docker load < image.tar
|
||||
- docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY
|
||||
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
|
||||
- cosign sign --key $COSIGN_KEY "$(cat image-digest.txt)"
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
## 本章小结
|
||||
|
||||
Docker 的安全性依赖于多层隔离机制的协同工作,同时需要用户遵循最佳实践。
|
||||
Docker 的安全性依赖于多层隔离机制的协同工作,同时需要用户遵循最佳实践。本章涵盖的核心安全维度包括:
|
||||
|
||||
| 维度 | 关键措施 |
|
||||
|------|---------|
|
||||
| **内核隔离** | Namespace 隔离进程/网络/文件系统,Cgroups 限制资源使用 |
|
||||
| **权限控制** | 非 root 运行、`--cap-drop ALL` 最小能力集、`--read-only` 只读根文件系统 |
|
||||
| **镜像安全** | 使用可信基础镜像、定期扫描漏洞(Trivy / Snyk)、启用 Docker Content Trust 签名验证 |
|
||||
| **运行时防护** | Seccomp 系统调用过滤、AppArmor / SELinux 强制访问控制 |
|
||||
| **网络隔离** | 自定义 bridge 网络隔离容器通信、限制容器对宿主机网络的访问 |
|
||||
|
||||
总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。
|
||||
|
||||
|
||||
@@ -160,10 +160,10 @@ $ docker compose up -d
|
||||
* **节点 CPU 使用率**:`100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)`
|
||||
* **节点内存使用率**:`(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100`
|
||||
* **节点磁盘空间使用率**:`(1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"})) * 100`
|
||||
* **容器 CPU**:`sum by (name) (rate(container_cpu_usage_seconds_total[5m]))`
|
||||
* **容器内存**:`sum by (name) (container_memory_working_set_bytes)`
|
||||
* **容器 CPU**:`sum by (namespace, pod, container) (rate(container_cpu_usage_seconds_total[5m]))`
|
||||
* **容器内存**:`sum by (namespace, pod, container) (container_memory_working_set_bytes)`
|
||||
|
||||
说明:不同版本的 cAdvisor/Docker 对 label 命名可能存在差异 (如 `name`、`container`、`container_name`),如果查询为空,建议先用 `label_values(container_cpu_usage_seconds_total, __name__)` 或在 Prometheus 的图形界面查看可用 label。
|
||||
说明:不同采集路径的 label 命名不同。Docker Compose 中独立部署的 cAdvisor 常见容器标签是 `name`;Kubernetes kubelet 的 `/metrics/cadvisor` 中,`container_cpu_usage_seconds_total` 等稳定指标使用 `container`、`pod`、`namespace`。如果查询为空,先直接查询 `container_cpu_usage_seconds_total` 样本并在 Prometheus 图形界面查看实际 label,不要假设存在 `container_name`。
|
||||
|
||||
#### Targets down 排错清单
|
||||
|
||||
@@ -245,7 +245,7 @@ receivers:
|
||||
|
||||
```yaml
|
||||
alertmanager:
|
||||
image: prom/alertmanager:v0.27.0
|
||||
image: prom/alertmanager:v0.32.0
|
||||
volumes:
|
||||
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
|
||||
ports:
|
||||
|
||||
@@ -22,7 +22,7 @@ ELK (Elasticsearch,Logstash,Kibana) 是目前业界最流行的开源日志
|
||||
```yaml
|
||||
services:
|
||||
elasticsearch:
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:9.3.3
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:9.4.0
|
||||
container_name: elasticsearch
|
||||
environment:
|
||||
- "discovery.type=single-node"
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
- logging
|
||||
|
||||
kibana:
|
||||
image: docker.elastic.co/kibana/kibana:9.3.3
|
||||
image: docker.elastic.co/kibana/kibana:9.4.0
|
||||
container_name: kibana
|
||||
environment:
|
||||
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
|
||||
|
||||
@@ -66,8 +66,11 @@ docker stats nginx redis
|
||||
# 一次性输出不进入交互模式
|
||||
docker stats --no-stream
|
||||
|
||||
# 指定刷新间隔(单位:秒,默认 1 秒)
|
||||
docker stats --no-stream --interval 2
|
||||
# 每 2 秒采样一次(docker stats 没有 --interval 选项)
|
||||
while true; do
|
||||
docker stats --no-stream
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# 格式化输出(使用 Go 模板)
|
||||
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" --no-stream
|
||||
@@ -100,6 +103,8 @@ done
|
||||
|
||||
cAdvisor 是 Google 开发的容器监控工具,提供比 `docker stats` 更详细的性能数据。
|
||||
|
||||
> **⚠️ 安全权衡提示**:下面的示例为简化部署使用了 `privileged: true`,与 [第 18 章](../18_security/README.md) 中“最小权限 / `cap_drop=all`”的原则相冲突。生产环境建议改为按需授予能力(如 `cap_add: [SYS_ADMIN]` 加 `device_cgroup_rules` 与精确的 `devices`、`volumes` 挂载),并将 cAdvisor 部署在独立的监控网络中。如何选择请参考 [18.4 节](../18_security/18.4_kernel_capability.md) 关于内核能力(capabilities)的细化授权。
|
||||
|
||||
**Docker Compose 部署 cAdvisor:**
|
||||
|
||||
```yaml
|
||||
@@ -180,6 +185,8 @@ services:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
networks:
|
||||
- monitoring
|
||||
|
||||
@@ -256,7 +263,7 @@ scrape_configs:
|
||||
|
||||
- job_name: 'docker'
|
||||
static_configs:
|
||||
- targets: ['localhost:9323']
|
||||
- targets: ['host.docker.internal:9323']
|
||||
```
|
||||
**常用的 Prometheus 查询(PromQL):**
|
||||
|
||||
@@ -274,7 +281,7 @@ rate(container_network_receive_bytes_total[5m]) / 1024 / 1024
|
||||
rate(container_network_transmit_bytes_total[5m]) / 1024 / 1024
|
||||
|
||||
# 容器磁盘读取速率(MB/s)
|
||||
rate(container_fs_io_current[5m]) / 1024 / 1024
|
||||
rate(container_fs_reads_bytes_total[5m]) / 1024 / 1024
|
||||
|
||||
# CPU 限流情况
|
||||
rate(container_cpu_cfs_throttled_seconds_total[5m])
|
||||
@@ -623,5 +630,6 @@ docker exec <container_id> ping 8.8.8.8
|
||||
docker inspect <container_id> | grep -A 10 NetworkSettings
|
||||
|
||||
# 解决方案:更换网络驱动或调整 MTU
|
||||
docker run --net=host myapp:latest # 使用宿主机网络(性能最佳)
|
||||
# host 网络可降低网络栈开销,但会放弃容器网络隔离;仅在明确接受安全边界变化时使用
|
||||
docker run --net=host myapp:latest
|
||||
```
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
- **容器监控**:以 Prometheus 为主,讲解如何采集和展示容器性能指标。
|
||||
- **日志管理**:以 ELK (Elasticsearch, Logstash, Kibana) 套件为例,介绍集中式日志收集平台。
|
||||
|
||||
为了让读者能够在生产环境中真正用起来,本章会补齐以下”最小闭环”:
|
||||
为了让读者能够在生产环境中真正用起来,本章会补齐以下“最小闭环”:
|
||||
|
||||
* 关键指标与日志的验证方法
|
||||
* 常见故障排查路径
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* **指标监控**:以 Prometheus + Grafana 为主,完成指标采集、存储与可视化。
|
||||
* **日志管理**:以 EFK/ELK 为例,完成容器日志的集中采集、检索与分析。
|
||||
|
||||
生产环境中,建议将”可观测性”当成一个完整闭环:**采集 -> 存储 -> 展示 -> 告警 -> 排错 -> 容量治理**。
|
||||
生产环境中,建议将“可观测性”当成一个完整闭环:**采集 -> 存储 -> 展示 -> 告警 -> 排错 -> 容量治理**。
|
||||
|
||||
## 扩展阅读:Docker 日志驱动
|
||||
|
||||
|
||||
+10
-10
@@ -25,7 +25,7 @@ Debian 是一个常用的基础镜像。
|
||||
```bash
|
||||
$ docker run -it debian bash
|
||||
root@668e178d8d69:/# cat /etc/issue
|
||||
Debian GNU/Linux 12
|
||||
Debian GNU/Linux 13
|
||||
```
|
||||
`Debian` 镜像很适合作为基础镜像,构建自定义镜像。
|
||||
|
||||
@@ -36,25 +36,25 @@ Debian GNU/Linux 12
|
||||

|
||||
|
||||
|
||||
`Ubuntu` 是一个以桌面应用为主的 `GNU/Linux` 操作系统,其名称来自非洲南部祖鲁语或豪萨语的 “ubuntu” 一词 (官方译名 “友帮拓”,另有 “吾帮托”、“乌班图”、“有奔头” 或 “乌斑兔” 等译名)。`Ubuntu` 意思是 “人性” 以及 “我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的 “仁爱” 思想。`Ubuntu` 基于 `Debian` 发行版和 `GNOME/Unity` 桌面环境,与 `Debian` 的不同在于它每 6 个月会发布一个新版本,每 2 年推出一个长期支持 **(Long Term Support,LTS)** 版本,一般支持 3 年时间。
|
||||
`Ubuntu` 是一个以桌面应用为主的 `GNU/Linux` 操作系统,其名称来自非洲南部祖鲁语或豪萨语的 “ubuntu” 一词 (官方译名 “友帮拓”,另有 “吾帮托”、“乌班图”、“有奔头” 或 “乌斑兔” 等译名)。`Ubuntu` 意思是 “人性” 以及 “我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的 “仁爱” 思想。`Ubuntu` 基于 `Debian` 发行版和 `GNOME/Unity` 桌面环境,与 `Debian` 的不同在于它每 6 个月会发布一个新版本,每 2 年推出一个长期支持 **(Long Term Support,LTS)** 版本;LTS 版本通常提供 5 年标准安全维护,Ubuntu Pro/ESM 可进一步延长安全覆盖。
|
||||
|
||||
#### 使用 Ubuntu 官方镜像
|
||||
|
||||
Ubuntu 是目前最流行的 Linux 发行版之一。
|
||||
|
||||
|
||||
下面以 `ubuntu:24.04` 为例,演示如何使用该镜像安装一些常用软件。
|
||||
下面以 `ubuntu:26.04` 为例,演示如何使用该镜像安装一些常用软件。
|
||||
|
||||
首先使用 `-ti` 参数启动容器,登录 `bash`,查看 `ubuntu` 的发行版本号。
|
||||
|
||||
```bash
|
||||
$ docker run -ti ubuntu:24.04 /bin/bash
|
||||
$ docker run -ti ubuntu:26.04 /bin/bash
|
||||
root@7d93de07bf76:/# cat /etc/os-release
|
||||
PRETTY_NAME="Ubuntu 24.04 LTS"
|
||||
PRETTY_NAME="Ubuntu 26.04 LTS"
|
||||
NAME="Ubuntu"
|
||||
VERSION_ID="24.04"
|
||||
VERSION="24.04 LTS (Noble Numbat)"
|
||||
VERSION_CODENAME=noble
|
||||
VERSION_ID="26.04"
|
||||
VERSION="26.04 LTS (Resolute Raccoon)"
|
||||
VERSION_CODENAME=resolute
|
||||
ID=ubuntu
|
||||
ID_LIKE=debian
|
||||
HOME_URL="https://www.ubuntu.com/"
|
||||
@@ -74,8 +74,8 @@ E: Unable to locate package curl
|
||||
|
||||
```bash
|
||||
root@7d93de07bf76:/# apt-get update
|
||||
Get:1 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB]
|
||||
Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
|
||||
Get:1 http://archive.ubuntu.com/ubuntu resolute InRelease [256 kB]
|
||||
Get:2 http://security.ubuntu.com/ubuntu resolute-security InRelease [126 kB]
|
||||
...
|
||||
Fetched 25.8 MB in 8s (3215 kB/s)
|
||||
Reading package lists... Done
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### 20.4.1 CentOS 系统简介
|
||||
|
||||
`CentOS` 和 `Fedora` 都是基于 `Redhat` 的常见 Linux 分支。`CentOS` 是目前企业级服务器的常用操作系统;`Fedora` 则主要面向个人桌面用户。
|
||||
`CentOS` 和 `Fedora` 都是基于 `Redhat` 的常见 Linux 分支。传统 `CentOS Linux` 曾是企业级服务器的常用操作系统,但相关 Docker 官方镜像已停止维护;新部署通常应评估 Rocky Linux、AlmaLinux、CentOS Stream 或直接使用 RHEL/UBI 等替代方案。`Fedora` 则主要面向个人桌面用户。
|
||||
|
||||

|
||||
|
||||
@@ -50,7 +50,7 @@ latest: Pulling from library/fedora
|
||||
Digest: sha256:64a02df6aac27d1200c2572fe4b9949f1970d05f74d367ce4af994ba5dc3669e
|
||||
Status: Downloaded newer image for fedora:latest
|
||||
[root@196ca341419b /]# cat /etc/redhat-release
|
||||
Fedora release 39 (Thirty Nine)
|
||||
Fedora release 43 (Forty Three)
|
||||
```
|
||||
|
||||
### 20.4.3 相关资源
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
本章示例中使用的操作系统镜像版本遵循以下原则:
|
||||
|
||||
- **Alpine、Debian、Ubuntu、CentOS** 等操作系统镜像采用大版本或次版本标签(如 `alpine:3.21`、`ubuntu:24.04`),避免使用 `latest` 标签确保构建的可再现性
|
||||
- **Alpine、Debian、Ubuntu、CentOS** 等操作系统镜像采用大版本或次版本标签(如 `alpine:3.21`、`ubuntu:26.04`),避免使用 `latest` 标签确保构建的可再现性
|
||||
- **OS 大版本保留**,以便获得最新的安全补丁和修复
|
||||
- 在生产环境中,建议根据实际需求选择合适的版本,并定期更新以获得安全修复
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user