Compare commits

..
154 Commits
Author SHA1 Message Date
yeasy 68fec82301 ci: sanitize auto-release artifact tag names 2026-06-24 15:39:30 +08:00
yeasy a601794cd4 ci: guard manual auto-release tag name 2026-06-21 15:53:28 +08:00
yeasy 2bcc83dcf4 ci: build and attach HTML reader to each release
Renders Mermaid to SVG via the workflow's Chrome, pandoc --mathml, assembles a
single self-contained responsive HTML reader, and attaches <repo>-<tag>.html to
the GitHub Release next to the PDF. Non-blocking (continue-on-error).
2026-06-21 10:14:47 +08:00
yeasy 9fdffa9d91 fix(content): harden Docker practice guide 2026-06-16 21:23:21 -07:00
yeasy f4e684afeb docs: update Fedora install support list 2026-06-16 19:32:29 -07:00
yeasy 01a6b2dccd fix(content): align compose demo Dockerfiles to COPY over ADD
The app and django compose demos used ADD for plain local files, but the
book's in-text versions of the same examples (11.3_usage.md, 11.6_django.md)
and its own guidance (7.2/7.3, appendix best_practices) all use COPY. Align
the demos with the documented practice.
2026-06-11 23:17:58 -07:00
yeasy 0cfd55af7b fix(content): repair Django tutorial crash and complete the hardening sweep
Follow-ups to the 9 secret-hardening commits (each verified against
docs.docker.com / vendor docs; one outright new bug found and fixed):

- 11.6: eb5e4397 changed settings.py to a hard os.environ lookup but the
  web service never receives POSTGRES_PASSWORD (only db does; DATABASE_URL
  is set but never read) -> step-6 'docker compose up' crashed with
  KeyError. Pass the var to web; harden the leftover literal password in
  the 配置详解 snippet that contradicted the new guidance two lines down;
  blank line after the inserted sentence (bold heading merged into the
  paragraph); dev/prod table no longer claims dev uses 明文 passwords
- 11.8: FAQ still told readers to check passwords in .env after the same
  file banned passwords in .env -> point at secrets/db_password.txt;
  backup sidecar env vars updated to tiredofit/db-backup 4.x interface
  (DB01_* + DB01_PASS_FILE + DB01_BACKUP_INTERVAL - the unprefixed DB_*
  names are ignored by current :latest; verified against upstream README)
- demo/wordpress: compose now references secrets files that ship nowhere
  -> add README with the creation commands from 11.8; demo/django: align
  with the hardened 11.6 (env-injected password, passed to web too)
- 04_image multistage demos: go build without go.mod fails on module-mode
  Go (reproduced by reviewer on go1.26) -> add 'go mod init helloworld'
  matching the 7.17 doc pattern in all three Dockerfiles
- 21.7: init script reworked init-db.sql -> init-db.sh per the official
  image's env-reading .sh hook - removes the baked 'secure_password' AND
  the CREATE DATABASE myappdb collision with POSTGRES_DB that aborted
  first-boot init (ON_ERROR_STOP); compose passes APP_DB_PASSWORD;
  microservices init.sql mount annotated schema-only (POSTGRES_USER:
  appuser would collide with CREATE USER); Dockerfile-redis healthcheck
  now authenticates via REDISCLI_AUTH read from redis.conf (plain
  redis-cli ping gets NOAUTH against requirepass - same class as the
  compose sibling eb5e4397 already fixed); dev-container dev/dev creds
  annotated local-only
- 19.3: Grafana admin password 'admin' sat directly under the newly added
  security warning -> env-injected like the rest of the stack
2026-06-10 12:06:57 -07:00
yeasy eb5e4397e8 docs: remove hardcoded compose secrets 2026-06-08 16:16:36 -07:00
yeasy 070d4d6d69 fix(content): harden secret handling examples 2026-06-06 00:43:52 -07:00
yeasy 67d5fc775a fix(content): harden Compose credential examples 2026-06-04 01:02:59 -07:00
yeasy 130d03bf65 fix(content): harden dashboard and etcd examples 2026-06-03 00:40:40 -07:00
yeasy 8dd6a556c8 fix(content): refresh DCT and monitoring safety guidance 2026-06-02 00:48:00 -07:00
yeasy 3c1720ccc9 应用专业编辑审查(复核续):修复确定性引用/链接/口径等 1 处 2026-06-01 21:04:00 -07:00
yeasy 6fc032f7d6 应用专业编辑审查:修复版本/引用/技术准确性等 3 处 2026-06-01 11:11:28 -07:00
yeasy 1cdd3c582a fix(content): harden Docker examples 2026-06-01 10:33:50 -07:00
yeasy 094965e039 修复编辑问题:错别字/语病/术语/标点等 25 处(自动审校) 2026-05-31 22:20:50 -07:00
yeasy 48e86b7bec fix(appendix): correct .dockerignore typo in image-slimming FAQ 2026-05-28 11:38:28 -07:00
yeasy 9230b49b6b fix(04): replace deprecated openjdk base image with eclipse-temurin and fix 地 typo 2026-05-28 11:38:28 -07:00
yeasy 2185211041 fix(07): note FROM uses pre-FROM ARG, not ENV, for variable substitution 2026-05-28 11:38:27 -07:00
yeasy f09e800020 fix(content): harden copy-paste safety examples 2026-05-27 18:17:24 -07:00
yeasy 3a9ee19d22 docs(content): refresh Kubernetes helper versions 2026-05-26 00:45:20 -07:00
yeasy ea26f96297 fix(content): remove demo registry credential 2026-05-25 01:13:10 -07:00
yeasy 30f26d9195 chore(17): remove obsolete coreos_README.md leftover
This 7-line file was never in SUMMARY.md and its content is a strict
subset of the current 17.1_coreos_intro.md. It looks like a draft
that survived the chapter rename to NN.M_topic.md convention.
Removed so the directory only contains files reachable from the ToC.
2026-05-24 12:56:55 -07:00
yeasy fb361bb1f0 fix(appendix): use H2 for 附录七 to match sibling appendix files
The other appendix entries (附录四 best_practices, 附录五 debug,
附录六 resources, 附录八 learning_roadmap) all use H2. glossary.md
was the lone H1, which broke the table-of-contents nesting in
GitBook. Demoted to H2 to align.
2026-05-24 01:03:34 -07:00
yeasy 036f0486db fix(content): tighten safety guidance 2026-05-24 00:57:03 -07:00
yeasy 28c23d003e fix(content): harden Docker examples 2026-05-23 21:28:59 -07:00
yeasy 6a55219310 fix(11.3): use COPY (not ADD) in Flask/Redis intro Dockerfile
§7.3 of this book explicitly recommends COPY over ADD for simple
file copies ("在大多数情况下,你应该使用 COPY,而不是 ADD"). The intro
Compose example showed ADD without needing tar extraction or URL
download, contradicting the canonical guidance. Switched to COPY
so the first Dockerfile readers see matches the rule the book
teaches a few chapters later.
2026-05-23 21:27:01 -07:00
yeasy 8f4d88e350 docs: refine Buildx guidance 2026-05-22 07:58:38 -07:00
yeasy 7f83abc53b fix(content): correct Docker Engine 29.0.0 date and align login-action version
Docker Engine 29.0.0 was released 2025-11-10 per docs.docker.com release
notes, not 2025-11-11 (off by one day). Also bring docker/login-action
reference in 18.6 up to v4 to match the 21.2 example (v4 has been current
since 2026-03-04).
2026-05-22 03:19:37 -07:00
yeasy ec0fa15835 docs(content): harden Kubernetes and supply-chain examples 2026-05-22 00:53:38 -07:00
yeasy 8b9e4518c8 docs(content): add Mac alternatives, K8s transition guide, CI/CD registry push example
- Add OrbStack/Colima comparison table to Mac install chapter (3.7.4)
- Add Docker→K8s concept mapping paragraph to Ch13 intro
- Add KubeKey/RKE2 deployment tool notes to Ch14
- Add production image checklist to Dockerfile chapter summary
- Add build-and-push-to-registry workflow example to GitHub Actions section
- Expand Ch18 security summary with dimension table
2026-05-21 21:33:58 -07:00
yeasy dae0af9ae7 fix(content): DCT expiry tense + bundle buildx --check additions 2026-05-21 20:49:42 -07:00
yeasy 10b09f35eb fix(content): update DCT expiry tense and prefer named multistage COPY 2026-05-21 20:49:19 -07:00
yeasy e17bef96d2 docs(content): update Compose and safety guidance 2026-05-21 20:13:39 -07:00
yeasy a3567ff6a0 docs: use digest-based cosign signing 2026-05-21 19:14:33 -07:00
yeasy 9ef842ebb3 docs: update distro caveats 2026-05-21 18:25:54 -07:00
yeasy 2e625a3cdf fix(content): harden install and security guidance 2026-05-21 01:23:44 -07:00
yeasy d47afa7e75 docs: harden Docker practice security examples 2026-05-20 15:58:46 -07:00
yeasy 1b651e5f8c fix(content): refresh Docker and Kubernetes guidance 2026-05-20 09:16:36 -07:00
yeasy e91fe87822 fix(content): harden kubernetes and signing examples 2026-05-20 08:49:28 -07:00
yeasy bb97d5a46a fix(13.2): remove incorrect "Node lifecycle" (Pending/Running/Terminated)
The "节点周期" subsection listed `Pending`/`Running`/`Terminated` as
node phases, but those are **Pod** phases (pod.status.phase). Kubernetes
nodes use Conditions (Ready/MemoryPressure/DiskPressure/PIDPressure)
not phases; there is no "Terminated" node state. Removed the
misleading subsection and clarified the surviving "节点状态" section
with an explicit note distinguishing Pod phases from node conditions,
and added the eviction behavior when a node becomes Unknown.
2026-05-20 08:37:43 -07:00
yeasy 1f69884c8f Fix Chinese quote formatting 2026-05-20 08:02:42 -07:00
yeasy 4f92b3aa70 fix(19.3): add security trade-off note for cAdvisor privileged: true
The cAdvisor compose examples in 19.3.3 use `privileged: true`, which
contradicts the minimum-privilege / cap_drop=all guidance in chapter 18.
Add an explicit trade-off note before the first cAdvisor snippet
explaining the inconsistency and pointing to 18.4 for capability-based
hardening alternatives (cap_add: [SYS_ADMIN] + device_cgroup_rules
instead of full privileged mode).

This addresses the Round 1 review finding about pedagogical conflict
between the monitoring and security chapters.
2026-05-20 00:18:37 -07:00
yeasy 58504e9316 fix(review-fixes): surgical content corrections from web-verified library deep review 2026-05-19 19:45:02 -07:00
yeasy 4075330dba Fix architecture mermaid and MySQL version 2026-05-19 18:43:11 -07:00
yeasy e6bf228066 docs: update image signing and login guidance 2026-05-19 15:29:26 -07:00
yeasy 1b15b65bc5 Clarify AKS pricing tiers 2026-05-19 08:20:49 -07:00
yeasy 26da467052 docs: link deployment engineering guide 2026-05-18 22:37:02 -07:00
yeasy 7abaff237a test: add project rules check 2026-05-18 22:37:02 -07:00
yeasy 1c4e0538d8 Fix CI PDF order 2026-05-18 08:06:51 -07:00
yeasy 0b8f6e9b60 Refresh metadata and workflows 2026-05-18 07:38:58 -07:00
yeasy 5650315cb4 Remove demo TLS key 2026-05-17 20:28:01 -07:00
yeasy e21794ebde Fix stale image facts 2026-05-17 20:28:01 -07:00
yeasy 78ca8f6d19 Refresh Docker ecosystem 2026-05-16 14:09:31 -07:00
yeasy 1ba904a9ff Fix markdown format issues 2026-05-15 09:58:19 -07:00
yeasy 705d162f05 Fix image docs typos 2026-05-15 09:16:33 -07:00
yeasy 92be0050fd Fix docker debug note, Go modules, Compose V2, CentOS Quay migration 2026-05-15 08:11:38 +00:00
yeasy a20d1b19c4 Fix 3 broken external links in appendix 2026-05-14 02:27:32 +00:00
yeasy 9f481e88ca Fix go mod, Docker Hub rate limit, Compose verbose, docker debug, htpasswd security 2026-05-13 08:30:20 +00:00
yeasy ef5a97fa09 Fix VirtioFS note, cri-socket, componentstatuses, ES version and typo 2026-05-13 08:26:24 +00:00
yeasy 3c5c5911b0 Fix nginx version, IPVS removal, cgroups v2 and Redis config 2026-05-13 08:22:20 +00:00
yeasy e2742313f2 Fix typo in Fedora install guide 2026-05-08 21:20:03 +00:00
yeasy 2cea196860 Replace chromium-browser snap with setup-chrome 2026-05-08 04:19:18 +00:00
yeasy 13fc8b34f0 Explain why docker run overrides crashing CMD 2026-05-08 04:13:09 +00:00
yeasy 29742c8f74 Clarify interactive debug uses new container 2026-05-08 04:10:38 +00:00
yeasy 7cae0b6bb3 Fix deprecated TLS protocols and mongo CLI 2026-05-03 15:20:57 +00:00
yeasy 10381deee4 Add healthcheck to Rails Compose example 2026-05-03 05:23:12 +00:00
yeasy 625d209fa8 Fix Docker Engine 29 release date and Rootless mode history 2026-05-02 22:26:19 +00:00
yeasy b148d9efa9 Update nginx to 1.30 stable, add IPVS deprecation note 2026-05-02 18:18:48 +00:00
yeasy 4cb91a75f3 Update etcd cluster demo to v3.5.29, Node to 22 LTS 2026-05-02 16:16:59 +00:00
yeasy bf3107b775 Update MySQL 8.0 to 8.4 LTS, fix Trivy tag count 2026-05-02 15:22:58 +00:00
yeasy 7e3f90b522 Update Node base images to 22 LTS 2026-05-01 10:24:43 +00:00
yeasy e6527ae769 Fix Docker Engine 29 release date 2026-05-01 07:17:56 +00:00
yeasy 9c378b1ef9 Use straight quotes in kubectl annotate examples 2026-04-30 19:18:49 +00:00
yeasy 340c8c9e61 Document ipvlan driver and update etcdctl v3 options 2026-04-30 09:20:59 +00:00
yeasy 89c2690a62 Correct Docker Engine 29 release date 2026-04-29 10:24:06 +00:00
yeasy c554799b08 Restore nginx 1.30 stable references 2026-04-29 07:53:31 +00:00
yeasy 99c56217f5 Fix Chinese curly quote direction 2026-04-29 05:21:02 +00:00
yeasy 9c98e35c62 Fix nginx version to 1.28 stable 2026-04-28 16:15:39 +00:00
yeasy 0e0afbd4d3 Update nginx to 1.30 and version references 2026-04-28 14:15:13 +00:00
yeasy 30f0115cb9 Update nginx, OS, Buildx, etcd and K8s refs 2026-04-28 12:22:57 +00:00
yeasy 62f48c1417 Update nginx, Debian, Ubuntu, Fedora, Docker versions 2026-04-28 11:14:55 +00:00
yeasy fab4e41587 Update OS examples to Debian 13, Ubuntu 26.04, Fedora 43 2026-04-28 09:24:17 +00:00
yeasy 229aec2f1e Update Kubernetes node status conditions terminology 2026-04-28 09:24:17 +00:00
yeasy 8ebf284f9e Update nginx references from 1.25 to 1.30 2026-04-28 09:24:03 +00:00
yeasy a89f7285c7 Fix typos and update Docker Hub limits and versions 2026-04-28 09:15:40 +00:00
yeasy 15c7fe1dc2 Update Docker Hub rate limits and version refs 2026-04-28 08:20:21 +00:00
yeasy 4d1e323faf Fix seccomp typo, postgres path and DCA exam details 2026-04-28 04:21:10 +00:00
yeasy 16203c5018 Complete Dockerfile instruction reference list 2026-04-27 23:17:39 +00:00
yeasy 3d3befa16a Add ipvlan driver and update EKS pricing 2026-04-27 22:45:17 +00:00
yeasy 09fd556c18 Refresh image CLI docs 2026-04-27 09:15:19 -07:00
yeasy 37e376d578 Fix mongosh, DCA price, compose healthcheck and cleanup 2026-04-27 14:17:57 +00:00
yeasy 04fd53ea3c Update Docker image tags and etcd commands 2026-04-27 11:18:08 +00:00
yeasy b1cd2f0878 Fix Docker Hub rate limits and etcdctl API version 2026-04-27 05:13:02 +00:00
yeasy e416a1be7e Fix Docker Hub rate limits, DCT timeline, image tags, etcd and Alertmanager 2026-04-27 01:15:52 +00:00
yeasy e406ed9185 Update Gateway API docs and image security practices 2026-04-26 00:18:39 +00:00
yeasy c36c420c7e Add nftables support and Time namespace documentation 2026-04-26 00:18:39 +00:00
yeasy 72513eb673 更新 Namespace/Gateway API/nftables/DCT 退役时间线
- ch12: 添加 TIME namespace (Linux 5.6+),内核 namespace 类型从 7 更新为 8
- ch12: 补充 Docker Engine v29.x 实���性 nftables 支持
- ch13: Ingress-NGINX 退役通知,添加 Gateway API 推荐方案和示例
- ch13: 添加 Pod Security Standards 章节(替代已移除的 PSP)
- ch18: 补充 DCT 退役时间线(2028-03-31 完全移除)和迁移建议
2026-04-26 00:12:59 +00:00
yeasy 8ea52620cc Update Prometheus to v3.11.2, fix etcdctl version 2026-04-25 22:39:33 +00:00
yeasy 22dd236122 Fix network IPs, compose healthcheck, update GH Actions versions 2026-04-25 21:11:50 +00:00
yeasy 98f4f7b1e5 Add official doc links to install guides 2026-04-25 21:11:50 +00:00
yeasy 87bb4b2ceb Add version notes and image tag best practices 2026-04-25 21:11:50 +00:00
yeasy dad26ccb28 Update docker0 default subnet to 172.17.0.0/16 2026-04-25 21:03:39 +00:00
yeasy 84a801f3ac Document depends_on condition and healthcheck 2026-04-25 21:03:39 +00:00
yeasy 420a5776ce Accurate cgroup v2 description, update Actions versions 2026-04-25 20:42:35 +00:00
yeasy b2839f735c Fix broken code block in laravel multistage Dockerfile 2026-04-25 20:42:18 +00:00
yeasy 98e299a38e Add version notes and official doc links 2026-04-25 15:58:42 +00:00
Baohua Yang aa204fb454 chore: lint cleanup and version corrections
- Accept benign linter changes (version notes, explicit tags, formatting)
- Fix incorrect version downgrades introduced by linter:
  - golang:1.22→1.26 (restored)
  - rust:1.82→1.95 (restored)
- 23 files updated
2026-04-25 15:58:27 +00:00
yeasy 1e9cdeea3f Update Grafana to v13, add version notes 2026-04-25 15:50:13 +00:00
yeasy 515ba9f64a Add blank lines before lists per CommonMark 2026-04-25 15:13:27 +00:00
yeasy 9abc1cbb69 Update Kubernetes to v1.36, build-push-action to v7 2026-04-25 15:10:51 +00:00
yeasy 839a63f5af Update versions and fix formatting issues 2026-04-25 15:10:43 +00:00
yeasy 20a3479f8a Add Docker Scout, remove deprecated type_name 2026-04-25 15:02:24 +00:00
yeasy 52329fee5a Update etcd to v3.5.29 2026-04-25 15:00:47 +00:00
yeasy 8093b198ce Update node-exporter to v1.11.1, fcct to butane 2026-04-25 14:58:40 +00:00
yeasy 77a537df54 Add blank lines before lists per CommonMark 2026-04-25 14:57:09 +00:00
yeasy e414d9475b Update containerd config path for 2.x 2026-04-25 14:22:55 +00:00
yeasy 037591e5af Update content and fix issues 2026-04-25 02:14:58 +00:00
yeasy 94f74fc86e Clarify image build semantics 2026-04-24 10:51:49 -07:00
yeasy 4b44d64cd8 Fix straight quotes to curly quotes in mirror doc 2026-04-24 13:24:52 +00:00
yeasy 49a85c802e Fix Ubuntu codenames and containerd LTS description 2026-04-24 03:16:05 +00:00
yeasy 2a7f7d9a3d Fix apt cache cleanup path in Dockerfile example 2026-04-23 13:16:21 -07:00
yeasy 544ede8498 Pin Prometheus and Grafana image versions 2026-04-22 12:24:31 -07:00
yeasy 54a9a6e55b Add runC CVEs and AuthZ plugin guidance 2026-04-22 12:24:31 -07:00
yeasy 27617ea619 Add section numbers to ecosystem headings 2026-04-22 12:24:30 -07:00
yeasy 69fc2234d0 Update nginx version and K8s dashboard date 2026-04-22 12:24:30 -07:00
yeasy ac92e6c536 Fix Debian dates and FAQ template syntax 2026-04-22 08:43:48 -07:00
yeasy 1fc64ab875 Refresh install guidance
# Conflicts:
#	03_install/3.1_ubuntu.md
#	03_install/3.2_debian.md
#	03_install/3.3_fedora.md
#	03_install/3.9_mirror.md
2026-04-22 08:24:38 -07:00
yeasy c9c72618c3 Refresh k8s docker versions and references 2026-04-21 20:57:33 -07:00
yeasy 4b93651989 Refine Docker concepts 2026-04-21 14:39:41 -07:00
yeasy b3d1508310 Add new content and update versions 2026-04-19 22:35:33 -07:00
yeasy 1d780f70c5 Drop legacy plugins 2026-04-19 20:14:36 -07:00
yeasy ff48ac79ee Clarify intro chapter 2026-04-18 20:25:29 -07:00
yeasy 077e55f494 Update software versions and fix security refs 2026-04-18 19:04:14 -07:00
yeasy 1bed644e5e Fix mermaid syntax and update K8s taint labels 2026-04-18 15:17:56 -07:00
yeasy da5867c921 Update Kind v0.31.0 and Flannel v0.28.2 2026-04-18 13:31:43 -07:00
yeasy 407d508590 Restructure README with badges and cover 2026-04-17 21:51:38 -07:00
yeasy 6fcb74bccc Add Ubuntu 20.04 EOL exact date 2026-04-17 21:19:32 -07:00
yeasy d81405a807 Update versions and fix stale data 2026-04-17 21:17:12 -07:00
github-actions[bot]andGitHub 983e7c18c3 Merge pull request #564 from yeasy/dependabot/github_actions/dependencies-8fe05ed821
chore(deps): bump the dependencies group with 2 updates
2026-04-15 18:46:57 +00:00
dependabot[bot]andGitHub 9e194b9a74 chore(deps): bump the dependencies group with 2 updates
Bumps the dependencies group with 2 updates: [softprops/action-gh-release](https://github.com/softprops/action-gh-release) and [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata).


Updates `softprops/action-gh-release` from 2 to 3
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

Updates `dependabot/fetch-metadata` from 2 to 3
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dependencies
- dependency-name: dependabot/fetch-metadata
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-15 18:46:44 +00:00
yeasy 6b2ebd12ac Fix Chinese curly quotes in prose text 2026-04-14 20:29:35 -07:00
yeasy f86e3567e8 Fix figure caption punctuation and table formatting 2026-04-13 18:37:00 -07:00
yeasy 2dacddb999 Fix figure caption format 2026-04-09 09:02:44 -07:00
yeasy 422123dd70 Add section numbering and archive notice 2026-04-08 22:40:15 -07:00
yeasy adee45f7bc Fix bash comment style to single hash 2026-04-08 22:39:51 -07:00
yeasy 04b81a8c05 Fix mdpress port 4000 to 9000 2026-04-05 13:39:46 -07:00
yeasy e85ca7a11e Fix typo in offline install image alt text 2026-04-05 12:59:09 -07:00
yeasy 66905627b8 Remove time annotation in install docs 2026-04-05 12:58:42 -07:00
yeasy aec453b9bb Remove duplicate release-pdf workflow 2026-04-05 08:55:52 -07:00
yeasy 565b40ab0b Add release-pdf CI workflow for automated PDF builds 2026-04-05 08:29:11 -07:00
yeasy 50fe8ebbbb Replace defunct AtomHub mirror with docker.1ms.run 2026-04-05 08:16:08 -07:00
yeasy c84927c196 ci: add auto-release.yml, remove release-pdf.yml, limit CI trigger to master 2026-04-05 07:57:56 -07:00
Baohua Yang 2b0c00c5e5 Add recommended reading paths table to README 2026-04-04 22:31:23 -07:00
164 changed files with 1835 additions and 881 deletions
+1 -4
View File
@@ -11,12 +11,9 @@
"forwardPorts": [
4000
],
"runArgs": [
"--cap-add=SYS_ADMIN"
],
"postStartCommand": [
"sh",
"-cx",
"pwd ; cd /workspaces/docker_practice ; mkdir -p ${PWD}/node_modules; mkdir -p ${PWD}/_book; mount --bind /srv/gitbook/node_modules ${PWD}/node_modules ; mount --bind /mnt ${PWD}/_book"
"pwd ; cd /workspaces/docker_practice ; mkdir -p ${PWD}/node_modules ${PWD}/_book"
]
}
+64 -10
View File
@@ -15,37 +15,91 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Check project rules
run: python3 check_project_rules.py
- name: Check release metadata
run: npm test
- name: Install Chromium and CJK fonts
id: setupchrome
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
- name: Extract tag name
id: tag
run: echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
run: |
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
tag_name="${GITHUB_REF#refs/tags/}"
else
tag_name="latest"
fi
safe_tag_name=$(printf '%s' "$tag_name" | sed 's/[^A-Za-z0-9._-]/-/g')
safe_tag_name="${safe_tag_name:-latest}"
echo "TAG_NAME=${tag_name}" >> "$GITHUB_OUTPUT"
echo "SAFE_TAG_NAME=${safe_tag_name}" >> "$GITHUB_OUTPUT"
- name: Build PDF
run: mdpress build --format pdf --output docker_practice-${{ steps.tag.outputs.TAG_NAME || 'latest' }}.pdf
run: mdpress build --format pdf --output docker_practice-${{ steps.tag.outputs.SAFE_TAG_NAME || 'latest' }}.pdf
- name: Create Release with PDF
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v3
with:
generate_release_notes: true
files: docker_practice-${{ steps.tag.outputs.TAG_NAME }}.pdf
files: docker_practice-${{ steps.tag.outputs.SAFE_TAG_NAME }}.pdf
- name: Upload PDF as artifact
uses: actions/upload-artifact@v7
with:
name: docker_practice-pdf
path: "docker_practice-*.pdf"
- name: Build HTML reader
id: htmlreader
continue-on-error: true
env:
CHROME_BIN: ${{ steps.setupchrome.outputs.chrome-path }}
run: |
# recent pandoc (apt's is too old for --embed-resources); + mermaid-cli using system Chrome
curl -fsSL https://github.com/jgm/pandoc/releases/download/3.5/pandoc-3.5-1-amd64.deb -o /tmp/pandoc.deb
sudo dpkg -i /tmp/pandoc.deb && pandoc --version | head -1
PUPPETEER_SKIP_DOWNLOAD=true npm install -g @mermaid-js/mermaid-cli@10
TITLE=$(python3 -c "import json,os;print((json.load(open('book.json')).get('title') if os.path.exists('book.json') else '') or '${{ github.event.repository.name }}')")
TAG="${{ steps.tag.outputs.SAFE_TAG_NAME || 'latest' }}"
python3 tools/render_mermaid.py --book-dir . --svg-out /tmp/mmsvg
python3 tools/build_html_reader.py --book-dir . --title "$TITLE" --svg-dir /tmp/mmsvg \
--out "${{ github.event.repository.name }}-${TAG}.html"
ls -lh ${{ github.event.repository.name }}-${TAG}.html
- name: Attach HTML to release
if: steps.htmlreader.outcome == 'success' && startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.tag.outputs.TAG_NAME }}
files: "${{ github.event.repository.name }}-${{ steps.tag.outputs.SAFE_TAG_NAME }}.html"
- name: Upload HTML as artifact
if: steps.htmlreader.outcome == 'success'
uses: actions/upload-artifact@v7
with:
name: html-edition
path: "${{ github.event.repository.name }}-*.html"
+20 -9
View File
@@ -16,23 +16,34 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Check project rules
run: python3 check_project_rules.py
- name: Check release metadata
run: npm test
- 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:
+25 -3
View File
@@ -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}}
+20 -7
View File
@@ -22,18 +22,31 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Check project rules
run: python3 check_project_rules.py
- name: Check release metadata
run: npm test
- 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
+3
View File
@@ -13,6 +13,8 @@ node_modules/
package-lock.json
docker-compose.override.yml
06_repository/demo/auth/nginx.htpasswd
11_compose/demo/wordpress/secrets/
# Editor configs
.obsidian/
@@ -26,6 +28,7 @@ Docker -- *_site/
# Check scripts
check*.py
!check_project_rules.py
find*.py
fix*.py
format*.py
+3 -1
View File
@@ -2,11 +2,13 @@
> **版本说明**本节示例基于 Docker v29.x 编写示例中使用的 `nginx:alpine` 镜像标签为演示用途请查阅 [Docker Hub - nginx](https://hub.docker.com/_/nginx) 确认最新可用版本。
开始前请先完成 [ 3 章安装 Docker](../03_install/README.md)并确认 `docker version` `docker run hello-world` 可以正常执行若你只是先浏览流程可以读完本节后再回到安装章实践
本节将通过一个简单的 Web 应用例子带你快速体验 Docker 的核心流程构建镜像运行容器
### 为什么选择 Nginx + HTML 作为入门例子
在学习 Docker 之前我们先来理解为什么这个例子是最适合初学者Docker 的核心价值在于**一致性交付**无论你在本地云端还是他人的机器上运行容器应用行为都是完全一致这个 Nginx + 静态 HTML 的例子之所以被广泛采用是因为它展现了 Docker 工作流的三个核心阶段
在学习 Docker 之前我们先来理解为什么这个例子适合初学者Docker 的核心价值在于**一致性交付**在相同镜像CPU 架构内核能力配置和外部依赖都满足的前提下应用行为可以保持高度一致这个 Nginx + 静态 HTML 的例子之所以被广泛采用是因为它展现了 Docker 工作流的三个核心阶段
1. **镜像定义Image Layer**通过 Dockerfile 描述如何把应用打包成一个自包含的单元
2. **镜像构建Build**执行 `docker build`Docker 根据 Dockerfile 逐层构建镜像
+3 -3
View File
@@ -4,11 +4,11 @@ Docker 是彻底改变了软件开发和交付方式的革命性技术。本节
### 1.2.1 一句话理解 Docker
> **Docker 是一种轻量级的虚拟化技术它让应用程序及其依赖环境可以被打包成一个标准化的单元任何地方都能一致地运行** 如果用一个生活中的类比**Docker 之于软件就像集装箱之于货物**
> **Docker 是一种轻量级的虚拟化技术它让应用程序及其依赖环境可以被打包成一个标准化的单元满足架构内核能力和外部依赖前提的环境中高度一致地运行** 如果用一个生活中的类比**Docker 之于软件就像集装箱之于货物**
在集装箱发明之前货物的运输是一件麻烦的事情不同的货物需要不同的包装不同的装卸方式换一种运输工具就要重新装卸集装箱的出现改变了这一切无论里面装的是什么集装箱的外形是标准的可以用同样的方式装卸堆放和运输
Docker 做的事情类似无论你的应用是用 PythonJavaNode.js 还是其他语言写的无论它需要什么样的依赖库和环境一旦被打包成 Docker 镜像就可以用同样的方式在任何支持 Docker 的机器上运行
Docker 做的事情类似无论你的应用是用 PythonJavaNode.js 还是其他语言写的无论它需要什么样的依赖库和环境一旦被打包成 Docker 镜像就可以用同样的方式在兼容的 Docker 环境中运行
### 1.2.2 Docker 的核心价值
@@ -112,7 +112,7 @@ flowchart LR
Docker 的发展历程
- **2013 3 **开源发布
- **2013 年底**dotCloud 公司改名为 DockerInc
- **2013 年底**dotCloud 公司改名为 Docker, Inc.
- **2015 **成立[开放容器联盟 (OCI)](https://opencontainers.org/),推动容器标准化
- **至今**[GitHub 项目](https://github.com/moby/moby)超过 7 万星标
+3 -3
View File
@@ -63,10 +63,10 @@ flowchart LR
#### 1. 环境一致性
Docker 镜像包含了应用运行所需的 **一切**代码运行时系统工具配置这意味着
Docker 镜像包含了应用运行所需的大部分用户态依赖代码运行时系统工具和默认配置它不包含宿主机内核也不能消除 CPU 架构内核能力外部服务网络卷和运行时配置差异这意味着
- 开发环境和生产环境完全一致
- 不会再有 在我机器上能跑 的问题
- 开发环境和生产环境可以显著减少差异
- 大幅降低 在我机器上能跑 的问题
- 新人入职一条命令就能启动开发环境
```bash
+1 -1
View File
@@ -172,7 +172,7 @@ registry.example.com/myproject/myapp:v1.2.3
## 简写(使用 Docker Hub
nginx:1.25
nginx:1.28
ubuntu:24.04
## 省略标签(默认使用 latest)
+11 -11
View File
@@ -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 Hubghcr.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)` 进入弃用阶段Docker 官方说明最早一批 DCT 签名证书自 2025 8 8 开始过期并建议镜像发布者迁移到 SigstoreNotation 等方案完整弃用时间线仍以 Docker 后续公告为准不建议把 DCT 作为新项目方案
> 注意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
+1 -1
View File
@@ -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
# 若需要测试频道
+1 -1
View File
@@ -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
# 若需要测试频道
+3 -6
View File
@@ -18,7 +18,6 @@ Fedora 的快速发布周期(每 6 个月发布新版本)决定了它的用
* Fedora 44
* Fedora 43
* Fedora 42
#### 卸载旧版本
@@ -39,7 +38,7 @@ $ sudo dnf remove docker \
### 3.3.2 使用 dnf 安装
使用 dnf 包管理器安装是推荐的方式便于后续的更和管理
使用 dnf 包管理器安装是推荐的方式便于后续的更和管理
执行以下命令安装依赖包
@@ -51,9 +50,7 @@ $ sudo dnf -y install dnf-plugins-core
执行下面的命令添加 `dnf` 软件源
```bash
$ sudo dnf config-manager \
--add-repo \
https://download.docker.com/linux/fedora/docker-ce.repo
$ sudo dnf config-manager addrepo --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo
```
如果需要测试版本的 Docker 请使用以下命令
@@ -91,7 +88,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
# 若需要测试频道
+1 -1
View File
@@ -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
# 若需要测试频道
+1 -1
View File
@@ -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
# 若需要测试频道
+10 -6
View File
@@ -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
View File
@@ -72,6 +72,25 @@ $ docker stop webserver
$ docker rm webserver
```
### 3.7.4 镜像加速
### 3.7.4 替代容器运行时
Docker Desktop 并非 macOS 上运行容器的唯一选择以下两个工具也广泛使用各有侧重
| 特性 | Docker Desktop | OrbStack | Colima |
|------|---------------|-----------|--------|
| 启动速度 | 较慢 1030 | 极快 2 | 中等 510 |
| 空闲内存占用 | 46 GB | 200300 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)
+2 -2
View File
@@ -80,7 +80,7 @@ Registry Mirrors:
### 3.9.6 Kubernetes 官方镜像地址迁移
可以登录 [阿里云容器镜像服务](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu&type=copy),在 **镜像中心** -> **镜像搜索** 中查找。
可以登录 [阿里云容器镜像服务](https://www.aliyun.com/product/acr),在 **镜像中心** -> **镜像搜索** 中查找。
Kubernetes 社区已将官方镜像地址从 `k8s.gcr.io` 迁移到 `registry.k8s.io`建议优先使用新地址
@@ -108,4 +108,4 @@ $ docker pull registry.k8s.io/xxx
某些云服务商提供了 **仅供内部** 访问的镜像服务当您的 Docker 运行在云平台时可以选择它们
* [腾讯云 `https://mirror.ccs.tencentyun.com`](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61)
* [腾讯云 `https://mirror.ccs.tencentyun.com`](https://cloud.tencent.com/product/tke)
+1 -1
View File
@@ -18,7 +18,7 @@ Docker Engine 主要提供 `stable` 和 `test` 两个更新频道;`test.docker
**开发环境**本地开发机测试服务器
- 使用**脚本自动安装****包管理器直接安装**
- 配置 **Docker 官方源后** 使用包管理器安装或在一次性测试环境使用官方脚本自动安装
- 如果你想快速上手官方脚本`get.docker.com`是最便捷的选择
- 国内用户注意这一步一定要选对镜像源否则网络卡顿会严重影响体验
+2 -2
View File
@@ -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)
{
+3 -3
View File
@@ -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`就能看到我们刚刚提交出来的新层
+4 -4
View File
@@ -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` 命令进行镜像构建其格式为
@@ -180,4 +180,4 @@ cat Dockerfile | docker build -
```bash
$ docker build - < context.tar.gz
```
如果发现标准输入的文件格式是 `gzip``bzip2` 以及 `xz` 的话将会使其为上下文压缩包直接将其展开将里面视为上下文并开始构建
如果发现标准输入的文件格式是 `gzip``bzip2` 以及 `xz` 的话将会将其视为上下文压缩包直接将其展开将里面视为上下文并开始构建
+2 -2
View File
@@ -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 \
@@ -70,7 +70,7 @@ filename: POSIX tar archive
```bash
$ docker save alpine | gzip > alpine-latest.tar.gz
```
然后我们将 `alpine-latest.tar.gz` 文件复制到了到了另一个机器上可以用下面这个命令加载镜像
然后我们将 `alpine-latest.tar.gz` 文件复制到了另一个机器上可以用下面这个命令加载镜像
```bash
$ docker load -i alpine-latest.tar.gz
+1 -1
View File
@@ -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 storeDocker Desktop 4.34 及之后也默认启用 containerd image store实际环境仍应以当前配置为准
虽然底层实现细节不同但它们都遵循上述的 **分层 + CoW** 模型因此无论你看到的是 `overlay2` 还是 containerd snapshotter理解镜像层容器层和写时复制的方式都是一样重要的
+6 -14
View File
@@ -1,4 +1,4 @@
# syntax = docker/dockerfile:experimental
# syntax=docker/dockerfile:1
FROM node:alpine as builder
@@ -6,24 +6,16 @@ WORKDIR /app
COPY package.json /app/
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
--mount=type=cache,target=/root/.npm,id=npm_cache \
npm i --registry=https://registry.npmmirror.com
RUN --mount=type=cache,target=/root/.npm,id=npm_cache \
npm install --registry=https://registry.npmmirror.com
COPY src /app/src
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
# --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \
npm run build
RUN npm run build
FROM nginx:alpine
# COPY --from=builder /app/dist /app/dist
# 为了更直观的说明 from source 指令这里使用 RUN 指令
RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
# --mount=type=cache,target/tmp/dist,from=my_app_dist,sharing=locked \
mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist
COPY --from=builder /app/dist /app/dist
RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \
cat /docker-php-entrypoint
@@ -32,6 +24,6 @@ RUN --mount=type=tmpfs,target=/temp \
mount | grep /temp
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
cat /root/.aws/credentials
test -s /root/.aws/credentials && echo "credentials mounted"
# docker build -t test --secret id=aws,src=$PWD/aws.txt --progress=plain -f Dockerfile.buildkit .
+2 -5
View File
@@ -1,14 +1,11 @@
FROM golang:alpine as builder
RUN apk --no-cache add git
WORKDIR /go/src/github.com/go/helloworld/
RUN go get -d -v github.com/go-sql-driver/mysql
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
RUN go mod init helloworld \
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest as prod
@@ -1,10 +1,8 @@
FROM golang:alpine
RUN apk --no-cache add git
WORKDIR /go/src/github.com/go/helloworld
COPY app.go .
RUN go get -d -v github.com/go-sql-driver/mysql \
RUN go mod init helloworld \
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
@@ -1,12 +1,12 @@
FROM golang:alpine
RUN apk --no-cache add git ca-certificates
RUN apk --no-cache add ca-certificates
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 \
&& CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \
&& cp /go/src/github.com/go/helloworld/app /root
+4 -4
View File
@@ -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容器在后台运行但无法访问服务
+1 -1
View File
@@ -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容器无法停止
+2 -1
View File
@@ -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+ 提供的功能需要 ProTeam Business 订阅它会附加一个包含常用调试工具vimcurlhtop 的工具箱到目标容器即使目标镜像基于 `scratch` 也能使用
---
### 5.4.7 常见问题
+3 -3
View File
@@ -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)
+10 -9
View File
@@ -11,7 +11,7 @@ Docker Hub 是 Docker 的中央镜像仓库,通过它您可以轻松地分享
- **官方镜像** Docker 官方和软件厂商 ( NginxMySQLNode.js) 维护的高质量镜像
- **个人/组织仓库**用户可以上传自己的镜像
- **自动构建** GitHub/Bitbucket 集成 (需付费)
- **自动构建** GitHub/Bitbucket 集成的历史功能Docker 已标记为 deprecated并计划于 2027-04-01 完全退役
- **Webhooks**镜像更新时触发回调
---
@@ -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. 关注镜像漏洞
@@ -130,8 +131,8 @@ Docker Hub 提供 Docker Scout 安全扫描功能。官方镜像的漏洞扫描
### 6.1.6 自动构建
> 目前仅限付费用户 (Pro/Team) 使用
> Docker Hub Automated Builds 已被 Docker 标记为 deprecated并计划于 2027-04-01 完全退役新项目应优先使用 GitHub ActionsBuildx 或自有 CI 构建并推送镜像
链接 GitHub/Bitbucket 仓库后当代码有提交或打标签时Docker Hub 会自动运行构建这保证了镜像总是与代码同步且由可信的官方环境构建
对于仍在迁移期内的旧仓库链接 GitHub/Bitbucket 仓库后当代码有提交或打标签时Docker Hub 会自动运行构建不要把它作为新架构的默认方案
---
+2 -2
View File
@@ -4,7 +4,7 @@
本节介绍如何使用本地仓库
[Docker Registry](https://docs.docker.com/registry/) 是官方提供的工具,可以用于构建私有的镜像仓库。本文内容基于 [distribution/distribution](https://github.com/distribution/distribution) v2.x 版本
[Docker Registry](https://docs.docker.com/registry/) 是官方提供的工具,可以用于构建私有的镜像仓库。本文示例沿用 [distribution/distribution](https://github.com/distribution/distribution) v2.x 兼容路径;新生产部署应评估 Distribution 3.x,并核对配置路径、迁移说明和生态兼容性
### 6.2.1 安装运行 docker-registry
@@ -18,7 +18,7 @@
$ docker run -d -p 5000:5000 --restart=always --name registry registry:2
```
> **版本说明**使用 `registry:2` 表示 Docker Registry 2.x 版本这是当前推荐的版本旧版本 Registry 1.x 已停止维护不建议使用
> **版本说明**使用 `registry:2` 表示 Docker Registry 2.x 兼容示例Distribution 3.x 已发布稳定版本不要直接把本章 v2 配置原样套到 v3 生产环境升级前应阅读迁移说明并做兼容测试旧版本 Registry 1.x 已停止维护不建议使用
这将使用官方的 `registry` 镜像来启动私有仓库默认情况下仓库会被创建在容器的 `/var/lib/registry` 目录下你可以通过 `-v` 参数来将镜像文件存放在本地的指定路径例如下面的例子将上传的镜像放到本地的 `/opt/data/registry` 目录
```bash
+13 -4
View File
@@ -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]
@@ -112,7 +116,7 @@ health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
threshold: 3
```
### 6.3.3 生成 http 认证文件
@@ -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,7 +154,9 @@ volumes:
registry-data:
```
> **版本说明**Compose 配置中明确指定 `registry:2` 版本生产环境建议固定版本号 `registry:2.8.3`而非使用 `latest`以保证部署的可重复性
本书配套的 `06_repository/demo/` 也采用同样约定容器内 registry 监听 `:5000`宿主机通过 `443:5000` 暴露 HTTPS 服务这样可以避免在容器内占用特权端口同时仍让客户端使用 `https://docker.domain.com` 访问
> **版本说明**Compose 配置中明确指定 `registry:2` 版本生产环境建议固定具体补丁版本 `registry:2.8.x`并在新部署时评估 Distribution 3.x不要使用 `latest`以保证部署的可重复性
### 6.3.5 修改 Hosts 文件
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -10,7 +10,7 @@
本章涉及的 Registry 和相关工具版本说明
- **Docker Registry**使用 `registry:2` 推荐版本已停止维护的 `registry:1` 不建议使用
- **Docker Registry / CNCF Distribution**本章示例使用 `registry:2` 兼容路径新生产部署应评估 Distribution 3.x并核对配置路径迁移说明和生态兼容性已停止维护的 `registry:1` 不建议使用
- **Nexus 3**建议指定具体版本 `sonatype/nexus3:3.69`而非 `latest`避免自动升级带来的兼容性问题
- **镜像标签规范**
- 生产环境推送至仓库时应明确指定版本号 `myapp:v1.0.0`
+5
View File
@@ -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.
-2
View File
@@ -1,2 +0,0 @@
username:$2y$05$TRWvCC6ilpKpY3ICifw32Ok3.8SpG3etq8O5WGdCm9wvyDhtSbRgy
+3
View File
@@ -0,0 +1,3 @@
*
!.gitignore
!README.md
+5
View File
@@ -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-----
MIIJKgIBAAKCAgEA1Hbm1tZvAeC8J54pQLHTVCtrICQ8KFTLOZakPHSWox8iQ4i2
fkZaSccvE/51LIFnCM1yyZv88ILucqitG4zvuhDG+cU8w1vRbWf3xfGCCsHyn6LK
BHR0Kk6+WRIBZTdRSsW8ZvpL2Y7eBNAUkC2oeaOJEOQ8D50b3u5jhAFmXuAcTiZh
90Ve4JBKZV8dGs8L81vOvb7tqvJrEvCNKuZO7mEcjXkgiwUdP3pkZYa0tPOV5UrL
H/oEvgPDJfXrNntCY1+A+CBQ7Sq3S2YpNJN7VnK6SboRi7xpOEgQOXwNVJWm/5YB
vnbAztNXKcE2q2wREL9TulUJCqo2h6NRaGYPfiLZIUHEJ7vQitRBRDpkxcX8XJX3
Jm7weRPXLDOG8RN3FzPDTGL2ZDTWKDIQ20OhYEmENInKkpC2bYpwMzNvBA7AJN6M
CYHXl4VP/Df0pPtMM/DiZX+68ng3RQXT5VzDYURIH2wP5kcTL0irsNr+L7lHD+5m
A1VErdQsh6AHWjrwMrSMegJpLP11rK4J+P/HHnqsBEi5XZI/hvRmwD7gwskRqXdD
MHaWnoIIpPO3TeNYQUjDxaV5KUQuWVME5Ihuy03FPMChXXB0WF+tclPJxjQyDkwE
VL+6d8i5yCPUBS2gBSBypQQINFH4hOcx2e9Lujx7dOWfidjX3xssC9bEe60CAwEA
AQKCAgEAqT/6zePOVFGhsXG17Rp7fY6E7PrQjVRW/A470QkTQui3U9MhhWAn5qPs
peHLl+ORn5qCOYawrSuwJdim5c6U3cUlrKzppbqMD7qFz8J+1HECBRcaFQhrzZQi
4DOOtwGlGYqBdgsnxyyfQng8GUq17ghPVQxrqAiAvktrLSosUaH4Cm1bFy7E0OFA
0pY9SjDrlTZqcA8bp1Ur5M+JtUX4VL85jp2SRgyR6xJlzdbMN2Xf3+OAAn4ZrwCy
QZgwgpsYHK9kvsSHkxa3IzJD2uUtmIUWT0sRVR6HN1V4z0I6IEqC2RG3W/Gf0GLd
CZ8oHNCem5e+bC33YO6NN+nrHN5Isb+itdbtE392P6FgPbM1um1zuuTTewaUyXS7
ATomznTpYXkHvCdvU5yOEH+yDYfcm99v77qVr0+arecVx2h0M2tqROwEza3Rw5Wp
928vyxPFde9HFHQG4SWRzCGfKpnvIT/ce2ayWHEDEbvzlwL9lokZqe0YYu5KDYTL
j3DsnzMPiMn6bpQUIBXlO5+eAh94vatPCriNpEkHw3aYQNyux1BmyvKxflj6pg9u
lxKWGng8YOW88ysXvXlAssjpDe+k/Cvaja3ZeV3pyRbMnK3ARHXi3mQ6wBsOVa6e
zt3cpBgXik7m7u6a82FhLafP2UfFIpW6WRTA28ercpKtHRKJJgUCggEBAPWJsfPa
4movMI6ofySMFm74u779aO5rGMQumR52vwlWyNDmOWNRrQaU/tpyaFOiPeIOGt2V
UM02rdWHbnAhsgYP0cjUs34aJV/Z4nunw5Jc6rrT+dhd3+ZgqM1X/sLt5JfEavHe
bV/cDV+xDp4FAXrLOPeRldvLPT1dmdQnirPGK3A1WWi5GQ+//Kas+lHuqECWYRrU
LVFx0tR/pmdCC5Lb58kuPOxFP4OaeC3PbGyA2y0gv+QR/5Nc0o1y/X6p6XIM5QxY
fg4gDKwSewrZ40+9taRNtgMQz3xKkeYmaNgLKnCBnLhDYdLZPAeYkOUIytzJbaYg
oWHzmdd5FIKCgzcCggEBAN2Ecd7lJRIISuQop5GQ44mRrsDZTxBWnZ9pn3VFWNfA
tF5MHofrtED7mXBSAt88TryqndcyC6qMvaS4Ifk1cNSFdz9FLsNzxJj4wp5Cj+e1
aSY5ARvXTXqTfKZErQNXFk1oCa+ARZIs5SPjh0LH+Iq2pd72cEap7pi3JT5RbOtE
ReDCAKayyejFMKtekzccishIwH/nzYlNaNBkmG7MZG8V+FFlxYSieIa7Ohcbmmj3
D3ssbi+y+peRt14wZB/daScybcIqdu544ZIvJOpm0i9rHxE49bodmTDhAZ9awqls
nRsyI0NNDExPDhCrzPogcRLVHn2KbcZbjGPS5jossjsCggEAazYchaXlhwfj4+ae
3Y5tnTbug46S6sfIoKDYKv0enS1PsidUl5FqQ517Slb6RspoyvPttyMjjPd7H+lq
x3tvCEaQC2kUltNDzn6M7gFq29XGiJ1WUqtqwGUkT8VEcEj/r2UMbV/50gl7rXTa
NRVqd/uUfEUNclNkAg+Ew6YgYi79eJlS2O85ii8CWqTdCDl1Lf57mANdZlqU/ERg
nGWyOAXdR3LxFxmFiilAoIAZj6cUDLhoEWXqeqXlKe4z0cLPNAV9Xc6l+/Tyk4/e
Ofa50m+7iGqGNwB4GIVW/292CB+YAFgX3j1N0YsZMxfi7J7SNWWegxNsZCDB49vy
oKnsMQKCAQEA0iurbnOyrF050SfRdQcnG4shZs/HeBT2EB3CsR1OocWwXBeUkBlO
OKl+d1cYan1ppw+qGlbdQr+t3u7lLPFLUBghf+I/8CmSyiCbZlR4/LrePOmw551r
YXU1uvtFu/mQq3ieV+k4GOyHq3lhCDd61QFedyESfbkVK8f4ihvvX3izZAAtZfwU
HcmZ174vpwZploWQPsrL9A2B+Na42ccLM2qA45nPwXv1Jr/U6b/CzPw7r/4DvTXv
FIeolrELDkCgWBQ8lxB7Lt96BZy9Rbiwi1TzcP++BQu4IOwbAfq23tCybu8vDde4
Z15KVf7qyBansdqKx0njxWNu2/dpgKCPqQKCAQEAzWV4aajox7eeTi3iudP1Oxu3
OBiu8xie4xq0mlM13tMxAQry/uOAuTxbaQ48mNsSXdeYeSgmT45lUvFWROqdVScK
8gh04G1NiRAkITzXwCCwKkAQxvQppgypZ+aksBHkFQFBAIg2/mLizS4cicXNEY4G
vb+RImfn8MSqSMLu3cJ8zgFyqfRg6F0oHg9EgEwvbnCLYglN6Xm5KlZutjW4eu7m
Q+1y0lg05e7vFyj2UIVylfzT/aoF/xzXzNt9/LZs0klO3vMmaVyTjuF/71+AyphH
FTmpNs1wpZU2IRqKOMrimIhk6TTxvMSaN4pxKdLPqgHYLWhwkbsdmqtTnCljRg==
-----END RSA PRIVATE KEY-----
+4 -4
View File
@@ -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 ./
+4 -4
View File
@@ -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 .
+1 -1
View File
@@ -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/*
+2 -2
View File
@@ -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
```
+1 -1
View File
@@ -59,7 +59,7 @@ LABEL maintainer="user@example.com" \
```docker
LABEL org.opencontainers.image.authors="yeasy" \
org.opencontainers.image.documentation="https://yeasy.gitbooks.io" \
org.opencontainers.image.documentation="https://yeasy.gitbook.io/docker_practice/" \
org.opencontainers.image.source="https://github.com/yeasy/docker_practice" \
org.opencontainers.image.licenses="MIT"
```
+15 -7
View File
@@ -2,9 +2,9 @@
### 官方文档
* `Dockerfile` 官方参考手册https://docs.docker.com/engine/reference/builder/
* `Dockerfile` 官方参考手册https://docs.docker.com/reference/dockerfile/
* `Dockerfile` 最佳实践指南https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
* `Dockerfile` 最佳实践指南https://docs.docker.com/build/building/best-practices/
* `Docker` 官方镜像 `Dockerfile` https://github.com/docker-library/docs
@@ -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
### 最佳实践建议
+19 -8
View File
@@ -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-alpinecomposer:2.xphp:8.3-fpm-alpinenginx:1.25-alpine
FROM node:alpine as frontend
# 生产环境推荐使用具体的版本标签 node:22-alpinecomposer:2.xphp:8.3-fpm-alpinenginx: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
+3 -1
View File
@@ -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 语法编写多行脚本无需行末反斜杠 `\` 连接
+1 -1
View File
@@ -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
+29 -28
View File
@@ -4,12 +4,12 @@
在开始前让我们直言不讳**在大多数情况下你应该使用 COPY而不是 ADD**
`ADD` `COPY` 基础上增加了两个额外功能但这些功能往往引入复杂性而非便利
`ADD` `COPY` 基础上增加了两个额外功能它不是 `COPY` 的通用替代品但在少数场景中更合适
1. 自动解压 tar 压缩包有时你想复制一个 .tar.gz 本身 ADD 会意外地解压它
2. 支持从 URL 下载文件这个功能由于网络不稳定已被广泛认为是反模式
2. 支持从 URL 下载公开远程文件并可配合 `--checksum` 做校验
**实践中的建议**除非你明确需要自动解压功能比如官方基础镜像构建根文件系统否则始终使 COPY原因很简单显式优于隐式你的 Dockerfile 6 个月后被接手维护时清晰的意图会让团队少走很多弯路
**实践中的建议**本地普通文件默认 COPY本地 tar 自动解压或公开远程 artifact 下载并校验时用 ADD需要认证请求头重试或自定义解压流程时用 `RUN curl/wget`
### 7.3.1 基本语法
@@ -20,7 +20,7 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
`ADD` `COPY` 基础上增加了两个功能
1. 自动解压 tar 压缩包
2. 支持从 URL 下载文件 (不推荐)
2. 支持从 URL 下载文件
---
@@ -30,11 +30,11 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
|------|------|-----|
| 复制本地文件 | | |
| 自动解压 tar | | |
| 支持 URL | | (不推荐)|
| 支持 URL | | (公开 artifact 可配合校验使用)|
| 行为可预测性 | | |
| 推荐程度 | **优先使用** | 解压场景 |
| 推荐程度 | **普通复制优先使用** | 解压本地 Git/公开远程 artifact |
> **笔者建议**除非需要自动解压 tar 文件否则始终使用 COPY明确的行为比隐式的魔法更好
> **笔者建议**普通复制始终优先 COPY只有当你明确需要 ADD 的额外语义时再使用 ADD并把意图写清楚
---
@@ -79,7 +79,7 @@ app.tar.gz 包含: /app/ 目录结果:
```
---
### 7.3.4 URL 下载功能不推荐
### 7.3.4 URL 下载功能谨慎使用
#### 基本用法
@@ -89,32 +89,29 @@ app.tar.gz 包含: /app/ 目录结果:
ADD https://example.com/app.zip /app/app.zip
```
#### 为什么不推荐
#### 使用边界
| 问题 | 说明 |
| 场景 | 建议 |
|------|------|
| 权限固定 | 下载的文件权限为 600通常需要额外 RUN 修改 |
| 不会解压 | URL 下载的压缩包不会自动解压 |
| 缓存问题 | URL 内容变化时不会重新下载 |
| 层数增加 | 需要额外 RUN 清理 |
| 公开版本固定的远程 artifact | 使用 `ADD --checksum=sha256:... URL dest` |
| 需要认证请求头或复杂重试 | 使用 `RUN curl/wget` |
| 下载后需要复杂解压校验或清理 | 使用 `RUN curl/wget`把流程显式写出 |
| URL 内容可变但无校验 | 不建议直接写入 Dockerfile |
#### 推荐替代方案
#### 推荐写法
```docker
## 不推荐使用 ADD 下载
## 公开 artifact使用 ADD 并固定校验值
ADD https://example.com/app.tar.gz /tmp/
ADD --checksum=sha256:<digest> https://example.com/app.tar.gz /tmp/app.tar.gz
RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz
## 推荐使用 RUN + curl
## 需要认证请求头或特殊处理使用 RUN + curl
RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
```
优势
`ADD --checksum` 的优势是缓存更精确并且校验值直接绑定到 Dockerfile`RUN curl/wget` 的优势是控制力更强适合企业内网认证下载或复杂处理
- 一条 RUN 完成下载解压清理
- 减少镜像层数
- 更清晰的构建意图
---
@@ -139,6 +136,10 @@ ADD rootfs.tar.gz /
## 解压应用包
ADD dist.tar.gz /app/
## 下载公开 artifact 并校验
ADD --checksum=sha256:<digest> https://example.com/app.tar.gz /tmp/app.tar.gz
```
#### 不适合使用 ADD
@@ -149,9 +150,9 @@ ADD dist.tar.gz /app/
ADD package.json /app/ #
COPY package.json /app/ #
## 下载文件 RUN + curl
## 需要认证或复杂下载逻辑 RUN + curl/wget
ADD https://example.com/file / # ❌
ADD https://example.com/file / # ❌ 无法传认证信息,也没有显式处理
RUN curl -fsSL ... -o /file #
## 需要保留 tar 不解压 COPY
@@ -203,14 +204,14 @@ COPY . /app/
ADD app.tar.gz /app/
```
#### 3. 不要 ADD 下载文件
#### 3. 远程 artifact 使 ADD 时必须固定校验值
```docker
## 避免
## 公开 artifact
ADD https://example.com/file.tar.gz /tmp/
ADD --checksum=sha256:<digest> https://example.com/file.tar.gz /tmp/file.tar.gz
## 推荐
## 认证下载或复杂处理
RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
```
+6 -6
View File
@@ -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 格式推荐
@@ -65,7 +65,7 @@ CMD echo $HOME
CMD ["sh", "-c", "echo $HOME"]
```
**优点**可以使用环境变量管道等 shell 特性
**优点**可以使用 `$HOME` 这类 shell 变量展开管道等 shell 特性
**缺点**主进程是 sh信号无法正确传递给应用
@@ -77,7 +77,7 @@ CMD ["sh", "-c", "echo $HOME"]
|------|----------|-----------|
| 主进程 | 指定的程序 | `/bin/sh` |
| 信号传递 | 正确 | 无法传递 |
| 环境变量 | 需要 shell 包装 | 自动解析 |
| `$VAR` shell 展开 | 不自动展开环境变量仍会传入进程 | 自动展开 |
| 推荐使用 | 大多数场景 | 需要 shell 特性时 |
#### 信号传递问题示例
+1 -1
View File
@@ -40,7 +40,7 @@
| 格式 | 语法 | 推荐程度 |
|------|------|---------|
| **exec 格式**| `ENTRYPOINT [可执行文件, 参数1]` | **推荐** |
| **exec 格式**| `ENTRYPOINT ["可执行文件", "参数1"]` | **推荐** |
| **shell 格式** | `ENTRYPOINT 命令 参数` | 不推荐 |
```docker
+6 -4
View File
@@ -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. 不要存储敏感信息
@@ -210,7 +212,7 @@ ENV HOST=localhost \
#### Q环境变量在 CMD 中不展开
exec 格式不会自动展开环境变量
exec 格式不会自动执行 shell 展开因此命令参数里的 `$PORT` 会按字面值传给进程但环境变量本身仍会注入进程环境应用可以通过语言运行时读取
```docker
## 不会展开 $PORT
+10 -8
View File
@@ -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
```
@@ -146,17 +146,19 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
#### 4. 配置私有仓库
```docker
ARG NPM_TOKEN
不要用 `ARG` `ENV` 传递仓库 tokenDocker 官方构建检查会把这类写法视为不安全因为构建参数和环境变量可能进入镜像元数据或历史记录使用 BuildKit secret mount 只在单条 `RUN` 指令期间暴露凭据
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \
```docker
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN="$(cat /run/secrets/npm_token)" && \
printf "//registry.npmjs.org/:_authToken=%s\n" "$NPM_TOKEN" > ~/.npmrc && \
npm install && \
rm ~/.npmrc
```
```bash
## 构建时传入 token
$ docker build --build-arg NPM_TOKEN=xxx .
$ docker build --secret id=npm_token,env=NPM_TOKEN .
```
---
+10 -10
View File
@@ -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,23 +82,23 @@ $ 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
```
---
### 7.8.5 VOLUME 在构建时的特殊行为
> **重要**VOLUME 之后该目录的修改会被丢弃
> **重要**`VOLUME` 之后再写入该目录的构建语义取决于 builderlegacy builder 会丢弃这些修改BuildKit 会保留但运行容器时一旦该路径挂载了卷卷会遮蔽镜像内同路径的内容
```docker
FROM ubuntu
VOLUME /data
## 这个文件不会出现在镜像中
## legacy builder 会丢弃BuildKit 会保留但运行时挂载卷会遮蔽它
RUN echo "hello" > /data/test.txt
```
**原因**在构建过程中VOLUME 指令会为该目录创建一个临时匿名卷后续 RUN 指令对该目录的写入实际发生在这个临时卷中而非镜像层当该 RUN 指令结束后临时卷被丢弃因此写入的内容不会保存到最终镜像中注意这与容器运行时创建的匿名卷是不同的运行时创建的卷会在容器生命周期内持续存在
**原因** builder 在构建过程中为该目录创建临时匿名卷后续写入发生在临时卷中BuildKit 则会把修改保留在镜像层为了避免不同 builder 下出现不同结果也为了避免运行时卷遮蔽镜像内初始化数据不要把必须存在的初始化文件写在 `VOLUME` 之后
#### 正确做法
@@ -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
```
---
+1 -1
View File
@@ -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
+17 -2
View File
@@ -7,12 +7,12 @@
| **FROM** | 指定基础镜像 | 必须是第一条指令 |
| **RUN** | 在新层执行命令 | 合并命令清理缓存以减小体积 |
| **COPY** | 复制文件 | 优先使用支持 `--from` |
| **ADD** | 更高级的复制 | 自动解压 tar不推荐用于下载 |
| **ADD** | 更高级的复制 | 自动解压 tar公开远程 artifact 应配合 `--checksum` |
| **CMD** | 容器启动默认命令 | 可被 `docker run` 参数覆盖 |
| **ENTRYPOINT** | 容器入口点 | 固定启动命令CMD 作为默认参数 |
| **ENV** | 设置环境变量 | 构建时 + 运行时均生效 |
| **ARG** | 构建参数 | 仅构建时生效FROM 后需重新声明 |
| **VOLUME** | 定义匿名卷 | VOLUME 之后的修改会丢失 |
| **VOLUME** | 定义匿名卷 | 运行时挂载会遮蔽镜像内目录构建后续写入语义依赖 builder |
| **EXPOSE** | 声明端口 | 仅文档作用不自动映射 |
| **WORKDIR** | 指定工作目录 | 替代 `RUN cd`目录不存在会自动创建 |
| **USER** | 指定运行用户 | 用户必须已存在推荐 gosu |
@@ -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 入门
+5 -1
View File
@@ -122,6 +122,8 @@ $ docker run -d \
#### 场景四共享 SSH 密钥
只读挂载可以防止容器修改主机密钥但不能防止容器读取并外传密钥只有在镜像完全可信密钥作用域很窄且可随时轮换时才考虑这种做法更稳妥的方式是使用 SSH agent socket 转发一次性 deploy key或在 CI/构建场景中使用 BuildKit `--ssh`
```bash
## 挂载 SSH 密钥只读
@@ -238,7 +240,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 +250,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 最佳实践
+10 -3
View File
@@ -20,11 +20,12 @@ ghi789... none null local
| **host** | 容器直接使用宿主机网络栈 | 需要最高网络性能时 |
| **none** | 禁用网络 | 完全隔离的容器 |
| **overlay** | 跨主机网络 | Docker Swarm 集群 |
| **macvlan** | 容器拥有独立 MAC 地址 | 需要直接接入物理网络 |
| **macvlan** | 容器拥有独立 MAC 地址 | Linux 主机上需要直接接入物理网络 |
| **ipvlan** | 容器共享父接口 MAC独享 IP | 同网段大量容器 MAC 数量受限的网络 |
### 9.2.2 Bridge 网络默认
Bridge Docker 默认使用的网络模式Docker 启动时会自动创建 `docker0` 虚拟网桥所有未指定网络的容器会连接到这个网桥上
Bridge Docker 默认使用的网络模式在原生 Linux Docker Engine Docker 启动时通常会创建 `docker0` 虚拟网桥未指定网络的容器会连接到这个网桥上Docker Desktop 运行在虚拟机内宿主机上不会直接看到 `docker0`也不能假设宿主机可直接访问每个容器 IP
核心组件如下
@@ -44,6 +45,8 @@ $ docker run -d --network host nginx
```
这种模式下网络性能最高但容器之间和宿主机之间没有网络隔离
> 注意host 网络优先用于明确需要高性能或大量端口的 Linux 主机场景Docker Desktop 仅在较新版本中支持且需要在设置中启用使用 host 网络时 `-p` / `--publish` 端口映射不会生效普通 Web 服务默认仍建议使用 bridge 网络并显式发布端口
### 9.2.4 None 网络
使用 `--network none` 参数启动的容器只有 `lo` 回环网卡完全没有外部网络连接适用于只需要运行计算任务不需要网络的容器
@@ -54,7 +57,11 @@ $ docker run -it --network none alpine ip addr
inet 127.0.0.1/8 scope host lo
```
### 9.2.5 数据流向
### 9.2.5 Macvlan 与平台限制
Macvlan 适合少数需要让容器像物理主机一样直接出现在二层网络中的场景它只支持 Linux 主机不支持 Docker Desktop for Mac / Windows也不支持 rootless 模式多数云厂商网络会阻断或限制 macvlan默认情况下macvlan 容器与宿主机直接通信也需要额外路由或接口配置
### 9.2.6 数据流向
容器网络中的数据流向可以分为以下几种情况
+7 -6
View File
@@ -7,7 +7,7 @@
容器的网络访问规则如下
- **容器之间**可以通过 IP 或容器名 (自定义网络) 互通
- **宿主机访问容器**可以通过容器 IP 访问
- **宿主机访问容器**原生 Linux 环境下可按网络配置访问容器 IPDocker Desktop 上不能依赖容器 IP应通过端口映射容器名容器间 `host.docker.internal` 等机制访问
- **外部网络访问容器** 默认无法直接访问
为了让外部 (如你的浏览器其他局域网机器) 访问容器内的服务我们需要将容器的端口 **映射** 到宿主机的端口
@@ -39,10 +39,10 @@ $ docker run -d -p 8080:80 nginx
| 格式 | 含义 | 示例 |
|------|------|------|
| `ip:hostPort:containerPort` | 绑定指定 IP 的特定端口 | `-p 127.0.0.1:8080:80` (仅本机访问) |
| `ip:hostPort:containerPort` | 绑定指定 IP 的特定端口 | `-p 127.0.0.1:8080:80` ( IPv4 本机访问) |
| `ip::containerPort` | 绑定指定 IP 的随机端口 | `-p 127.0.0.1::80` |
| `hostPort:containerPort` | 绑定所有 IP (0.0.0.0) 的特定端口 | `-p 8080:80` (默认) |
| `containerPort` | 绑定所有 IP 的随机端口 | `-p 80` |
| `hostPort:containerPort` | 绑定所有地址通常包括 `0.0.0.0` `[::]`的特定端口 | `-p 8080:80` (默认) |
| `containerPort` | 绑定所有地址的随机端口 | `-p 80` |
#### 2. 随机映射
@@ -93,14 +93,15 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web
#### 1. 限制监听 IP
默认情况下`-p 8080:80` 会监听 `0.0.0.0:8080`这意味着任何人只要能连接你的宿主机 IP就能访问该服务
默认情况下`-p 8080:80` 会监听所有可用地址常见输出包括 `0.0.0.0:8080` `[::]:8080`这意味着任何人只要能连接你的宿主机 IP就能访问该服务
如果不希望对外暴露 (例如数据库服务)应绑定到 `127.0.0.1`
如果不希望对外暴露 (例如数据库服务)应绑定到回环地址IPv4 使用 `127.0.0.1`IPv6 使用 `[::1]`
```bash
## 仅允许本机访问
$ docker run -d -p 127.0.0.1:3306:3306 mysql
$ docker run -d -p '[::1]:3306:3306' mysql
```
#### 2. 避免端口冲突
+1 -1
View File
@@ -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)
+17 -29
View File
@@ -2,7 +2,7 @@
**BuildKit** 是下一代的镜像构建组件 [moby/buildkit](https://github.com/moby/buildkit) 开源。
> **重要** Docker 23 BuildKit 已成为 **默认稳定构建器**无需手动启用Docker Engine 29 进一步将 Containerd 镜像存储设为默认提升与 Kubernetes 的互操作性
> **重要** Docker 23 BuildKit 已成为 **默认稳定构建器**无需手动启用Docker Engine 29 在新安装场景中进一步将 containerd image store 设为默认提升多平台镜像SBOM/Provenance OCI 元数据能力
目前Docker Hub 自动构建已经支持 BuildKit具体请参考 [docker-practice/docker-hub-buildx](https://github.com/docker-practice/docker-hub-buildx)。
@@ -15,7 +15,7 @@ BuildKit 引入了多项新指令,旨在优化构建缓存和安全性。以
要使用最新的 Dockerfile 语法特性建议在 Dockerfile 开头添加语法指令
```docker
## syntax=docker/dockerfile:1
# syntax=docker/dockerfile:1
```
这将使用最新的稳定版语法解析器确保你可以使用所有最新特性
@@ -46,12 +46,12 @@ COPY --from=builder /app/dist /app/dist
```
使用多阶段构建构建的镜像中只包含了目标文件夹 `dist`但仍然存在一些问题 `package.json` 文件变动时`RUN npm i && rm -rf ~/.npm` 这一层会重新执行变更多次后生成了大量的中间层镜像
为解决这个问题进一步的我们可以设想一个类似 **数据卷** 的功能在镜像构建时把 `node_modules` 文件夹挂载上去在构建完成后这个 `node_modules` 文件夹会自动卸载实际的镜像中并不包含 `node_modules` 这个文件夹这样我们就省去了每次获取依赖的时间大大增加了镜像构建效率同时也避免了生成了大量的中间层镜像
为解决这个问题可以把包管理器的下载缓存挂载到构建步骤中例如 npm `/root/.npm`注意`type=cache` 只能作为性能优化不能成为构建正确性的前提缓存目录可能被并发构建改写也可能被 GC 清理所以不要把 `node_modules`编译产物等必须存在的内容只放在 cache mount
`BuildKit` 提供了 `RUN --mount=type=cache` 指令可以实现上边的设想
```docker
## syntax=docker/dockerfile:1
# syntax=docker/dockerfile:1
FROM node:alpine as builder
@@ -59,35 +59,23 @@ WORKDIR /app
COPY package.json /app/
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
--mount=type=cache,target=/root/.npm,id=npm_cache \
npm i --registry=https://registry.npmmirror.com
RUN --mount=type=cache,target=/root/.npm,id=npm_cache \
npm install --registry=https://registry.npmmirror.com
COPY src /app/src
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
## --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \
npm run build
RUN npm run build
FROM nginx:alpine
## COPY --from=builder /app/dist /app/dist
## 为了更直观的说明 from source 指令这里使用 RUN 指令
RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
# --mount=type=cache,target=/tmp/dist,from=my_app_dist,sharing=locked \
mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist
COPY --from=builder /app/dist /app/dist
```
第一个 `RUN` 指令执行后`id` `my_app_npm_module` 的缓存文件夹挂载到了 `/app/node_modules` 文件夹中多次执行也不会产生多个中间层镜像
第一个 `RUN` 指令执行后`id` `npm_cache` 的缓存文件夹挂载到了 `/root/.npm`后续构建可复用下载缓存
第二个 `RUN` 指令执行时需要用到 `node_modules` 文件夹`node_modules` 已经挂载命令也可以正确执行
第二个 `RUN` 指令执行时`node_modules` 已经作为上一层真实写入到 builder 阶段的文件系统中构建不依赖缓存目录内容
第三个 `RUN` 指令将上一阶段产生的文件复制到指定位置`from` 指明缓存的来源这里 `builder` 表示缓存来源于构建的第一阶段`source` 指明缓存来源的文件夹
最后使用 `COPY --from=builder` 将上一阶段产生的文件复制到最终镜像跨阶段复制构建产物应使用 `COPY --from`如果只是临时读取上一阶段文件可使用 `RUN --mount=type=bind,from=builder,source=/app/dist,target=/tmp/dist,ro`
上面的 `Dockerfile` `--mount=type=cache,...` 中指令作用如下
@@ -105,7 +93,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 +104,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 +115,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 +129,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
@@ -163,4 +151,4 @@ Docker Compose 同样支持 BuildKit,这使得多服务应用的构建更加
### 10.1.3 官方文档
* https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md
* https://docs.docker.com/reference/dockerfile/
+13 -2
View File
@@ -13,6 +13,17 @@ $ docker buildx build .
```
Buildx 使用 [BuildKit 引擎](10.1_buildkit.md)进行构建支持许多新的功能具体参考 [Buildkit](10.1_buildkit.md) 一节
需要注意的是默认 `docker` driver 会把构建结果加载到本地镜像存储使用 `docker-container`remotecloud builder 如未指定 `--load``--push` `--output`结果通常只保留在构建缓存中
#### 构建前检查
Buildx 0.15 起支持构建检查常规构建会默认检查 Dockerfile 与构建参数如果只想做检查而不真正构建可以使用 `--check`
```bash
$ docker buildx build --check .
```
这适合作为 CI 的快速门禁普通构建中的检查告警默认不会让构建失败 `--check` 发现问题会以非零状态退出需要把告警提升为错误时可在 Dockerfile 顶部配合 `# check=error=true`
#### 使用 `bake`
`docker buildx bake` 是一个高级构建命令支持从 HCLJSON Compose 文件中定义构建目标实现复杂的流水线构建
@@ -34,12 +45,12 @@ Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对
```bash
$ docker buildx build --sbom=true -t myimage .
```
该命令会在构建结果中包含 SPDX CycloneDX 格式的 SBOM 数据
该命令会 SBOM 作为构建 attestation 附加到构建结果中BuildKit 默认使用 SPDX SBOM attestation需要 CycloneDX 文件时可使用 SyftDocker Scout 等工具另行生成或转换
> ** 注意与失败模式**
> 要使 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
View File
@@ -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 功能支持
## 本章内容
+1
View File
@@ -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` 生成软件物料清单 |
+24 -5
View File
@@ -1,17 +1,32 @@
## 11.2 安装与卸载
`Compose` Docker 官方的开源项目负责实现 Docker 容器集群的快速编排
`Compose` Docker 官方的开源项目负责实现本地或单机多容器应用的快速编排跨主机集群编排应使用 SwarmKubernetes 或云厂商托管服务
当前的 Compose `docker compose` 子命令的形式提供Docker Desktop macOSWindows Linux 上默认包含它如果你已经在 Linux 上单独安装了 Docker Engine Docker CLI也可以再安装 Compose CLI 插件
### 11.2.1 Linux
Linux 你可以通过 Docker 官方发布页安装 Compose CLI 插件把二进制文件保存到 `$DOCKER_CONFIG/cli-plugins/docker-compose`并赋予执行权限即可
Linux 默认建议通过 Docker 官方软件仓库安装 Compose CLI 插件这样可以随系统包管理器更新
Ubuntu / Debian
```bash
$ sudo apt-get update
$ sudo apt-get install docker-compose-plugin
```
Fedora / CentOS / RHEL 兼容发行版
```bash
$ sudo dnf install docker-compose-plugin
```
如果是离线环境需要锁定特定版本或包管理器暂不覆盖你的架构可以从 Docker 官方发布页手工安装手工安装不会自动更新下载 URL 中的版本号和架构 `x86_64``aarch64`需要按目标机器替换
```bash
$ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
$ mkdir -p $DOCKER_CONFIG/cli-plugins
$ curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
$ curl -SL https://github.com/docker/compose/releases/download/v5.1.2/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
$ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
```
@@ -19,13 +34,17 @@ $ 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 卸载
如果是二进制包方式安装删除二进制文件即可
如果是仓库方式安装使用包管理器卸载如果是二进制包方式安装删除二进制文件即可
```bash
$ sudo apt-get remove docker-compose-plugin
#
$ sudo dnf remove docker-compose-plugin
$ rm $DOCKER_CONFIG/cli-plugins/docker-compose
```
+1 -1
View File
@@ -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"]
+3 -3
View File
@@ -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` 打印版本并退出
@@ -228,7 +228,7 @@ $ docker compose run --no-deps web python manage.py shell
#### `scale`
当前 Compose CLI 更稳妥的扩缩容写法是通过 `docker compose up --scale` 完成
当前 Compose CLI 仍支持 `docker compose scale`实际使用中更常见也更便于和创建/重建流程放在一起的写法是通过 `docker compose up --scale` 完成
例如
@@ -238,7 +238,7 @@ $ docker compose up -d --scale web=3 --scale db=2
将启动 3 个容器运行 `web` 服务2 个容器运行 `db` 服务
> **说明**有些旧环境或实验性入口中仍可能出现 `docker compose scale`但它不应再被视为当前 Compose 的通用稳定默认命令
> **说明**如果 Compose 文件为服务指定了 `container_name`该服务无法扩展到多个容器需要扩缩容的服务应使用 Compose 自动生成的容器名并通过服务名做 DNS 访问
一般的当指定数目多于该服务当前实际运行容器将新创建并启动容器反之将停止容器
+20 -13
View File
@@ -55,7 +55,7 @@ build:
### 11.5.2 `cap_add, cap_drop`
指定容器的内核能力 (capacity) 分配
指定容器的内核能力 (capability) 分配
例如让容器拥有所有能力可以指定为
@@ -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
@@ -583,6 +582,14 @@ $ docker compose --profile debug up # 启动 web + debug
$ docker compose up # 仅启动 web
```
也可以通过环境变量激活
```bash
$ COMPOSE_PROFILES=debug,test docker compose up
```
如果在命令行里显式指定某个带 profile 的服务Compose 会自动启动这个目标服务及其声明的依赖但不会自动启动同一 profile 下的其它服务除非也显式指定或通过 `--profile` / `COMPOSE_PROFILES` 启用
### 11.5.35 读取变量
Compose 模板文件支持动态读取主机的系统环境变量和当前目录下的 `.env` 文件中的变量
+10 -5
View File
@@ -116,7 +116,7 @@ services:
environment:
POSTGRES_DB: django_db
POSTGRES_USER: django_user
POSTGRES_PASSWORD: django_password
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
@@ -136,7 +136,9 @@ services:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://django_user:django_password@db:5432/django_db
# settings.py 直接读取 POSTGRES_PASSWORD必须传入 web 容器
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
DATABASE_URL: postgres://django_user:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/django_db
volumes:
postgres_data:
@@ -153,7 +155,7 @@ db:
environment:
POSTGRES_DB: django_db # 创建的数据库名
POSTGRES_USER: django_user # 数据库用户
POSTGRES_PASSWORD: django_password # 数据库密码
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD} # 数据库密码经环境变量注入不写明文
volumes:
- postgres_data:/var/lib/postgresql/data # 持久化数据
healthcheck: # 健康检查确保数据库就绪
@@ -229,7 +231,7 @@ DATABASES = {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('POSTGRES_DB', 'django_db'),
'USER': os.environ.get('POSTGRES_USER', 'django_user'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', 'django_password'),
'PASSWORD': os.environ['POSTGRES_PASSWORD'],
'HOST': 'db', # Docker Compose 服务名
'PORT': 5432,
}
@@ -239,6 +241,9 @@ DATABASES = {
ALLOWED_HOSTS = ['*']
```
生产环境优先使用 Docker Compose secrets 或外部密钥管理即使是本地示例也不要把固定密码写进 Compose 文件或 Django 默认值中
**为什么 HOST `db` 而不是 `localhost`**
Docker Compose 各服务通过服务名相互访问Docker 内置的 DNS 会将 `db` 解析为 db 服务容器的 IP 地址这是 Docker Compose 的核心功能之一
@@ -328,7 +333,7 @@ $ sudo chown -R $USER:$USER .
|--------|---------|---------|
| **Web 服务器** | `runserver` | `gunicorn` + Nginx |
| **DEBUG** | `True` | `False` |
| **密码管理** | 明文写在配置 | 使用 Docker Secrets 环境变量 |
| **密码管理** | 环境变量注入如本节 `${POSTGRES_PASSWORD:?}` | 使用 Docker Secrets 外部密钥管理 |
| **Volume** | 挂载代码目录 | 代码直接 COPY 进镜像 |
| **ALLOWED_HOSTS** | `['*']` | 具体域名 |
+11 -5
View File
@@ -96,16 +96,21 @@ $ touch Gemfile.lock
### 11.7.5 步骤 3创建 compose.yaml
配置如下
配置如下下面为了本地练习使用环境变量占位不要把真实数据库密码写进 `compose.yaml``.env` Git生产环境应使用 Compose secretsRails credentials 或平台密钥管理
```yaml
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: password
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_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,9 +120,10 @@ services:
ports:
- "3000:3000"
depends_on:
- db
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:password@db:5432/myapp_development
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/myapp_development
volumes:
postgres_data:
@@ -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 项目
+48 -26
View File
@@ -1,10 +1,10 @@
## 11.8 实战 WordPress
> **版本说明**本示例使用以下镜像版本
> - MySQL8.0可替换为其他 8.x 版本或使用 MariaDB 替代
> - MySQL8.4可替换为其他 8.x 版本或使用 MariaDB 替代
> - WordPresslatest建议在生产环境指定具体版本 6.x
WordPress 是全球最流行的内容管理系统 (CMS)使用 Docker Compose 可以在几分钟内搭建一个包含数据库Web 服务和持久化存储的生产级 WordPress 环境
WordPress 是全球最流行的内容管理系统 (CMS)使用 Docker Compose 可以在几分钟内搭建一个包含数据库Web 服务和持久化存储的本地练习/单机演示环境
---
@@ -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`命令行或 GitCompose 官方建议敏感值使用 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. 数据持久化
@@ -138,7 +157,7 @@ $ docker compose logs -f
```bash
## 导出 SQL
$ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup.sql
$ docker compose exec -T db sh -c 'tmp=$(mktemp) && printf "[client]\nuser=wordpress\npassword=%s\n" "$(cat /run/secrets/db_password)" > "$tmp" && mysqldump --defaults-extra-file="$tmp" wordpress; rc=$?; rm -f "$tmp"; exit "$rc"' > backup.sql
```
或者添加一个自动备份容器
@@ -148,12 +167,15 @@ $ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup
volumes:
- ./backups:/backup
environment:
- DB_TYPE=mysql
- DB_HOST=db
- DB_NAME=wordpress
- DB_USER=wordpress
- DB_PASS=${DB_PASSWORD}
- DB_DUMP_FREQ=1440 # 每天备份一次
# tiredofit/db-backup 4.x 起按 DB01_ 前缀配置备份任务并原生支持 _FILE 读密
- DB01_TYPE=mysql
- DB01_HOST=db
- DB01_NAME=wordpress
- DB01_USER=wordpress
- DB01_PASS_FILE=/run/secrets/db_password
- DB01_BACKUP_INTERVAL=1440 # 每天备份一次单位分钟
secrets:
- db_password
depends_on:
- db
networks:
@@ -190,9 +212,9 @@ WordPress 支持 Redis 缓存以提高性能。
**现象**访问页面显示 Error establishing a database connection**排查**
1. 检查 `docker compose logs wordpress`
2. 确认 `.env` 中的密码与 YAML 文件引用一致
2. 确认 `secrets/db_password.txt` 的内容正确且与数据库初始化时使用的密码一致改密码后需要重建 db 数据卷
3. 确认 `WORDPRESS_DB_HOST` 也是 `db` (服务名)
4. MySQL 8.0 可能需要几秒钟启动WordPress 会自动重试稍等片刻即可
4. MySQL 8.4 可能需要几秒钟启动WordPress 会自动重试稍等片刻即可
#### Q无法上传大文件
+1 -1
View File
@@ -1,6 +1,6 @@
# 第十一章 Docker Compose
`Docker Compose` Docker 官方编排 (Orchestration) 项目之一负责快速的部署分布式应用
`Docker Compose` Docker 官方编排 (Orchestration) 项目之一负责快速定义和启动本地或单机多容器应用跨主机集群编排应交给 SwarmKubernetes 或云厂商托管服务
> **重要提示Compose V1 已停止支持**
>
+1 -1
View File
@@ -1,5 +1,5 @@
FROM python:3.12-alpine
ADD . /code
COPY . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
+2 -2
View File
@@ -2,6 +2,6 @@ FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
COPY requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
COPY . /code/
+21 -2
View File
@@ -2,9 +2,18 @@
services:
db:
image: postgres
image: postgres:16
environment:
POSTGRES_PASSWORD: 'postgres'
POSTGRES_DB: django_db
POSTGRES_USER: django_user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U django_user -d django_db"]
interval: 5s
timeout: 5s
retries: 5
web:
build: .
@@ -13,3 +22,13 @@ services:
- .:/code
ports:
- "8000:8000"
depends_on:
db:
condition: service_healthy
environment:
# 与书中 11.6 节一致settings.py 从环境变量读取数据库密码
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
DATABASE_URL: postgres://django_user:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/django_db
volumes:
postgres_data:
+18
View File
@@ -0,0 +1,18 @@
# WordPress Compose 示例
本示例使用 Docker Compose secrets 管理数据库密码启动前需要先创建密钥文件参见书中 11.8
```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
```
然后启动
```bash
docker compose up -d
```
注意`secrets/` 目录不要提交到版本库生产环境应改用平台的密钥管理能力
+17 -6
View File
@@ -2,30 +2,41 @@
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:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_root_password
- db_password
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
- "127.0.0.1:8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
db_data:
secrets:
db_root_password:
file: ./secrets/db_root_password.txt
db_password:
file: ./secrets/db_password.txt
+2 -2
View File
@@ -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
@@ -100,7 +100,7 @@ flowchart TD
Docker Engine v29.x 开始架构进一步简化和标准化
- **Containerd 镜像存储 (Image Store)** v29.x 的新安装场景中默认启用Docker 直接使用 Containerd 的镜像管理能力不再维护自己的一套 graphdriver
- **优势**多平台镜像支持更好镜像拉取更快 (lazy pulling) K8s 共享镜像
- **优势**多平台镜像支持更好可保存 SBOM/Provenance attestations并可使用 containerd snapshotters lazy pulling 等能力
- **实验性 nftables 支持**随着主流 Linux 发行版逐步弃用 iptablesDocker v29.x 引入了实验性 nftables 后端启用方式为 `dockerd --firewall-backend=nftables`可直接创建 nftables 规则而无需依赖 iptables-nft 转换层生产环境请谨慎使用
---
+1 -1
View File
@@ -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
{
+8 -8
View File
@@ -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应用代码
@@ -92,11 +92,11 @@ Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, device
| 存储后端 / 驱动 | 核心特性说明 | 推荐程度 |
|---------|------|---------|
| **containerd image store**| (v29.x 新一代默认后端新装默认) 基于 containerd snapshotters原生支持 OCI image index多架构镜像与 Attestations 构建溯源元数据存储 | **强烈推荐 (现代默认)** |
| **containerd image store**| (v29.x 新一代默认后端新装默认) 基于 containerd snapshotters原生支持 OCI image index多架构镜像与 Attestations 构建溯源元数据存储启用 `userns-remap` 时不可用 | **强烈推荐 (现代默认)** |
| **overlay2**| (经典 Graph Driver) 传统架构下的现代 Linux 默认驱动性能优秀但在处理复杂溯源元数据索引时受限 | **推荐 (主要后备)** |
| **aufs** | 早期默认兼容性好 | 遗留系统 |
| **aufs** | 早期默认已从现代 Docker Engine 移除 | 历史资料 |
| **btrfs**/**zfs** | 使用原生稳定文件系统快照能力 | 特定场景 |
| **devicemapper** | 块设备级存储 | 遗留系统 (已被逐步弃用) |
| **devicemapper** | 块设备级存储已从现代 Docker Engine 移除 | 历史资料 |
| **vfs** | 不使用 CoW每层完整复制 | 仅测试 |
#### Classic Graph Drivers Snapshotters 的核心差异
@@ -104,7 +104,7 @@ Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, device
传统模型 `overlay2`将镜像拉取解包的过程由 Docker graph drivers 处理而新的 `containerd image store` 则将这一职责彻底下放给了 `containerd` 自身的 `snapshotters`底层在 Linux 发行版通常依然利用操作系统的 overlayfs这种架构改变带来了
1. 本地免拉取查看多平台镜像 index manifest attestations (SBOMProvenance)
2. 避免了以前绕过 CRI 获取本地镜像的问题带来更好的原生 Kubernetes 生态兼容性
2. 允许 Docker 使用 containerd snapshotters 管理镜像层便于与现代 OCI 生态能力对齐它不表示 kubelet/containerd 会自动复用 Docker 本地镜像Kubernetes 镜像分发仍应以 registry镜像拉取策略和运行时配置为准
#### 查看当前存储驱动与后端
@@ -114,14 +114,14 @@ $ docker info | grep "Storage Driver"
Storage Driver: overlay2
## Engine v29.x 可以通过如下输出验证是否开启了 containerd 镜像后端
$ docker info | grep "containerd image store"
containerd image store: true
$ docker info -f '{{ .DriverStatus }}'
[[driver-type io.containerd.snapshotter.v1]]
```
---
### 12.4.5 overlay2 工作原理
overlay2 是目前最推荐的存储驱动
在经典 graph driver 体系下overlay2 仍是 Linux 上的主要推荐驱动Docker Engine 29 新安装场景默认走 containerd image store/snapshotter
```mermaid
flowchart TD
+2 -2
View File
@@ -4,9 +4,9 @@
| 技术 | 作用 | 要点 |
|------|------|------|
| **Namespace** | 资源隔离 | PIDNETMNTUTSIPCUSER 六种命名空间 |
| **Namespace** | 资源隔离 | 常见核心包括 PIDNETMNTUTSIPCUSERCgroupTime namespace 通常默认不启用 |
| **Cgroups** | 资源限制 | 限制 CPU内存磁盘 I/O进程数 |
| **Union FS** | 分层存储 | overlay2 为推荐驱动支持 Copy-on-Write |
| **Union FS** | 分层存储 | 镜像分层与 Copy-on-Write 是核心Engine 29 新装默认 containerd image storeoverlay2 是经典 graph driver 场景的主要后备 |
| Namespace | 隔离内容 | 一句话说明 |
|-----------|---------|-----------|
+15 -17
View File
@@ -7,19 +7,18 @@
13-2Kubernetes 基本概念示意图
* 节点 (`Node`)一个节点是一个运行 Kubernetes 中的主机
* 容器组 (`Pod`)一个 Pod 对应于由若干容器组成的一个容器同个组内的容器共享一个存储 (volume)
* 容器组生命周期 (`pod-states`)包含所有容器状态集合包括容器组状态类型容器组生命周期事件重启策略以及 replication controllers
* Replication Controllers主要负责指定数量的 pod 在同一时间一起运行
* 容器组 (`Pod`)Kubernetes 中最小的可部署和调度单元一个 Pod 包含一个或多个紧密协作的容器共享网络身份并可共享一个或多个 (volume)
* 容器组生命周期 (`pod-states`)包含所有容器状态集合包括容器组状态类型容器组生命周期事件重启策略
* 服务 (`services`)一个 Kubernetes 服务是容器组逻辑的高级抽象同时也对外提供访问容器组的策略
* (`volumes`)一个卷就是一个目录容器对其有访问权限
* 标签 (`labels`)标签是用来连接一组对象的比如容器组标签可以被用来组织和选择子对象
* 接口权限 (`accessing_the_api`)端口IP 地址和代理的防火墙规则
* web 界面 (`ux`)用户可以通过 web 界面操作 Kubernetes
* web 界面 (`ux`)用户可以通过 Headlamp 等仍在维护的 web 界面观察和操作 Kubernetes历史 Dashboard 已停止维护
* 命令行操作 (`cli`)`kubectl` 命令
### 13.2.1 节点
`Kubernetes` 节点是实际工作的点节点可以是虚拟机或者物理机器依赖于一个集群环境每个节点都有一些必要的服务以运行容器组并且它们都可以通过主节点来管理必要服务包括 Dockerkubelet 和代理服务
`Kubernetes` 节点是实际工作的点节点可以是虚拟机或者物理机器依赖于一个集群环境每个节点都有一些必要的组件以运行容器组并且它们都可以通过控制平面来管理必要组件包括 kubelet容器运行时 containerd CRI-O kube-proxyDocker 不再是 Kubernetes 节点的默认基线运行时
#### 容器状态
@@ -29,13 +28,11 @@
主机 IP 需要云平台来查询`Kubernetes` 把它作为状态的一部分来保存如果 `Kubernetes` 没有运行在云平台上节点 ID 就是必需的IP 地址可以变化并且可以包含多种类型的 IP 地址如公共 IP私有 IP动态 IPipv6 等等
##### 节点周期
通常来说节点有 `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 会被驱逐重新调度到其他节点
#### 节点管理
@@ -85,7 +82,7 @@ $ kubectl drain worker-1 --ignore-daemonsets
### 13.2.2 容器组
Kubernetes 使用的最小调度单位是容器组 (Pod)它是创建调度管理的最小单位一个 Pod 包含一个或多个紧密协作的容器它们共享网络命名空间存储卷
Kubernetes 使用的最小调度单位是容器组 (Pod)它是创建调度管理的最小单位一个 Pod 包含一个或多个紧密协作的容器它们共享网络命名空间并可共享一个或多个存储卷
Pod 通常不会被直接创建而是通过 Deployment 等控制器来管理当节点发生故障时控制器会在其他可用节点上重新创建 Pod
@@ -97,9 +94,9 @@ Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理
容器组主要是为了数据共享和它们之间的通信
在一个容器组中容器都使用相同的网络地址和端口可以通过本地网络来相互通信每个容器组都有独立的 IP通过网络来和其他物理主机或者容器通信
在一个容器组中容器都使用相同的网络地址和端口可以通过本地网络来相互通信每个容器组都有独立的 IP通过网络来和其他物理主机或者容器通信
容器组一组存储卷 (挂载点)主要是为了让容器在重启之后可以不丢失数据
容器组可以挂载一组存储卷 (挂载点)卷不只用于持久化也可用于 `emptyDir` 临时交换ConfigMap/Secret 投射日志旁路收集等场景真正需要跨 Pod 生命周期保留的数据应使用 PersistentVolume / PersistentVolumeClaim 等持久化机制
#### 容器组管理
@@ -124,7 +121,7 @@ Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理
#### 容器组的生命状态
包括若干状态值`Pending``Running``Succeeded``Failed`
Pod phase 包括若干状态值`Pending``Running``Succeeded``Failed``Unknown`
| 状态 | 说明 |
|------|------|
@@ -132,6 +129,7 @@ Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理
| **Running** | Pod 已被调度到节点并且所有容器都已启动至少有一个容器处于运行状态|
| **Succeeded** | Pod 中的所有容器都正常退出且不会被重启|
| **Failed** | Pod 中的所有容器都已终止且至少有一个容器以失败状态退出|
| **Unknown** | 集群无法获取 Pod 状态常见原因是节点失联|
#### 容器组生命周期与重启策略
@@ -143,7 +141,7 @@ Pod 的重启策略 (`restartPolicy`) 决定了容器退出后的行为:
| **OnFailure** | 不重启 | 重启容器 |
| **Never** | 不重启 | 不重启 |
当节点故障或不可达时节点控制器会将该节点上所有 Pod 的状态标记 `Failed`如果这些 Pod Deployment 等控制器管理控制器会自动在其他节点上重新创建
当节点故障或不可达时Pod 可能先表现为 `Unknown`之后根据控制器驱逐策略和垃圾回收机制转 `Failed` 或被重新创建如果这些 Pod Deployment 等控制器管理控制器会自动在其他节点上重新创建
### 13.2.3 Deployment ReplicaSet
@@ -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
+1 -1
View File
@@ -39,7 +39,7 @@
#### Etcd
这里 Etcd 作为数据后端又作为消息中间件
这里 Etcd 作为数据后端又作为消息中间件
通过 Etcd 来存储所有的主节点上的状态信息很容易实现主节点的分布式扩展
+6 -1
View File
@@ -62,6 +62,7 @@ Ingress 资源仍可正常使用,但建议新项目直接采用 Gateway API。
* **PVC (Persistent Volume Claim)**用户申请存储的声明
* **PV (Persistent Volume)**实际的存储资源 (NFSAWS EBSCeph )
* **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
+19 -5
View File
@@ -1,12 +1,18 @@
## 13.5 实战练习
本章将通过一个具体的案例部署一个 Nginx 网站并为其配置 Service Ingress来串联前面学到的知识
本章将通过一个具体的案例部署一个 Nginx 网站并为其配置 Service来串联前面学到的知识
开始前请先准备好可用的 Kubernetes 集群和 `kubectl` 上下文你可以先完成 [14.3 Docker Desktop](../14_kubernetes_setup/14.3_docker-desktop.md) [14.4 Kind](../14_kubernetes_setup/14.4_kind.md)并确认
```bash
kubectl get nodes
```
### 13.5.1 目标
1. 部署一个 Nginx Deployment
2. 创建一个 Service 暴露 Nginx
3. (可选) 通过 Ingress 访问服务
3. 通过端口转发或 NodePort 访问服务
### 13.5.2 步骤 1创建 Deployment
@@ -31,7 +37,7 @@ spec:
spec:
containers:
- name: nginx
image: nginx:1.30
image: nginx:1.28
ports:
- containerPort: 80
```
@@ -69,11 +75,19 @@ kubectl apply -f nginx-service.yaml
```bash
kubectl get svc nginx-service
```
如果输出端口是 `80:30080/TCP`你可以通过 `http://<NodeIP>:30080` 访问 Nginx
如果输出端口是 `80:30080/TCP`你可以通过 `http://<NodeIP>:30080` 访问 NginxDocker DesktopKind 等本地集群中NodePort 到宿主机的可达性取决于集群实现更稳定的本地访问方式是端口转发
```bash
kubectl port-forward svc/nginx-service 8080:80
```
然后访问 `http://localhost:8080`
> Ingress 只有在集群中已安装 Ingress controller 且配置了 IngressClass 时才会生效当前练习只覆盖 ServiceIngress/Gateway API 建议在完成第 14 章后再单独练习
### 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
+2
View File
@@ -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)
+18 -15
View File
@@ -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
@@ -169,24 +171,23 @@ $ sudo systemctl enable containerd
$ sudo systemctl start containerd
$ 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 默认使用 `registry.k8s.io` 拉取 Kubernetes 控制平面镜像受限网络环境可通过 kubeadm 配置文件中的 `imageRepository` 指向受信任镜像仓库不要把第三方镜像仓库当成通用默认值
> 执行可能出现错误例如缺少依赖包根据提示安装即可
> `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
+25 -21
View File
@@ -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
@@ -195,25 +197,24 @@ $ sudo systemctl daemon-reload
#### master
```bash
$ sudo kubeadm init --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers \
--pod-network-cidr 10.244.0.0/16 \
$ sudo kubeadm init --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 默认使用 `registry.k8s.io` 拉取 Kubernetes 控制平面镜像受限网络环境可通过 kubeadm 配置文件中的 `imageRepository` 指向受信任镜像仓库不要把第三方镜像仓库当成通用默认值
> 执行可能出现错误例如缺少依赖包根据提示安装即可
> `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
+5 -3
View File
@@ -4,15 +4,17 @@
### 14.3.1 启用 Kubernetes
Docker Desktop 设置页面点击 `Kubernetes`选择 `Enable Kubernetes`稍等片刻看到左下方 `Kubernetes` 变为 `running`Kubernetes 启动成功
Docker Desktop 设置页面进入 `Kubernetes`创建或启用集群较新的 Docker Desktop 可选择 `kind` `kubeadm` 作为集群创建方式日常本地开发优先选择 `kind`因为它支持多节点和版本选择
![](../_images/settings-kubernetes.png)
> 注意Kubernetes 的镜像存储在 `registry.k8s.io`如果国内网络无法直接访问可以在 Docker Desktop 配置中 `Docker Engine` 处配置镜像加速器或者利用国内云服务商的镜像仓库手动拉取镜像并 retag
> 注意Docker Desktop Kubernetes 的控制平面镜像默认从 Docker Hub 拉取例如 `docker.io/docker/desktop-*` `docker.io/kindest/node:<tag>`如果企业网络不能访问 Docker Hub应按 Docker Desktop `KubernetesImagesRepository` 设置镜像仓库并用 `docker desktop kubernetes images list`Docker Desktop 4.44+ `docker ps` 确认实际镜像标签普通 Docker Engine `registry-mirrors` 不会自动改写这些控制平面镜像
### 14.3.2 测试
```bash
$ kubectl version
$ kubectl config use-context docker-desktop
$ kubectl get nodes
```
如果正常输出信息则证明 Kubernetes 成功启动
如果 `kubectl get nodes` 显示节点为 `Ready`则证明 Kubernetes 成功启动
+1 -1
View File
@@ -15,7 +15,7 @@ Kind 相比其他本地集群方案 (如 Minikube) 有以下显著优势:
### 14.4.2 安装 Kind
Kind 是一个二进制文件并在 PATH 中即可使用以下是不同系统的安装方法
Kind 是一个二进制文件放到 PATH 中即可使用以下是不同系统的安装方法
#### macOS
+1 -1
View File
@@ -17,7 +17,7 @@ K3s 的安装非常简单,官方提供了便捷的安装脚本。
#### 脚本安装
K3s 提供了极为便捷的安装脚本
K3s 提供了极为便捷的安装脚本该命令会从网络下载脚本并直接交给 `sh` 执行生产环境建议先下载审查脚本内容并按官方文档固定版本或安装参数
```bash
curl -sfL https://get.k3s.io | sh -
+28 -11
View File
@@ -1,23 +1,38 @@
## 14.7 部署 Dashboard
## 14.7 可视化管理界面
[Kubernetes Dashboard](https://github.com/kubernetes/dashboard) 是基于网页的 Kubernetes 用户界面
[Kubernetes Dashboard](https://github.com/kubernetes-retired/dashboard) 是历史上常用的 Kubernetes Web UI,但项目已停止维护
> **注意** `kubernetes/dashboard` 项目已于 2026 1 21 日归档停止维护推荐使用 [Headlamp](https://headlamp.dev/) 等替代方案。以下内容仅供历史参考,基于归档前的最新 Helm 安装方式
> **注意**Kubernetes 官方文档已将 Dashboard 标记为 deprecated and unmaintained新安装建议考虑 [Headlamp](https://headlamp.dev/) 等仍在维护的替代方案。以下 Dashboard 内容仅供历史迁移或存量环境参考
![](../_images/kubernetes-dashboard-ui.png)
### 14.7.1 部署
### 14.7.1 推荐替代Headlamp
Headlamp Kubernetes SIG UI 下的现代 Web UI可通过 Helm 安装
```bash
$ helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
$ helm install headlamp headlamp/headlamp --namespace kube-system
```
本地访问时优先使用端口转发避免直接把管理界面暴露到公网
```bash
$ kubectl -n kube-system port-forward svc/headlamp 4466:80
```
### 14.7.2 历史 Dashboard 部署
Dashboard 7.0+ 版本仅支持通过 Helm 安装
```bash
$ helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
$ helm repo add kubernetes-dashboard https://kubernetes-retired.github.io/dashboard/
$ helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard \
--create-namespace --namespace kubernetes-dashboard
```
### 14.7.2 访问
### 14.7.3 访问
通过端口转发访问 Dashboard
@@ -27,16 +42,18 @@ $ kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-pro
然后在浏览器打开 `https://localhost:8443` 即可访问
### 14.7.3 登录
### 14.7.4 登录
创建管理员服务账户并获取登录令牌
为历史 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 clusterrolebinding dashboard-readonly \
--clusterrole=view \
--serviceaccount=kubernetes-dashboard:dashboard-readonly
$ kubectl create token dashboard-admin -n kubernetes-dashboard
$ kubectl create token dashboard-readonly -n kubernetes-dashboard --duration=1h
```
将输出的令牌粘贴到登录页面即可登录
+5 -3
View File
@@ -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

Some files were not shown because too many files have changed in this diff Show More