├── .devcontainer └── devcontainer.json ├── .docker └── docker-entrypoint.sh ├── .drone.yml ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ ├── Custom.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── check-link.yml │ └── ci.yaml ├── .gitignore ├── .travis ├── Dockerfile ├── book.json ├── conf.d │ └── nginx.conf ├── docker-compose.test.yml ├── docker-entrypoint.sh └── update.sh ├── .vuepress ├── .gitignore └── config.js ├── CHANGELOG.md ├── CONTRIBUTING.md ├── README.md ├── SUMMARY.md ├── _config.yml ├── _images ├── cover.jpg ├── cover.png ├── cover.sketch ├── cover_small.jpg ├── docker_primer.png ├── docker_primer2.png ├── docker_primer3.png └── donate.jpeg ├── advanced_network ├── README.md ├── _images │ └── network.png ├── access_control.md ├── bridge.md ├── config_file.md ├── docker0.md ├── example.md ├── how_connect.md ├── port_mapping.md ├── ptp.md └── quick_guide.md ├── appendix ├── README.md ├── _images │ ├── cmd_logic.dot │ ├── cmd_logic.dot.bak │ ├── cmd_logic.graffle │ │ ├── data.plist │ │ ├── image10.pdf │ │ ├── image11.pdf │ │ ├── image12.pdf │ │ ├── image13.pdf │ │ ├── image4.pdf │ │ ├── image5.pdf │ │ ├── image6.pdf │ │ ├── image7.pdf │ │ └── image9.pdf │ ├── cmd_logic.png │ ├── container_status.dot │ └── container_status.png ├── best_practices.md ├── command │ ├── README.md │ ├── docker.md │ └── dockerd.md ├── debug.md ├── faq │ └── README.md ├── repo │ ├── README.md │ ├── centos.md │ ├── minio.md │ ├── mongodb.md │ ├── mysql.md │ ├── nginx.md │ ├── nodejs.md │ ├── php.md │ ├── redis.md │ ├── ubuntu.md │ └── wordpress.md └── resources.md ├── archive └── README.md ├── basic_concept ├── README.md ├── container.md ├── image.md └── repository.md ├── book.json ├── buildx ├── README.md ├── buildkit.md ├── buildx.md └── multi-arch-images.md ├── cases ├── ci │ ├── README.md │ ├── actions │ │ └── README.md │ └── drone │ │ ├── .env.example │ │ ├── .gitignore │ │ ├── README.md │ │ ├── _images │ │ └── drone-build.png │ │ ├── demo │ │ ├── .drone.yml │ │ ├── README.md │ │ └── app.go │ │ ├── docker-compose.yml │ │ └── install.md └── os │ ├── README.md │ ├── _images │ ├── alpinelinux-logo.png │ ├── busybox-logo.png │ ├── centos-logo.png │ ├── coreos-login.png │ ├── coreos-logo.jpg │ ├── coreos_crt.png │ ├── coreos_list.png │ ├── coreos_run_ip.png │ ├── debian-logo.png │ ├── docker_version.png │ ├── fedora-logo.png │ ├── php_pulling.png │ ├── ubuntu-logo.jpg │ └── vmware_coreos.png │ ├── alpine.md │ ├── busybox.md │ ├── centos.md │ ├── debian.md │ └── summary.md ├── cloud ├── README.md ├── _images │ ├── ECS.jpg │ ├── aliyun-logo.png │ ├── aws-logo.jpg │ └── qcloud-logo.jpg ├── alicloud.md ├── aws.md ├── intro.md ├── summary.md └── tencentCloud.md ├── compose ├── README.md ├── commands.md ├── compose_file.md ├── demo │ ├── app │ │ ├── Dockerfile │ │ ├── app.py │ │ └── docker-compose.yml │ ├── django │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── docker-compose.yml │ │ └── requirements.txt │ └── wordpress │ │ └── docker-compose.yml ├── django.md ├── install.md ├── introduction.md ├── lnmp.md ├── rails.md ├── usage.md └── wordpress.md ├── container ├── README.md ├── attach_exec.md ├── daemon.md ├── import_export.md ├── rm.md ├── run.md └── stop.md ├── coreos ├── README.md ├── demo │ └── example.fcc ├── install.md └── intro.md ├── cover.jpg ├── data_management ├── README.md ├── _images │ └── types-of-mounts.png ├── bind-mounts.md └── volume.md ├── docker-compose.yml ├── etcd ├── README.md ├── _images │ └── etcd_logo.png ├── cluster.md ├── demo │ └── cluster │ │ └── docker-compose.yml ├── etcdctl-v2.md ├── etcdctl.md ├── install.md └── intro.md ├── ide ├── README.md └── vsCode.md ├── image ├── README.md ├── _images │ ├── images-create-nginx-docker.png │ └── images-mac-example-nginx.png ├── build.md ├── commit.md ├── demo │ ├── buildkit │ │ ├── Dockerfile │ │ ├── Dockerfile.buildkit │ │ ├── aws.txt │ │ ├── package.json │ │ └── src │ │ │ └── index.js │ ├── multi-arch │ │ └── Dockerfile │ └── multistage-builds │ │ ├── .gitignore │ │ ├── Dockerfile │ │ ├── Dockerfile.build │ │ ├── Dockerfile.copy │ │ ├── Dockerfile.one │ │ ├── app.go │ │ └── build.sh ├── dockerfile │ ├── README.md │ ├── add.md │ ├── arg.md │ ├── cmd.md │ ├── copy.md │ ├── entrypoint.md │ ├── env.md │ ├── expose.md │ ├── healthcheck.md │ ├── label.md │ ├── onbuild.md │ ├── references.md │ ├── shell.md │ ├── user.md │ ├── volume.md │ └── workdir.md ├── internal.md ├── list.md ├── manifest.md ├── multistage-builds │ ├── README.md │ ├── example │ │ └── laravel │ │ │ ├── .dockerignore │ │ │ ├── Dockerfile │ │ │ └── laravel.conf │ └── laravel.md ├── other.md ├── pull.md └── rm.md ├── install ├── README.md ├── _images │ ├── image-20200412202617411.png │ ├── install-mac-apps.png │ ├── install-mac-dmg.png │ ├── install-mac-example-nginx.png │ ├── install-mac-menu.png │ ├── install-mac-menubar.png │ ├── install-win-docker-app-search.png │ └── install-win-taskbar-circle.png ├── centos.md ├── debian.md ├── experimental.md ├── fedora.md ├── mac.md ├── mirror.md ├── offline.md ├── raspberry-pi.md ├── ubuntu.md └── windows.md ├── introduction ├── README.md ├── _images │ ├── docker.png │ └── virtualization.png ├── what.md └── why.md ├── kubernetes ├── README.md ├── _images │ ├── k8s-singlenode-docker.png │ ├── k8s_architecture.png │ ├── kube-proxy.png │ ├── kubernetes_design.jpg │ ├── kubernetes_logo.png │ └── kubernetes_logo.svg ├── advanced.md ├── concepts.md ├── design.md ├── intro.md ├── kubectl │ └── README.md ├── practice.md └── setup │ ├── README.md │ ├── dashboard.md │ ├── docker-desktop.md │ ├── k3s.md │ ├── kind.md │ ├── kubeadm-docker.md │ ├── kubeadm.md │ └── systemd.md ├── manifest ├── network ├── README.md ├── dns.md ├── linking.md └── port_mapping.md ├── package.json ├── podman └── README.md ├── repository ├── README.md ├── demo │ ├── auth │ │ └── nginx.htpasswd │ ├── config.yml │ ├── docker-compose.yml │ ├── root-ca.cnf │ ├── site.cnf │ └── ssl │ │ ├── docker.domain.com.crt │ │ └── docker.domain.com.key ├── dockerhub.md ├── nexus3_registry.md ├── registry.md └── registry_auth.md ├── security ├── README.md ├── control_group.md ├── daemon_sec.md ├── kernel_capability.md ├── kernel_ns.md ├── other_feature.md └── summary.md ├── swarm_mode ├── README.md ├── config.md ├── create.md ├── demo │ └── docker-compose.yml ├── deploy.md ├── image │ └── wordpress.png ├── overview.md ├── rolling_update.md ├── secret.md └── stack.md └── underly ├── README.md ├── _images └── docker_arch.png ├── arch.md ├── cgroups.md ├── container_format.md ├── namespace.md ├── network.md └── ufs.md /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // https://code.visualstudio.com/docs/remote/devcontainerjson-reference 2 | 3 | { 4 | "image": "yeasy/docker_practice:latest", 5 | "mounts": [ 6 | "source=dp-code-remote-cache,target=/root/.vscode-server,type=volume" 7 | ], 8 | "settings": { 9 | "terminal.integrated.shell.linux": "/bin/sh" 10 | }, 11 | "forwardPorts": [ 12 | 4000 13 | ], 14 | "runArgs": [ 15 | "--cap-add=SYS_ADMIN" 16 | ], 17 | "postStartCommand": [ 18 | "sh", 19 | "-cx", 20 | "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" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.docker/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | echo 4 | echo 5 | echo "Please open your browser: 127.0.0.1:4000" 6 | echo 7 | echo "欢迎加入 QQ 群:【 145983035 】 分享 Docker 资源,交流 Docker 技术" 8 | echo 9 | echo 10 | 11 | exec nginx -g "daemon off;" 12 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | kind: pipeline 2 | type: docker 3 | name: build 4 | steps: 5 | - name: build 6 | image: yeasy/docker_practice:latest 7 | pull: if-not-exists # always never 8 | environment: 9 | TZ: Asia/Shanghai 10 | commands: 11 | - docker-entrypoint.sh build 12 | 13 | trigger: 14 | branch: 15 | - master 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | 7 | indent_style = space 8 | 9 | indent_size = 2 10 | 11 | end_of_line = lf 12 | 13 | charset = utf-8 14 | 15 | trim_trailing_whitespace = true 16 | 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | 21 | trim_trailing_whitespace = false 22 | 23 | [*.py] 24 | 25 | indent_size = 4 26 | 27 | [Makefile] 28 | 29 | indent_style = tab 30 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.sh text eol=lf 4 | 5 | * linguist-language=go 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @yeasy @khs1994 2 | /.github/* @khs1994 3 | /.travis/* @khs1994 4 | /.vuepress/* @khs1994 5 | /advanced_network/* @yeasy @khs1994 6 | /appendix/* @yeasy @khs1994 7 | /archive/* @khs1994 8 | /basic_concept/* @yeasy @khs1994 9 | /buildx/* @khs1994 10 | /cases/* @yeasy @khs1994 11 | /cloud/* @khs1994 12 | /compose/* @yeasy @khs1994 13 | /container/* @yeasy @khs1994 14 | /coreos/* @khs1994 15 | /data_management/* @khs1994 16 | /etcd/* @khs1994 17 | /IDE/* @khs1994 18 | /image/* @yeasy @khs1994 19 | /install/* @khs1994 20 | /introduction/* @yeasy @khs1994 21 | /kubernetes/* @yeasy @khs1994 22 | /network/* @yeasy @khs1994 23 | /opensource/* @khs1994 24 | /repository/* @khs1994 25 | /security/* @yeasy @khs1994 26 | /underly/* @yeasy @khs1994 27 | /.drone.yml @khs1994 28 | /.editorconfig/ @khs1994 29 | /.gitattributes @khs1994 30 | /.gitignore @khs1994 31 | /_config.yml @yeasy @khs1994 32 | /book.json @yeasy @khs1994 33 | /CHANGELOG.md @yeasy @khs1994 34 | /CONTRIBUTING.md @yeasy @khs1994 35 | /docker-compose.yml @khs1994 36 | /manifest @khs1994 37 | /package.json @khs1994 38 | /README.md @yeasy @khs1994 39 | /SUMMARY.md @yeasy @khs1994 40 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: yeasy 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | * [ ] Have u googled the problem? If no, pls do that first! 8 | 9 | ### Environment 10 | 11 | 12 | 13 | * [x] Linux 14 | * [x] CentOS 7 15 | * [x] Fedora 16 | * [x] Ubuntu 16.04 + 17 | * [x] Debian 9 + 18 | * [x] macOS 19 | * [x] Windows 10 20 | * [x] Raspberry Pi (ARM) 21 | * [x] Others (Pls describe below) 22 | 23 | ### Docker Version 24 | 25 | 26 | 27 | * [x] Test (v20.10) 28 | * [x] Stable (v20.10) 29 | * [x] 1.13.0 or Before 30 | 31 | ### Problem Description 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Create a issue about Docker 4 | 5 | --- 6 | 7 | * [ ] Have u googled the problem? If no, pls do that first! 8 | 9 | ### Environment 10 | 11 | 12 | 13 | * [x] Linux 14 | * [x] CentOS 7 15 | * [x] Fedora 16 | * [x] Ubuntu 16.04 + 17 | * [x] Debian 9 + 18 | * [x] macOS 19 | * [x] Windows 10 20 | * [x] Raspberry Pi (ARM) 21 | * [x] Others (Pls describe below) 22 | 23 | ### Docker Version 24 | 25 | 26 | 27 | * [x] Test (v20.10) 28 | * [x] Stable (v20.10) 29 | * [x] 1.13.0 or Before 30 | 31 | ### Problem Description 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for docker_practice 4 | 5 | --- 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | **Proposed changes (Mandatory)** 7 | 8 | 15 | 16 | **Fix issues (Optional)** 17 | 18 | 21 | -------------------------------------------------------------------------------- /.github/workflows/check-link.yml: -------------------------------------------------------------------------------- 1 | name: Check link 2 | 3 | on: 4 | # push: 5 | # pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | check-link: 10 | name: check-link 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@master 14 | with: 15 | fetch-depth: 1 16 | # search Issues :-( 17 | - run: | 18 | docker run -i --rm \ 19 | -v $PWD:/mnt:ro \ 20 | dkhamsing/awesome_bot \ 21 | --white-list "localhost","0.0.0.0",\ 22 | "server","example.com","docker",\ 23 | "docker.domain.com","YourIP","register",\ 24 | "172.16.238.100","172.16.238.101","172.16.238.102",\ 25 | "192.168.199.100",\ 26 | "github.com/settings",\ 27 | "github.com/docker/compose/releases/download",\ 28 | "github.com/etcd-io/etcd/releases/download",\ 29 | "github.com/tianon/gosu/releases/download",\ 30 | "github.com/yeasy/docker_practice",\ 31 | "github.com/AliyunContainerService/k8s-for-docker-desktop/raw",\ 32 | "dl-cdn.alpinelinux.org/alpine/edge/testing",\ 33 | "www.w3.org/1999/xhtml",\ 34 | "cr.console.aliyun.com",\ 35 | "cloud.tencent.com",\ 36 | "nodejs.org/dist/",\ 37 | "c.163.com/hub",\ 38 | "drone.yeasy.com",\ 39 | "docs.docker.com",\ 40 | "dockerhub.azk8s.cn",\ 41 | "reg-mirror.qiniu.com",\ 42 | "registry.docker-cn.com",\ 43 | "mirror.ccs.tencentyun.com",\ 44 | "vuepress.mirror.docker-practice.com",\ 45 | "mc.qcloudimg.com/static/img",\ 46 | "www.daocloud.io/mirror",\ 47 | "download.docker.com",\ 48 | "www.ubuntu.com",\ 49 | "archive.ubuntu.com",\ 50 | "security.ubuntu.com/ubuntu",\ 51 | "nginx.com",\ 52 | "img.shields.io/github/release/yeasy/docker_practice",\ 53 | "launchpad.net",\ 54 | "www.w3.org/1999",\ 55 | "chat.freenode.net",\ 56 | "en.wikipedia.org/wiki/UnionFS",\ 57 | "product.china-pub.com",\ 58 | "union-click.jd.com",\ 59 | "x.x.x.x/base",\ 60 | "x.x.x.x:9090",\ 61 | "yeasy.gitbooks.io",\ 62 | "download.fastgit.org",\ 63 | "www.aliyun.com" \ 64 | --allow-dupe \ 65 | --skip-save-results \ 66 | -t 10 \ 67 | `find . \( -path "./mesos" -o -path "./swarm_mode" \) -prune -o -name "*.md" -exec ls {} \;` 68 | name: check-link 69 | timeout-minutes: 25 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .gitignore support plugin (hsz.mobi) 2 | *.~ 3 | *.tmp 4 | .idea/ 5 | _book/ 6 | *.swp 7 | *.edx 8 | .DS_Store 9 | 10 | node_modules/ 11 | package-lock.json 12 | 13 | docker-compose.override.yml 14 | -------------------------------------------------------------------------------- /.travis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.4.0-alpine 2 | 3 | ENV TZ=Asia/Shanghai 4 | 5 | WORKDIR /srv/gitbook 6 | 7 | COPY book.json book.json 8 | 9 | COPY docker-entrypoint.sh /usr/local/bin/ 10 | 11 | RUN set -x && apk add --no-cache \ 12 | tzdata bash \ 13 | && npm install -g gitbook-cli \ 14 | && gitbook install \ 15 | && ln -s /usr/local/bin/docker-entrypoint.sh / \ 16 | && rm -rf /root/.npm /tmp/* 17 | 18 | EXPOSE 4000 19 | 20 | VOLUME /srv/gitbook-src 21 | 22 | WORKDIR /srv/gitbook-src 23 | 24 | ENTRYPOINT ["docker-entrypoint.sh"] 25 | 26 | CMD server 27 | -------------------------------------------------------------------------------- /.travis/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Docker -- 从入门到实践", 3 | "author": "yeasy", 4 | "language": "zh-hans", 5 | "links": { 6 | "sidebar": { 7 | "GitHub": "https://github.com/yeasy/docker_practice" 8 | } 9 | }, 10 | "plugins": [ 11 | "-livereload", 12 | "image-captions", 13 | "github", 14 | "page-treeview@2.9.8", 15 | "editlink" 16 | ], 17 | "pluginsConfig": { 18 | "image-captions": { 19 | "attributes": { 20 | "width": "600" 21 | }, 22 | "caption": "图 _PAGE_LEVEL_._PAGE_IMAGE_NUMBER_ - _CAPTION_" 23 | }, 24 | "github": { 25 | "url": "https://github.com/yeasy/docker_practice" 26 | }, 27 | "editlink": { 28 | "base": "https://github.com/yeasy/docker_practice/blob/master/", 29 | "label": "编辑本页" 30 | }, 31 | "page-treeview": { 32 | "copyright": "Copyright © yeasy", 33 | "minHeaderCount": "2", 34 | "minHeaderDeep": "2" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.travis/conf.d/nginx.conf: -------------------------------------------------------------------------------- 1 | user root; 2 | worker_processes auto; 3 | 4 | error_log /var/log/nginx/error.log warn; 5 | pid /var/run/nginx.pid; 6 | 7 | 8 | events { 9 | worker_connections 1024; 10 | } 11 | 12 | 13 | http { 14 | include /etc/nginx/mime.types; 15 | default_type application/octet-stream; 16 | 17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 18 | '$status $body_bytes_sent "$http_referer" ' 19 | '"$http_user_agent" "$http_x_forwarded_for"'; 20 | 21 | access_log /var/log/nginx/access.log main; 22 | 23 | sendfile on; 24 | #tcp_nopush on; 25 | 26 | keepalive_timeout 65; 27 | 28 | #gzip on; 29 | 30 | index index.html index.php; 31 | 32 | server { 33 | 34 | server_name localhost; 35 | 36 | listen 4000; 37 | 38 | root /srv/www/; 39 | 40 | index index.html; 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.travis/docker-compose.test.yml: -------------------------------------------------------------------------------- 1 | sut: 2 | build: . 3 | volumes: 4 | - ../:/srv/gitbook-src 5 | command: build 6 | -------------------------------------------------------------------------------- /.travis/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | START=`date "+%F %T"` 4 | 5 | if [ $1 = "sh" ];then sh ; exit 0; fi 6 | 7 | rm -rf node_modules _book 8 | 9 | srcDir=$PWD 10 | 11 | cp -a . /srv/gitbook 12 | 13 | cd /srv/gitbook 14 | 15 | main(){ 16 | if [ "$1" = build ];then 17 | gitbook build && cp -a _book $srcDir && echo $START && date "+%F %T" && exit 0 18 | else 19 | exec gitbook serve 20 | fi 21 | } 22 | 23 | main $1 $2 $3 24 | -------------------------------------------------------------------------------- /.travis/update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # cd .travis 4 | # ./update.sh 5 | 6 | if [ ! -f Dockerfile ];then exit 1; fi 7 | 8 | cp -a ../book.json book.json 9 | -------------------------------------------------------------------------------- /.vuepress/.gitignore: -------------------------------------------------------------------------------- 1 | /* 2 | !.gitignore 3 | !config.js 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 修订记录 2 | 3 | * 1.4.0 2022-MM-DD 4 | * 以 Docker Compose v2 为例介绍 compose 5 | 6 | * 1.3.0 2021-12-02 7 | * 全面支持 Docker v20.10 新版本 8 | * 新增 Docker Compose v2 9 | * Docker Hub 自动构建转为付费功能 10 | 11 | * 1.2.0 2020-12-20 12 | * 错误修复 13 | 14 | * 1.1.0 2019-12-31 15 | * 全面支持 Docker v19.03 新版本 16 | * 增加 `BuildKit` 17 | * 增加 `docker buildx` 命令使用说明 18 | * 增加 `docker manifest` 命令使用说明 19 | * 移除 `Ubuntu 14.04` `Debian 8` `Debian 7` 20 | 21 | * 1.0.0: 2018-12-31 22 | * 全面支持 Docker v18.x 新版本 23 | * 添加如何调试 Docker 24 | * 错误修正 25 | 26 | * 0.9.0: 2017-12-31 27 | * 对 v1.13.x 旧版本的最后支持 28 | 29 | * 0.9.0-rc2: 2017-12-10 30 | 31 | * 增加 Docker 中文资源链接 32 | * 增加介绍基于 Docker 的 CI/CD 工具 `Drone` 33 | * 增加 `docker secret` 相关内容 34 | * 增加 `docker config` 相关内容 35 | * 增加 `LinuxKit` 相关内容 36 | 37 | * 更新 `CoreOS` 章节 38 | * 更新 `etcd` 章节,基于 3.x 版本 39 | 40 | * 删除 `Docker Compose` 中的 `links`指令 41 | 42 | * 替换 `docker daemon` 命令为 `dockerd` 43 | * 替换 `docker ps` 命令为 `docker container ls` 44 | * 替换 `docker images` 命令为 `docker image ls` 45 | 46 | * 修改 `安装 Docker` 一节中部分文字表述 47 | 48 | * 移除历史遗留文件和错误的文件 49 | * 优化文字排版 50 | * 调整目录结构 51 | * 修复内容逻辑错误 52 | * 修复`404` 链接 53 | 54 | * 0.9.0-rc1: 2017-11-29 55 | 56 | * 根据最新版本(v17.09)修订内容 57 | 58 | * 增加 `Dockerfile` 多阶段构建( `multistage builds` ) `Docker 17.05` 新增特性 59 | * 增加 `docker exec` 子命令介绍 60 | * 增加 `docker` 管理子命令 `container` `image` `network` `volume` 介绍 61 | * 增加 `树莓派单片电脑` 安装 Docker 62 | * 增加 Docker 存储驱动 `OverlayFS` 相关内容 63 | 64 | * 更新 `Docker CE` `v17.x` 安装说明 65 | * 更新 `Docker 网络` 一节 66 | * 更新 `Docker Machine` 基于 0.13.0 版本 67 | * 更新 `Docker Compose` 基于 3 文件格式 68 | 69 | * 删除 `Docker Swarm` 相关内容,替换为 `Swarm mode` `Docker 1.12.0` 新增特性 70 | * 删除 `docker run` `--link` 参数 71 | 72 | * 精简 `Docker Registry` 一节 73 | 74 | * 替换 `docker run` `-v` 参数为 `--mount` 75 | 76 | * 修复 `404` 链接 77 | * 优化文字排版 78 | * 增加离线阅读功能 79 | 80 | * 0.8.0: 2017-01-08 81 | 82 | * 修正文字内容 83 | * 根据最新版本(1.12)修订安装使用 84 | * 补充附录章节 85 | 86 | * 0.7.0: 2016-06-12 87 | 88 | * 根据最新版本进行命令调整 89 | * 修正若干文字描述 90 | 91 | * 0.6.0: 2015-12-24 92 | 93 | * 补充 Machine 项目 94 | * 修正若干 bug 95 | 96 | * 0.5.0: 2015-06-29 97 | 98 | * 添加 Compose 项目 99 | * 添加 Machine 项目 100 | * 添加 Swarm 项目 101 | * 完善 Kubernetes 项目内容 102 | * 添加 Mesos 项目内容 103 | 104 | * 0.4.0: 2015-05-08 105 | 106 | * 添加 Etcd 项目 107 | * 添加 Fig 项目 108 | * 添加 CoreOS 项目 109 | * 添加 Kubernetes 项目 110 | 111 | * 0.3.0: 2014-11-25 112 | 113 | * 完成仓库章节 114 | * 重写安全章节 115 | * 修正底层实现章节的架构、命名空间、控制组、文件系统、容器格式等内容 116 | * 添加对常见仓库和镜像的介绍 117 | * 添加 Dockerfile 的介绍 118 | * 重新校订中英文混排格式 119 | * 修订文字表达 120 | * 发布繁体版本分支:zh-Hant 121 | 122 | * 0.2.0: 2014-09-18 123 | 124 | * 对照官方文档重写介绍、基本概念、安装、镜像、容器、仓库、数据管理、网络等章节 125 | * 添加底层实现章节 126 | * 添加命令查询和资源链接章节 127 | * 其它修正 128 | 129 | * 0.1.0: 2014-09-05 130 | 131 | * 添加基本内容 132 | * 修正错别字和表达不通顺的地方 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 如何贡献 2 | 3 | 领取或创建新的 [Issue](https://github.com/yeasy/docker_practice/issues),如 [issue 235](https://github.com/yeasy/docker_practice/issues/235),添加自己为 `Assignee`。 4 | 5 | 在 [GitHub](https://github.com/yeasy/docker_practice/fork) 上 `fork` 到自己的仓库,如 `docker_user/docker_practice`,然后 `clone` 到本地,并设置用户信息。 6 | 7 | ```bash 8 | $ git clone git@github.com:docker_user/docker_practice.git 9 | 10 | $ cd docker_practice 11 | ``` 12 | 13 | 修改代码后提交,并推送到自己的仓库,注意修改提交消息为对应 Issue 号和描述。 14 | 15 | ```bash 16 | # Update the content 17 | 18 | $ git commit -a -s 19 | 20 | # In commit msg dialog, add content like "Fix issue #235: describe ur change" 21 | 22 | $ git push 23 | ``` 24 | 25 | 在 [GitHub](https://github.com/yeasy/docker_practice/pulls) 上提交 `Pull Request`,添加标签,并邀请维护者进行 `Review`。 26 | 27 | 定期使用项目仓库内容更新自己仓库内容。 28 | 29 | ```bash 30 | $ git remote add upstream https://github.com/yeasy/docker_practice 31 | 32 | $ git fetch upstream 33 | 34 | $ git rebase upstream/master 35 | 36 | $ git push -f origin master 37 | ``` 38 | 39 | ## 排版规范 40 | 41 | 本开源书籍遵循 [中文排版指南](https://github.com/mzlogin/chinese-copywriting-guidelines) 规范。 42 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate 2 | include: [_images] 3 | -------------------------------------------------------------------------------- /_images/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/cover.jpg -------------------------------------------------------------------------------- /_images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/cover.png -------------------------------------------------------------------------------- /_images/cover.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/cover.sketch -------------------------------------------------------------------------------- /_images/cover_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/cover_small.jpg -------------------------------------------------------------------------------- /_images/docker_primer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/docker_primer.png -------------------------------------------------------------------------------- /_images/docker_primer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/docker_primer2.png -------------------------------------------------------------------------------- /_images/docker_primer3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/docker_primer3.png -------------------------------------------------------------------------------- /_images/donate.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/_images/donate.jpeg -------------------------------------------------------------------------------- /advanced_network/README.md: -------------------------------------------------------------------------------- 1 | # 高级网络配置 2 | 3 | >注意:本章属于 `Docker` 高级配置,如果您是初学者,您可以暂时跳过本章节,直接学习 [Docker Compose](../compose) 一节。 4 | 5 | 本章将介绍 Docker 的一些高级网络配置和选项。 6 | 7 | 当 Docker 启动时,会自动在主机上创建一个 `docker0` 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。 8 | 9 | 同时,Docker 随机分配一个本地未占用的私有网段(在 [RFC1918](https://datatracker.ietf.org/doc/html/rfc1918) 中定义)中的一个地址给 `docker0` 接口。比如典型的 `172.17.42.1`,掩码为 `255.255.0.0`。此后启动的容器内的网口也会自动分配一个同一网段(`172.17.0.0/16`)的地址。 10 | 11 | 当创建一个 Docker 容器的时候,同时会创建了一对 `veth pair` 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 `eth0`;另一端在本地并被挂载到 `docker0` 网桥,名称以 `veth` 开头(例如 `vethAQI2QT`)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。 12 | 13 | ![Docker 网络](./_images/network.png) 14 | 15 | 接下来的部分将介绍在一些场景中,Docker 所有的网络定制配置。以及通过 Linux 命令来调整、补充、甚至替换 Docker 默认的网络配置。 16 | -------------------------------------------------------------------------------- /advanced_network/_images/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/advanced_network/_images/network.png -------------------------------------------------------------------------------- /advanced_network/access_control.md: -------------------------------------------------------------------------------- 1 | # 容器访问控制 2 | 3 | 容器的访问控制,主要通过 Linux 上的 `iptables` 防火墙来进行管理和实现。`iptables` 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。 4 | 5 | ## 容器访问外部网络 6 | 容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。 7 | 8 | ```bash 9 | $sysctl net.ipv4.ip_forward 10 | net.ipv4.ip_forward = 1 11 | ``` 12 | 如果为 0,说明没有开启转发,则需要手动打开。 13 | ```bash 14 | $sysctl -w net.ipv4.ip_forward=1 15 | ``` 16 | 如果在启动 Docker 服务的时候设定 `--ip-forward=true`, Docker 就会自动设定系统的 `ip_forward` 参数为 1。 17 | 18 | ## 容器之间访问 19 | 容器之间相互访问,需要两方面的支持。 20 | * 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 `docker0` 网桥上。 21 | * 本地系统的防火墙软件 -- `iptables` 是否允许通过。 22 | 23 | ### 访问所有端口 24 | 当启动 Docker 服务(即 dockerd)的时候,默认会添加一条转发策略到本地主机 iptables 的 FORWARD 链上。策略为通过(`ACCEPT`)还是禁止(`DROP`)取决于配置`--icc=true`(缺省值)还是 `--icc=false`。当然,如果手动指定 `--iptables=false` 则不会添加 `iptables` 规则。 25 | 26 | 可见,默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在 `/etc/docker/daemon.json` 文件中配置 `{"icc": false}` 来禁止它。 27 | 28 | ### 访问指定端口 29 | 在通过 `-icc=false` 关闭网络访问后,还可以通过 `--link=CONTAINER_NAME:ALIAS` 选项来访问容器的开放端口。 30 | 31 | 例如,在启动 Docker 服务时,可以同时使用 `icc=false --iptables=true` 参数来关闭允许相互的网络访问,并让 Docker 可以修改系统中的 `iptables` 规则。 32 | 33 | 此时,系统中的 `iptables` 规则可能是类似 34 | ```bash 35 | $ sudo iptables -nL 36 | ... 37 | Chain FORWARD (policy ACCEPT) 38 | target prot opt source destination 39 | DROP all -- 0.0.0.0/0 0.0.0.0/0 40 | ... 41 | ``` 42 | 43 | 之后,启动容器(`docker run`)时使用 `--link=CONTAINER_NAME:ALIAS` 选项。Docker 会在 `iptable` 中为 两个容器分别添加一条 `ACCEPT` 规则,允许相互访问开放的端口(取决于 `Dockerfile` 中的 `EXPOSE` 指令)。 44 | 45 | 当添加了 `--link=CONTAINER_NAME:ALIAS` 选项后,添加了 `iptables` 规则。 46 | ```bash 47 | $ sudo iptables -nL 48 | ... 49 | Chain FORWARD (policy ACCEPT) 50 | target prot opt source destination 51 | ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80 52 | ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80 53 | DROP all -- 0.0.0.0/0 0.0.0.0/0 54 | ``` 55 | 56 | 注意:`--link=CONTAINER_NAME:ALIAS` 中的 `CONTAINER_NAME` 目前必须是 Docker 分配的名字,或使用 `--name` 参数指定的名字。主机名则不会被识别。 57 | -------------------------------------------------------------------------------- /advanced_network/bridge.md: -------------------------------------------------------------------------------- 1 | # 自定义网桥 2 | 3 | 除了默认的 `docker0` 网桥,用户也可以指定网桥来连接各个容器。 4 | 5 | 在启动 Docker 服务的时候,使用 `-b BRIDGE`或`--bridge=BRIDGE` 来指定使用的网桥。 6 | 7 | 如果服务已经运行,那需要先停止服务,并删除旧的网桥。 8 | 9 | ```bash 10 | $ sudo systemctl stop docker 11 | $ sudo ip link set dev docker0 down 12 | $ sudo brctl delbr docker0 13 | ``` 14 | 15 | 然后创建一个网桥 `bridge0`。 16 | 17 | ```bash 18 | $ sudo brctl addbr bridge0 19 | $ sudo ip addr add 192.168.5.1/24 dev bridge0 20 | $ sudo ip link set dev bridge0 up 21 | ``` 22 | 23 | 查看确认网桥创建并启动。 24 | 25 | ```bash 26 | $ ip addr show bridge0 27 | 4: bridge0: mtu 1500 qdisc noop state UP group default 28 | link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff 29 | inet 192.168.5.1/24 scope global bridge0 30 | valid_lft forever preferred_lft forever 31 | ``` 32 | 33 | 在 Docker 配置文件 `/etc/docker/daemon.json` 中添加如下内容,即可将 Docker 默认桥接到创建的网桥上。 34 | 35 | ```json 36 | { 37 | "bridge": "bridge0", 38 | } 39 | ``` 40 | 41 | 启动 Docker 服务。 42 | 43 | 新建一个容器,可以看到它已经桥接到了 `bridge0` 上。 44 | 45 | 可以继续用 `brctl show` 命令查看桥接的信息。另外,在容器中可以使用 `ip addr` 和 `ip route` 命令来查看 IP 地址配置和路由信息。 46 | -------------------------------------------------------------------------------- /advanced_network/config_file.md: -------------------------------------------------------------------------------- 1 | # 编辑网络配置文件 2 | 3 | Docker 1.2.0 开始支持在运行中的容器里编辑 `/etc/hosts`, `/etc/hostname` 和 `/etc/resolv.conf` 文件。 4 | 5 | 但是这些修改是临时的,只在运行的容器中保留,容器终止或重启后并不会被保存下来,也不会被 `docker commit` 提交。 6 | -------------------------------------------------------------------------------- /advanced_network/docker0.md: -------------------------------------------------------------------------------- 1 | # 配置 docker0 网桥 2 | 3 | Docker 服务默认会创建一个 `docker0` 网桥(其上有一个 `docker0` 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。 4 | 5 | Docker 默认指定了 `docker0` 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了 MTU(接口允许接收的最大传输单元),通常是 1500 Bytes,或宿主主机网络路由上支持的默认值。这些值都可以在服务启动的时候进行配置。 6 | 7 | * `--bip=CIDR` IP 地址加掩码格式,例如 192.168.1.5/24 8 | * `--mtu=BYTES` 覆盖默认的 Docker mtu 配置 9 | 10 | 也可以在配置文件中配置 DOCKER_OPTS,然后重启服务。 11 | 12 | 由于目前 Docker 网桥是 Linux 网桥,用户可以使用 `brctl show` 来查看网桥和端口连接信息。 13 | 14 | ```bash 15 | $ sudo brctl show 16 | bridge name bridge id STP enabled interfaces 17 | docker0 8000.3a1d7362b4ee no veth65f9 18 | vethdda6 19 | ``` 20 | *注:`brctl` 命令在 Debian、Ubuntu 中可以使用 `sudo apt-get install bridge-utils` 来安装。 21 | 22 | 23 | 每次创建一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。使用本地主机上 `docker0` 接口的 IP 作为所有容器的默认网关。 24 | 25 | ```bash 26 | $ sudo docker run -i -t --rm base /bin/bash 27 | $ ip addr show eth0 28 | 24: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 29 | link/ether 32:6f:e0:35:57:91 brd ff:ff:ff:ff:ff:ff 30 | inet 172.17.0.3/16 scope global eth0 31 | valid_lft forever preferred_lft forever 32 | inet6 fe80::306f:e0ff:fe35:5791/64 scope link 33 | valid_lft forever preferred_lft forever 34 | $ ip route 35 | default via 172.17.42.1 dev eth0 36 | 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3 37 | ``` 38 | -------------------------------------------------------------------------------- /advanced_network/example.md: -------------------------------------------------------------------------------- 1 | # 工具和示例 2 | 3 | 在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣: 4 | 5 | ## pipework 6 | Jérôme Petazzoni 编写了一个叫 [pipework](https://github.com/jpetazzo/pipework) 的 shell 脚本,可以帮助用户在比较复杂的场景中完成容器的连接。 7 | 8 | ## playground 9 | Brandon Rhodes 创建了一个提供完整的 Docker 容器网络拓扑管理的 [Python库](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT 防火墙;以及一些提供 `HTTP` `SMTP` `POP` `IMAP` `Telnet` `SSH` `FTP` 的服务器。 10 | -------------------------------------------------------------------------------- /advanced_network/how_connect.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /advanced_network/port_mapping.md: -------------------------------------------------------------------------------- 1 | # 映射容器端口到宿主主机的实现 2 | 3 | 默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。 4 | 5 | ## 容器访问外部实现 6 | 7 | 容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址。这是使用 `iptables` 的源地址伪装操作实现的。 8 | 9 | 查看主机的 NAT 规则。 10 | 11 | ```bash 12 | $ sudo iptables -t nat -nL 13 | ... 14 | Chain POSTROUTING (policy ACCEPT) 15 | target prot opt source destination 16 | MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16 17 | ... 18 | ``` 19 | 20 | 其中,上述规则将所有源地址在 `172.17.0.0/16` 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。 21 | 22 | ## 外部访问容器实现 23 | 24 | 容器允许外部访问,可以在 `docker run` 时候通过 `-p` 或 `-P` 参数来启用。 25 | 26 | 不管用那种办法,其实也是在本地的 `iptable` 的 nat 表中添加相应的规则。 27 | 28 | 使用 `-P` 时: 29 | 30 | ```bash 31 | $ iptables -t nat -nL 32 | ... 33 | Chain DOCKER (2 references) 34 | target prot opt source destination 35 | DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80 36 | ``` 37 | 38 | 使用 `-p 80:80` 时: 39 | 40 | ```bash 41 | $ iptables -t nat -nL 42 | Chain DOCKER (2 references) 43 | target prot opt source destination 44 | DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80 45 | ``` 46 | 47 | 注意: 48 | 49 | * 这里的规则映射了 `0.0.0.0`,意味着将接受主机来自所有接口的流量。用户可以通过 `-p IP:host_port:container_port` 或 `-p IP::port` 来指定允许访问容器的主机上的 IP、接口等,以制定更严格的规则。 50 | 51 | * 如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 `/etc/docker/daemon.json` 中添加如下内容。 52 | 53 | ```json 54 | { 55 | "ip": "0.0.0.0" 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /advanced_network/ptp.md: -------------------------------------------------------------------------------- 1 | # 示例:创建一个点到点连接 2 | 默认情况下,Docker 会将所有容器连接到由 `docker0` 提供的虚拟子网中。 3 | 4 | 用户有时候需要两个容器之间可以直连通信,而不用通过主机网桥进行桥接。 5 | 6 | 解决办法很简单:创建一对 `peer` 接口,分别放到两个容器中,配置成点到点链路类型即可。 7 | 8 | 首先启动 2 个容器: 9 | ```bash 10 | $ docker run -i -t --rm --net=none base /bin/bash 11 | root@1f1f4c1f931a:/# 12 | $ docker run -i -t --rm --net=none base /bin/bash 13 | root@12e343489d2f:/# 14 | ``` 15 | 16 | 找到进程号,然后创建网络命名空间的跟踪文件。 17 | ```bash 18 | $ docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a 19 | 2989 20 | $ docker inspect -f '{{.State.Pid}}' 12e343489d2f 21 | 3004 22 | $ sudo mkdir -p /var/run/netns 23 | $ sudo ln -s /proc/2989/ns/net /var/run/netns/2989 24 | $ sudo ln -s /proc/3004/ns/net /var/run/netns/3004 25 | ``` 26 | 27 | 创建一对 `peer` 接口,然后配置路由 28 | ```bash 29 | $ sudo ip link add A type veth peer name B 30 | 31 | $ sudo ip link set A netns 2989 32 | $ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A 33 | $ sudo ip netns exec 2989 ip link set A up 34 | $ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A 35 | 36 | $ sudo ip link set B netns 3004 37 | $ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B 38 | $ sudo ip netns exec 3004 ip link set B up 39 | $ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B 40 | ``` 41 | 现在这 2 个容器就可以相互 ping 通,并成功建立连接。点到点链路不需要子网和子网掩码。 42 | 43 | 此外,也可以不指定 `--net=none` 来创建点到点链路。这样容器还可以通过原先的网络来通信。 44 | 45 | 利用类似的办法,可以创建一个只跟主机通信的容器。但是一般情况下,更推荐使用 `--icc=false` 来关闭容器之间的通信。 46 | -------------------------------------------------------------------------------- /advanced_network/quick_guide.md: -------------------------------------------------------------------------------- 1 | # 快速配置指南 2 | 3 | 下面是一个跟 Docker 网络相关的命令列表。 4 | 5 | 其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效。 6 | 7 | * `-b BRIDGE` 或 `--bridge=BRIDGE` 指定容器挂载的网桥 8 | * `--bip=CIDR` 定制 docker0 的掩码 9 | * `-H SOCKET...` 或 `--host=SOCKET...` Docker 服务端接收命令的通道 10 | * `--icc=true|false` 是否支持容器之间进行通信 11 | * `--ip-forward=true|false` 请看下文容器之间的通信 12 | * `--iptables=true|false` 是否允许 Docker 添加 iptables 规则 13 | * `--mtu=BYTES` 容器网络中的 MTU 14 | 15 | 下面2个命令选项既可以在启动服务时指定,也可以在启动容器时指定。在 Docker 服务启动的时候指定则会成为默认值,后面执行 `docker run` 时可以覆盖设置的默认值。 16 | 17 | * `--dns=IP_ADDRESS...` 使用指定的DNS服务器 18 | * `--dns-search=DOMAIN...` 指定DNS搜索域 19 | 20 | 最后这些选项只有在 `docker run` 执行时使用,因为它是针对容器的特性内容。 21 | 22 | * `-h HOSTNAME` 或 `--hostname=HOSTNAME` 配置容器主机名 23 | * `--link=CONTAINER_NAME:ALIAS` 添加到另一个容器的连接 24 | * `--net=bridge|none|container:NAME_or_ID|host` 配置容器的桥接模式 25 | * `-p SPEC` 或 `--publish=SPEC` 映射容器端口到宿主主机 26 | * `-P or --publish-all=true|false` 映射容器所有端口到宿主主机 27 | -------------------------------------------------------------------------------- /appendix/README.md: -------------------------------------------------------------------------------- 1 | # 附录 -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.dot: -------------------------------------------------------------------------------- 1 | //dot -Tpng xx.dot -o xx.png 2 | digraph G { 3 | rankdir=TB; 4 | fontname = "Microsoft YaHei"; 5 | fontsize = 14; 6 | penwidth = 3; 7 | compound=true; 8 | rankdir=LR; 9 | 10 | node [shape = record]; 11 | edge [fontname = "Arial", fontsize = 12, color="darkgreen" ]; 12 | 13 | image[label="Image",color=blue]; 14 | registry[label="Registry",color=blue]; 15 | tar[label="Tar files",color=blue]; 16 | 17 | subgraph cluster_container { 18 | label = "Container"; 19 | style = "bold"; 20 | color = blue; 21 | edge [fontname = "Arial", fontsize = 11, color="skyblue" ]; 22 | //node [style=filled]; 23 | run[label="Running",shape=circle, style=filled, fillcolor=green]; 24 | stop[label="Stopped",shape=circle, style=filled, fillcolor=red]; 25 | pause[label="Paused",shape=circle, style=filled, fillcolor=blue]; 26 | 27 | run->pause[label="pause"]; 28 | pause->run[label="unpause"]; 29 | run->run[label="restart"]; 30 | run->stop[label="kill"]; 31 | stop->run[label="start"]; 32 | } 33 | 34 | run->image[label="commit",ltail=cluster_container]; 35 | image->run[label="start"]; 36 | 37 | image->tar[label="export|save"]; 38 | tar->image[label="import"]; 39 | 40 | image->registry[label="push"]; 41 | registry->image[label="pull"]; 42 | 43 | //heat[label="heat commands",color=blue]; 44 | //heatshell[label="heatclient.shell.HeatShell",color=blue]; 45 | //shell[label="{heatclient.v1.shell|+do_stack_create\l+do_stack_show\l+do_stack_update\l...\l+do_event_list\l...\l+do_resource_list\l...\l+do_resource_type_show\l...\l+do_template_show\l...\l}",color=blue]; 46 | //heatclient[label="heatclient.client.Client",color=blue]; 47 | //client[label="heatclient.v1.client.Client",color=blue]; 48 | //httpclient[label="heatclient.common.http.HTTPClient",color=blue]; 49 | 50 | 51 | 52 | //openstackservices[label="{OpenStack Services|+Nova\l+Neutron\l+Keystone\l...}",color=blue]; 53 | 54 | //{rank=same; image cluster_container} 55 | //{rank=same; rpcproxy apimixin} 56 | } 57 | -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/data.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/data.plist -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image10.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image11.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image12.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image13.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image13.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image4.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image5.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image6.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image7.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.graffle/image9.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.graffle/image9.pdf -------------------------------------------------------------------------------- /appendix/_images/cmd_logic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/cmd_logic.png -------------------------------------------------------------------------------- /appendix/_images/container_status.dot: -------------------------------------------------------------------------------- 1 | //dot -Tpng container_status.dot -o container_status.png 2 | digraph G { 3 | rankdir=TB; 4 | rankdir=LR; 5 | nodesep=1; 6 | //ranksep=1 7 | fontname = "Microsoft YaHei"; 8 | fontsize = 28; 9 | penwidth = 4; 10 | compound=true; 11 | style = "bold"; 12 | color = blue; 13 | 14 | node [shape = record]; 15 | edge [fontname = "Arial", fontsize = 20, color="darkgreen" ]; 16 | image[label="Image",color=blue]; 17 | image->create[label="create"]; 18 | image->run[label="run"]; 19 | 20 | edge [fontname = "Arial", fontsize = 20, color="skyblue" ]; 21 | //node [style=filled]; 22 | create[label="Created",shape=circle, style=filled, fillcolor=lightblue]; 23 | run[label="Running",shape=circle, style=filled, fillcolor=green]; 24 | pause[label="Paused",shape=circle, style=filled, fillcolor=blue]; 25 | stop[label="Stopped",shape=circle, style=filled, fillcolor=red]; 26 | exit[label="Exited",shape=circle, style=filled, fillcolor=gray]; 27 | 28 | create->run[label=<start>]; 29 | run->pause[label="pause"]; 30 | pause->run[label="unpause"]; 31 | run->run[label="restart"]; 32 | run->stop[label="stop"]; 33 | run->exit[label="kill"]; 34 | stop->run[label="start"]; 35 | 36 | 37 | //heat[label="heat commands",color=blue]; 38 | //heatshell[label="heatclient.shell.HeatShell",color=blue]; 39 | //shell[label="{heatclient.v1.shell|+do_stack_create\l+do_stack_show\l+do_stack_update\l...\l+do_event_list\l...\l+do_resource_list\l...\l+do_resource_type_show\l...\l+do_template_show\l...\l}",color=blue]; 40 | //heatclient[label="heatclient.client.Client",color=blue]; 41 | //client[label="heatclient.v1.client.Client",color=blue]; 42 | //httpclient[label="heatclient.common.http.HTTPClient",color=blue]; 43 | 44 | 45 | 46 | //openstackservices[label="{OpenStack Services|+Nova\l+Neutron\l+Keystone\l...}",color=blue]; 47 | 48 | //{rank=same; image registry dockerfile tar} 49 | //{rank=same; container} 50 | //{rank=same; user} 51 | } 52 | -------------------------------------------------------------------------------- /appendix/_images/container_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/appendix/_images/container_status.png -------------------------------------------------------------------------------- /appendix/command/README.md: -------------------------------------------------------------------------------- 1 | # Docker 命令查询 2 | 3 | ## 基本语法 4 | 5 | Docker 命令有两大类,客户端命令和服务端命令。前者是主要的操作接口,后者用来启动 Docker Daemon。 6 | 7 | * 客户端命令:基本命令格式为 `docker [OPTIONS] COMMAND [arg...]`; 8 | 9 | * 服务端命令:基本命令格式为 `dockerd [OPTIONS]`。 10 | 11 | 可以通过 `man docker` 或 `docker help` 来查看这些命令。 12 | 13 | 接下来的小节对这两个命令进行介绍。 14 | -------------------------------------------------------------------------------- /appendix/command/docker.md: -------------------------------------------------------------------------------- 1 | # 客户端命令(docker) 2 | 3 | ## 客户端命令选项 4 | 5 | * `--config=""`:指定客户端配置文件,默认为 `~/.docker`; 6 | * `-D=true|false`:是否使用 debug 模式。默认不开启; 7 | * `-H, --host=[]`:指定命令对应 Docker 守护进程的监听接口,可以为 unix 套接字 `unix:///path/to/socket`,文件句柄 `fd://socketfd` 或 tcp 套接字 `tcp://[host[:port]]`,默认为 `unix:///var/run/docker.sock`; 8 | * `-l, --log-level="debug|info|warn|error|fatal"`:指定日志输出级别; 9 | * `--tls=true|false`:是否对 Docker 守护进程启用 TLS 安全机制,默认为否; 10 | * `--tlscacert=/.docker/ca.pem`:TLS CA 签名的可信证书文件路径; 11 | * `--tlscert=/.docker/cert.pem`:TLS 可信证书文件路径; 12 | * `--tlscert=/.docker/key.pem`:TLS 密钥文件路径; 13 | * `--tlsverify=true|false`:启用 TLS 校验,默认为否。 14 | 15 | ## 客户端命令 16 | 17 | 可以通过 `docker COMMAND --help` 来查看这些命令的具体用法。 18 | 19 | * `attach`:依附到一个正在运行的容器中; 20 | * `build`:从一个 Dockerfile 创建一个镜像; 21 | * `commit`:从一个容器的修改中创建一个新的镜像; 22 | * `cp`:在容器和本地宿主系统之间复制文件中; 23 | * `create`:创建一个新容器,但并不运行它; 24 | * `diff`:检查一个容器内文件系统的修改,包括修改和增加; 25 | * `events`:从服务端获取实时的事件; 26 | * `exec`:在运行的容器内执行命令; 27 | * `export`:导出容器内容为一个 `tar` 包; 28 | * `history`:显示一个镜像的历史信息; 29 | * `images`:列出存在的镜像; 30 | * `import`:导入一个文件(典型为 `tar` 包)路径或目录来创建一个本地镜像; 31 | * `info`:显示一些相关的系统信息; 32 | * `inspect`:显示一个容器的具体配置信息; 33 | * `kill`:关闭一个运行中的容器 (包括进程和所有相关资源); 34 | * `load`:从一个 tar 包中加载一个镜像; 35 | * `login`:注册或登录到一个 Docker 的仓库服务器; 36 | * `logout`:从 Docker 的仓库服务器登出; 37 | * `logs`:获取容器的 log 信息; 38 | * `network`:管理 Docker 的网络,包括查看、创建、删除、挂载、卸载等; 39 | * `node`:管理 swarm 集群中的节点,包括查看、更新、删除、提升/取消管理节点等; 40 | * `pause`:暂停一个容器中的所有进程; 41 | * `port`:查找一个 nat 到一个私有网口的公共口; 42 | * `ps`:列出主机上的容器; 43 | * `pull`:从一个Docker的仓库服务器下拉一个镜像或仓库; 44 | * `push`:将一个镜像或者仓库推送到一个 Docker 的注册服务器; 45 | * `rename`:重命名一个容器; 46 | * `restart`:重启一个运行中的容器; 47 | * `rm`:删除给定的若干个容器; 48 | * `rmi`:删除给定的若干个镜像; 49 | * `run`:创建一个新容器,并在其中运行给定命令; 50 | * `save`:保存一个镜像为 tar 包文件; 51 | * `search`:在 Docker index 中搜索一个镜像; 52 | * `service`:管理 Docker 所启动的应用服务,包括创建、更新、删除等; 53 | * `start`:启动一个容器; 54 | * `stats`:输出(一个或多个)容器的资源使用统计信息; 55 | * `stop`:终止一个运行中的容器; 56 | * `swarm`:管理 Docker swarm 集群,包括创建、加入、退出、更新等; 57 | * `tag`:为一个镜像打标签; 58 | * `top`:查看一个容器中的正在运行的进程信息; 59 | * `unpause`:将一个容器内所有的进程从暂停状态中恢复; 60 | * `update`:更新指定的若干容器的配置信息; 61 | * `version`:输出 Docker 的版本信息; 62 | * `volume`:管理 Docker volume,包括查看、创建、删除等; 63 | * `wait`:阻塞直到一个容器终止,然后输出它的退出符。 64 | 65 | ## 一张图总结 Docker 的命令 66 | ![Docker 命令总结](../_images/cmd_logic.png) 67 | 68 | ## 参考 69 | 70 | * [官方文档](https://docs.docker.com/engine/reference/commandline/cli/) 71 | -------------------------------------------------------------------------------- /appendix/command/dockerd.md: -------------------------------------------------------------------------------- 1 | # 服务端命令(dockerd) 2 | 3 | ## dockerd 命令选项 4 | 5 | * `--api-cors-header=""`:CORS 头部域,默认不允许 CORS,要允许任意的跨域访问,可以指定为 "*"; 6 | * `--authorization-plugin=""`:载入认证的插件; 7 | * `-b=""`:将容器挂载到一个已存在的网桥上。指定为 `none` 时则禁用容器的网络,与 `--bip` 选项互斥; 8 | * `--bip=""`:让动态创建的 `docker0` 网桥采用给定的 CIDR 地址; 与 `-b` 选项互斥; 9 | * `--cgroup-parent=""`:指定 cgroup 的父组,默认 fs cgroup 驱动为 `/docker`,systemd cgroup 驱动为 `system.slice`; 10 | * `--cluster-store=""`:构成集群(如 `Swarm`)时,集群键值数据库服务地址; 11 | * `--cluster-advertise=""`:构成集群时,自身的被访问地址,可以为 `host:port` 或 `interface:port`; 12 | * `--cluster-store-opt=""`:构成集群时,键值数据库的配置选项; 13 | * `--config-file="/etc/docker/daemon.json"`:daemon 配置文件路径; 14 | * `--containerd=""`:containerd 文件的路径; 15 | * `-D, --debug=true|false`:是否使用 Debug 模式。缺省为 false; 16 | * `--default-gateway=""`:容器的 IPv4 网关地址,必须在网桥的子网段内; 17 | * `--default-gateway-v6=""`:容器的 IPv6 网关地址; 18 | * `--default-ulimit=[]`:默认的 ulimit 值; 19 | * `--disable-legacy-registry=true|false`:是否允许访问旧版本的镜像仓库服务器; 20 | * `--dns=""`:指定容器使用的 DNS 服务器地址; 21 | * `--dns-opt=""`:DNS 选项; 22 | * `--dns-search=[]`:DNS 搜索域; 23 | * `--exec-opt=[]`:运行时的执行选项; 24 | * `--exec-root=""`:容器执行状态文件的根路径,默认为 `/var/run/docker`; 25 | * `--fixed-cidr=""`:限定分配 IPv4 地址范围; 26 | * `--fixed-cidr-v6=""`:限定分配 IPv6 地址范围; 27 | * `-G, --group=""`:分配给 unix 套接字的组,默认为 `docker`; 28 | * `-g, --graph=""`:Docker 运行时的根路径,默认为 `/var/lib/docker`; 29 | * `-H, --host=[]`:指定命令对应 Docker daemon 的监听接口,可以为 unix 套接字 `unix:///path/to/socket`,文件句柄 `fd://socketfd` 或 tcp 套接字 `tcp://[host[:port]]`,默认为 `unix:///var/run/docker.sock`; 30 | * `--icc=true|false`:是否启用容器间以及跟 daemon 所在主机的通信。默认为 true。 31 | * `--insecure-registry=[]`:允许访问给定的非安全仓库服务; 32 | * `--ip=""`:绑定容器端口时候的默认 IP 地址。缺省为 `0.0.0.0`; 33 | * `--ip-forward=true|false`:是否检查启动在 Docker 主机上的启用 IP 转发服务,默认开启。注意关闭该选项将不对系统转发能力进行任何检查修改; 34 | * `--ip-masq=true|false`:是否进行地址伪装,用于容器访问外部网络,默认开启; 35 | * `--iptables=true|false`:是否允许 Docker 添加 iptables 规则。缺省为 true; 36 | * `--ipv6=true|false`:是否启用 IPv6 支持,默认关闭; 37 | * `-l, --log-level="debug|info|warn|error|fatal"`:指定日志输出级别; 38 | * `--label="[]"`:添加指定的键值对标注; 39 | * `--log-driver="json-file|syslog|journald|gelf|fluentd|awslogs|splunk|etwlogs|gcplogs|none"`:指定日志后端驱动,默认为 `json-file`; 40 | * `--log-opt=[]`:日志后端的选项; 41 | * `--mtu=VALUE`:指定容器网络的 `mtu`; 42 | * `-p=""`:指定 daemon 的 PID 文件路径。缺省为 `/var/run/docker.pid`; 43 | * `--raw-logs`:输出原始,未加色彩的日志信息; 44 | * `--registry-mirror=://`:指定 `docker pull` 时使用的注册服务器镜像地址; 45 | * `-s, --storage-driver=""`:指定使用给定的存储后端; 46 | * `--selinux-enabled=true|false`:是否启用 SELinux 支持。缺省值为 false。SELinux 目前尚不支持 overlay 存储驱动; 47 | * `--storage-opt=[]`:驱动后端选项; 48 | * `--tls=true|false`:是否对 Docker daemon 启用 TLS 安全机制,默认为否; 49 | * `--tlscacert=/.docker/ca.pem`:TLS CA 签名的可信证书文件路径; 50 | * `--tlscert=/.docker/cert.pem`:TLS 可信证书文件路径; 51 | * `--tlscert=/.docker/key.pem`:TLS 密钥文件路径; 52 | * `--tlsverify=true|false`:启用 TLS 校验,默认为否; 53 | * `--userland-proxy=true|false`:是否使用用户态代理来实现容器间和出容器的回环通信,默认为 true; 54 | * `--userns-remap=default|uid:gid|user:group|user|uid`:指定容器的用户命名空间,默认是创建新的 UID 和 GID 映射到容器内进程。 55 | 56 | ## 参考 57 | 58 | * [官方文档](https://docs.docker.com/engine/reference/commandline/dockerd/) 59 | -------------------------------------------------------------------------------- /appendix/debug.md: -------------------------------------------------------------------------------- 1 | # 如何调试 Docker 2 | 3 | ## 开启 Debug 模式 4 | 5 | 在 dockerd 配置文件 daemon.json(默认位于 /etc/docker/)中添加 6 | 7 | ```json 8 | { 9 | "debug": true 10 | } 11 | ``` 12 | 13 | 重启守护进程。 14 | 15 | ```bash 16 | $ sudo kill -SIGHUP $(pidof dockerd) 17 | ``` 18 | 19 | 此时 dockerd 会在日志中输入更多信息供分析。 20 | 21 | ## 检查内核日志 22 | 23 | ```bash 24 | $ sudo dmesg |grep dockerd 25 | $ sudo dmesg |grep runc 26 | ``` 27 | 28 | ## Docker 不响应时处理 29 | 30 | 可以杀死 dockerd 进程查看其堆栈调用情况。 31 | 32 | ```bash 33 | $ sudo kill -SIGUSR1 $(pidof dockerd) 34 | ``` 35 | 36 | ## 重置 Docker 本地数据 37 | 38 | *注意,本操作会移除所有的 Docker 本地数据,包括镜像和容器等。* 39 | 40 | ```bash 41 | $ sudo rm -rf /var/lib/docker 42 | ``` 43 | -------------------------------------------------------------------------------- /appendix/repo/README.md: -------------------------------------------------------------------------------- 1 | # 热门镜像介绍 2 | 3 | 本章将介绍一些热门镜像的功能,使用方法等。包括 Ubuntu、CentOS、MySQL、MongoDB、Redis、Nginx、Wordpress、Node.js 等。 4 | -------------------------------------------------------------------------------- /appendix/repo/centos.md: -------------------------------------------------------------------------------- 1 | # [CentOS](https://hub.docker.com/_/centos) 2 | 3 | ## 基本信息 4 | 5 | [CentOS](https://en.wikipedia.org/wiki/CentOS) 是流行的 Linux 发行版,其软件包大多跟 RedHat 系列保持一致。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/centos` ,提供了 CentOS 从 5 ~ 8 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 默认会启动一个最小化的 CentOS 环境。 12 | 13 | ```bash 14 | $ docker run --name centos -it centos bash 15 | bash-4.2# 16 | ``` 17 | 18 | ## Dockerfile 19 | 20 | 请到 https://github.com/docker-library/docs/tree/master/centos 查看。 21 | -------------------------------------------------------------------------------- /appendix/repo/minio.md: -------------------------------------------------------------------------------- 1 | # minio 2 | 3 | **MinIO** 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb 到最大 5T 不等。 4 | 5 | MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。 6 | 7 | [官方文档](https://docs.min.io/) 8 | 9 | ## 简单使用 10 | 11 | 测试、开发环境下不考虑数据存储的情况下可以使用下面的命令快速开启服务。 12 | 13 | ```bash 14 | $ docker run -d -p 9000:9000 -p 9090:9090 minio/minio server /data --console-address ':9090' 15 | ``` 16 | 17 | ## 离线部署 18 | 19 | 许多生产环境是一般是没有公网资源的,这就需要从有公网资源的服务器上把镜像导出,然后导入到需要运行镜像的内网服务器。 20 | 21 | ### 导出镜像 22 | 23 | 在有公网资源的服务器上下载好`minio/minio`镜像 24 | 25 | ```bash 26 | $ docker save -o minio.tar minio/minio:latest 27 | ``` 28 | 29 | > 使用docker save 的时候,也可以使用image id 来导出,但是那样导出的时候,就会丢失原来的镜像名称,推荐,还是使用镜像名字+tag来导出镜像 30 | 31 | ### 导入镜像 32 | 33 | 把压缩文件复制到内网服务器上,使用下面的命令导入镜像 34 | 35 | ```bash 36 | $ docker load minio.tar 37 | ``` 38 | 39 | ### 运行 minio 40 | 41 | - 把 `/mnt/data` 改成要替换的数据目录 42 | - 替换 `MINIO_ROOT_USER` 的值 43 | - 替换 `MINIO_ROOT_PASSWORD` 的值 44 | - 替换 name,minio1(可选) 45 | - 如果 9000、9090 端口冲突,替换端口前面的如 `9009:9000` 46 | 47 | ```bash 48 | $ sudo docker run -d -p 9000:9000 -p 9090:9090 --name minio1 \ 49 | -e "MINIO_ROOT_USER=改成自己需要的" \ 50 | -e "MINIO_ROOT_PASSWORD=改成自己需要的" \ 51 | -v /mnt/data:/data \ 52 | --restart=always \ 53 | minio/minio server /data --console-address ':9090' 54 | ``` 55 | 56 | ### 访问 web 管理页面 57 | 58 | http://x.x.x.x:9090 59 | -------------------------------------------------------------------------------- /appendix/repo/mongodb.md: -------------------------------------------------------------------------------- 1 | # [MongoDB](https://hub.docker.com/_/mongo/) 2 | 3 | ## 基本信息 4 | 5 | [MongoDB](https://en.wikipedia.org/wiki/MongoDB) 是开源的 NoSQL 数据库实现。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/mongo/` ,提供了 MongoDB 2.x ~ 4.x 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 默认会在 `27017` 端口启动数据库。 12 | 13 | ```bash 14 | $ docker run --name mongo -d mongo 15 | ``` 16 | 17 | 使用其他应用连接到容器,可以用 18 | 19 | ```bash 20 | $ docker run --name some-app --link some-mongo:mongo -d application-that-uses-mongo 21 | ``` 22 | 23 | 或者通过 `mongo` 24 | 25 | ```bash 26 | $ docker run -it --rm \ 27 | --link some-mongo:mongo \ 28 | mongo \ 29 | sh -c 'exec mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test"' 30 | ``` 31 | 32 | ## Dockerfile 33 | 34 | 请到 https://github.com/docker-library/docs/tree/master/mongo 查看。 35 | -------------------------------------------------------------------------------- /appendix/repo/mysql.md: -------------------------------------------------------------------------------- 1 | # [MySQL](https://hub.docker.com/_/mysql/) 2 | 3 | ## 基本信息 4 | 5 | [MySQL](https://en.wikipedia.org/wiki/MySQL) 是开源的关系数据库实现。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/mysql/` ,提供了 MySQL 5.5 ~ 8.x 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 默认会在 `3306` 端口启动数据库。 12 | 13 | ```bash 14 | $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=mysecretpassword -d mysql 15 | ``` 16 | 17 | 之后就可以使用其它应用来连接到该容器。 18 | 19 | ```bash 20 | $ docker run --name some-app --link some-mysql:mysql -d application-that-uses-mysql 21 | ``` 22 | 23 | 或者通过 `mysql` 命令行连接。 24 | 25 | ```bash 26 | $ docker run -it --rm \ 27 | --link some-mysql:mysql \ 28 | mysql \ 29 | sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"' 30 | ``` 31 | 32 | ## Dockerfile 33 | 34 | 请到 https://github.com/docker-library/docs/tree/master/mysql 查看 35 | -------------------------------------------------------------------------------- /appendix/repo/nginx.md: -------------------------------------------------------------------------------- 1 | # [Nginx](https://hub.docker.com/_/nginx/) 2 | 3 | ## 基本信息 4 | 5 | [Nginx](https://en.wikipedia.org/wiki/Nginx) 是开源的高效的 Web 服务器实现,支持 HTTP、HTTPS、SMTP、POP3、IMAP 等协议。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/nginx/` ,提供了 Nginx 1.0 ~ 1.19.x 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 下面的命令将作为一个静态页面服务器启动。 12 | 13 | ```bash 14 | $ docker run --name some-nginx -v /some/content:/usr/share/nginx/html:ro -d nginx 15 | ``` 16 | 17 | 用户也可以不使用这种映射方式,通过利用 Dockerfile 来直接将静态页面内容放到镜像中,内容为 18 | 19 | ```docker 20 | FROM nginx 21 | COPY static-html-directory /usr/share/nginx/html 22 | ``` 23 | 24 | 之后生成新的镜像,并启动一个容器。 25 | 26 | ```bash 27 | $ docker build -t some-content-nginx . 28 | $ docker run --name some-nginx -d some-content-nginx 29 | ``` 30 | 31 | 开放端口,并映射到本地的 `8080` 端口。 32 | 33 | ```bash 34 | $ docker run --name some-nginx -d -p 8080:80 some-content-nginx 35 | ``` 36 | 37 | Nginx的默认配置文件路径为 `/etc/nginx/nginx.conf`,可以通过映射它来使用本地的配置文件,例如 38 | 39 | ```bash 40 | $ docker run -d \ 41 | --name some-nginx \ 42 | -p 8080:80 \ 43 | -v /path/nginx.conf:/etc/nginx/nginx.conf:ro \ 44 | nginx 45 | ``` 46 | 47 | ## Dockerfile 48 | 49 | 请到 https://github.com/docker-library/docs/tree/master/nginx 查看。 50 | -------------------------------------------------------------------------------- /appendix/repo/nodejs.md: -------------------------------------------------------------------------------- 1 | # [Node.js](https://hub.docker.com/_/node/) 2 | 3 | ## 基本信息 4 | 5 | [Node.js](https://en.wikipedia.org/wiki/Node.js) 是基于 JavaScript 的可扩展服务端和网络软件开发平台。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/node/` ,提供了 Node.js 0.10 ~ 14.x 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 在项目中创建一个 Dockerfile。 12 | 13 | ```docker 14 | FROM node:12 15 | # replace this with your application's default port 16 | EXPOSE 8888 17 | ``` 18 | 19 | 然后创建镜像,并启动容器。 20 | 21 | ```bash 22 | $ docker build -t my-nodejs-app 23 | $ docker run -it --rm --name my-running-app my-nodejs-app 24 | ``` 25 | 26 | 也可以直接运行一个简单容器。 27 | 28 | ```bash 29 | $ docker run -it --rm \ 30 | --name my-running-script \ 31 | # -v "$(pwd)":/usr/src/myapp \ 32 | --mount type=bind,src=`$(pwd)`,target=/usr/src/myapp \ 33 | -w /usr/src/myapp \ 34 | node:12-alpine \ 35 | node your-daemon-or-script.js 36 | ``` 37 | 38 | ## Dockerfile 39 | 40 | 请到 https://github.com/docker-library/docs/tree/master/node 查看。 41 | -------------------------------------------------------------------------------- /appendix/repo/php.md: -------------------------------------------------------------------------------- 1 | # [PHP](https://hub.docker.com/_/php/) 2 | 3 | ## 基本信息 4 | 5 | [PHP](https://en.wikipedia.org/wiki/Php)(Hypertext Preprocessor 超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML 中,尤其适合 web 开发。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/php/` ,提供了 PHP 5.x ~ 8.x 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 下面的命令将运行一个已有的 PHP 脚本。 12 | 13 | ```bash 14 | $ docker run -it --rm -v "$PWD":/app -w /app php:alpine php your-script.php 15 | ``` 16 | 17 | ## Dockerfile 18 | 19 | 请到 https://github.com/docker-library/docs/tree/master/php 查看。 20 | -------------------------------------------------------------------------------- /appendix/repo/redis.md: -------------------------------------------------------------------------------- 1 | # [Redis](https://hub.docker.com/_/redis/) 2 | 3 | ## 基本信息 4 | 5 | [Redis](https://en.wikipedia.org/wiki/Redis) 是开源的内存 Key-Value 数据库实现。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/redis/` ,提供了 Redis 3.x ~ 6.x 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 默认会在 `6379` 端口启动数据库。 12 | 13 | ```bash 14 | $ docker run --name some-redis -d -p 6379:6379 redis 15 | ``` 16 | 17 | 另外还可以启用 [持久存储](https://redis.io/topics/persistence)。 18 | 19 | ```bash 20 | $ docker run --name some-redis -d -p 6379:6379 redis redis-server --appendonly yes 21 | ``` 22 | 23 | 默认数据存储位置在 `VOLUME/data`。可以使用 `--volumes-from some-volume-container` 或 `-v /docker/host/dir:/data` 将数据存放到本地。 24 | 25 | 使用其他应用连接到容器,可以用 26 | 27 | ```bash 28 | $ docker run --name some-app --link some-redis:redis -d application-that-uses-redis 29 | ``` 30 | 31 | 或者通过 `redis-cli` 32 | 33 | ```bash 34 | $ docker run -it --rm \ 35 | --link some-redis:redis \ 36 | redis \ 37 | sh -c 'exec redis-cli -h "$REDIS_PORT_6379_TCP_ADDR" -p "$REDIS_PORT_6379_TCP_PORT"' 38 | ``` 39 | 40 | ## Dockerfile 41 | 42 | 请到 https://github.com/docker-library/docs/tree/master/redis 查看。 43 | -------------------------------------------------------------------------------- /appendix/repo/ubuntu.md: -------------------------------------------------------------------------------- 1 | # [Ubuntu](https://hub.docker.com/_/ubuntu/) 2 | 3 | ## 基本信息 4 | 5 | [Ubuntu](https://en.wikipedia.org/wiki/Ubuntu) 是流行的 Linux 发行版,其自带软件版本往往较新一些。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/ubuntu/` ,提供了 Ubuntu 从 12.04 ~ 20.04 各个版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 默认会启动一个最小化的 Ubuntu 环境。 12 | 13 | ```bash 14 | $ docker run --name some-ubuntu -it ubuntu:20.04 15 | root@523c70904d54:/# 16 | ``` 17 | 18 | ## Dockerfile 19 | 20 | 请到 https://github.com/docker-library/docs/tree/master/ubuntu 查看。 21 | -------------------------------------------------------------------------------- /appendix/repo/wordpress.md: -------------------------------------------------------------------------------- 1 | # [WordPress](https://hub.docker.com/_/wordpress/) 2 | 3 | ## 基本信息 4 | 5 | [WordPress](https://en.wikipedia.org/wiki/WordPress) 是开源的 Blog 和内容管理系统框架,它基于 PHP 和 MySQL。 6 | 7 | 该仓库位于 `https://hub.docker.com/_/wordpress/` ,提供了 WordPress 4.x ~ 5.x 版本的镜像。 8 | 9 | ## 使用方法 10 | 11 | 启动容器需要 MySQL 的支持,默认端口为 `80`。 12 | 13 | ```bash 14 | $ docker run --name some-wordpress --link some-mysql:mysql -d wordpress 15 | ``` 16 | 17 | 启动 WordPress 容器时可以指定的一些环境变量包括: 18 | 19 | * `WORDPRESS_DB_USER` 缺省为 `root` 20 | * `WORDPRESS_DB_PASSWORD` 缺省为连接 mysql 容器的环境变量 `MYSQL_ROOT_PASSWORD` 的值 21 | * `WORDPRESS_DB_NAME` 缺省为 `wordpress` 22 | 23 | ## Dockerfile 24 | 25 | 请到 https://github.com/docker-library/docs/tree/master/wordpress 查看。 26 | -------------------------------------------------------------------------------- /appendix/resources.md: -------------------------------------------------------------------------------- 1 | # 资源链接 2 | 3 | ## 官方网站 4 | 5 | * Docker 官方主页:https://www.docker.com 6 | * Docker 官方博客:https://www.docker.com/blog/ 7 | * Docker 官方文档:https://docs.docker.com/ 8 | * Docker Hub:https://hub.docker.com 9 | * Docker 的源代码仓库:https://github.com/moby/moby 10 | * Docker 路线图 https://github.com/docker/roadmap/projects 11 | * Docker 发布版本历史:https://docs.docker.com/release-notes/ 12 | * Docker 常见问题:https://docs.docker.com/engine/faq/ 13 | * Docker 远端应用 API:https://docs.docker.com/develop/sdk/ 14 | 15 | ## 实践参考 16 | 17 | * Dockerfile 参考:https://docs.docker.com/engine/reference/builder/ 18 | * Dockerfile 最佳实践:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/ 19 | 20 | ## 技术交流 21 | 22 | * Docker 邮件列表: https://groups.google.com/forum/#!forum/docker-user 23 | * Docker 的 IRC 频道:https://chat.freenode.net#docker 24 | * Docker 的 Twitter 主页:https://twitter.com/docker 25 | 26 | ## 其它 27 | 28 | * Docker 的 StackOverflow 问答主页:https://stackoverflow.com/search?q=docker 29 | -------------------------------------------------------------------------------- /archive/README.md: -------------------------------------------------------------------------------- 1 | # 归档项目 2 | 3 | 以下项目不被官方支持或内容陈旧,将在下一版本中删除(或已经删除)。 4 | 5 | * [Docker Machine](https://github.com/yeasy/docker_practice/tree/ca29ab51b121f43563f5d6659dedbda5cb6f048d/machine) 6 | * [Docker Swarm](https://github.com/yeasy/docker_practice/tree/ca29ab51b121f43563f5d6659dedbda5cb6f048d/swarm) 7 | * Mesos 8 | -------------------------------------------------------------------------------- /basic_concept/README.md: -------------------------------------------------------------------------------- 1 | # 基本概念 2 | 3 | **Docker** 包括三个基本概念 4 | * **镜像**(`Image`) 5 | * **容器**(`Container`) 6 | * **仓库**(`Repository`) 7 | 8 | 理解了这三个概念,就理解了 **Docker** 的整个生命周期。 9 | -------------------------------------------------------------------------------- /basic_concept/container.md: -------------------------------------------------------------------------------- 1 | # Docker 容器 2 | 3 | 镜像(`Image`)和容器(`Container`)的关系,就像是面向对象程序设计中的 `类` 和 `实例` 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 4 | 5 | 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 [命名空间](https://en.wikipedia.org/wiki/Linux_namespaces)。因此容器可以拥有自己的 `root` 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。 6 | 7 | 前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 **容器存储层**。 8 | 9 | 容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。 10 | 11 | 按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 [数据卷(Volume)](../data_management/volume.md)、或者 [绑定宿主目录](../data_management/bind-mounts.md),在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。 12 | 13 | 数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。 14 | -------------------------------------------------------------------------------- /basic_concept/image.md: -------------------------------------------------------------------------------- 1 | # Docker 镜像 2 | 3 | 我们都知道,操作系统分为 **内核** 和 **用户空间**。对于 `Linux` 而言,内核启动后,会挂载 `root` 文件系统为其提供用户空间支持。而 **Docker 镜像**(`Image`),就相当于是一个 `root` 文件系统。比如官方镜像 `ubuntu:18.04` 就包含了完整的一套 Ubuntu 18.04 最小系统的 `root` 文件系统。 4 | 5 | **Docker 镜像** 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 **不包含** 任何动态数据,其内容在构建之后也不会被改变。 6 | 7 | ## 分层存储 8 | 9 | 因为镜像包含操作系统完整的 `root` 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 `ISO` 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。 10 | 11 | 镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。 12 | 13 | 分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。 14 | 15 | 关于镜像构建,将会在后续相关章节中做进一步的讲解。 16 | -------------------------------------------------------------------------------- /basic_concept/repository.md: -------------------------------------------------------------------------------- 1 | # Docker Registry 2 | 3 | 镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,[Docker Registry](../repository/registry.md) 就是这样的服务。 4 | 5 | 一个 **Docker Registry** 中可以包含多个 **仓库**(`Repository`);每个仓库可以包含多个 **标签**(`Tag`);每个标签对应一个镜像。 6 | 7 | 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 `latest` 作为默认标签。 8 | 9 | 以 [Ubuntu 镜像](https://hub.docker.com/_/ubuntu) 为例,`ubuntu` 是仓库的名字,其内包含有不同的版本标签,如,`16.04`, `18.04`。我们可以通过 `ubuntu:16.04`,或者 `ubuntu:18.04` 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 `ubuntu`,那将视为 `ubuntu:latest`。 10 | 11 | 仓库名经常以 *两段式路径* 形式出现,比如 `jwilder/nginx-proxy`,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。 12 | 13 | ## Docker Registry 公开服务 14 | 15 | Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。 16 | 17 | 最常使用的 Registry 公开服务是官方的 [Docker Hub](https://hub.docker.com/),这也是默认的 Registry,并拥有大量的高质量的 [官方镜像](https://hub.docker.com/search?q=&type=image&image_filter=official)。除此以外,还有 Red Hat 的 [Quay.io](https://quay.io/repository/);Google 的 [Google Container Registry](https://cloud.google.com/container-registry/),[Kubernetes](https://kubernetes.io/) 的镜像使用的就是这个服务;代码托管平台 [GitHub](https://github.com) 推出的 [ghcr.io](https://docs.github.com/cn/packages/working-with-a-github-packages-registry/working-with-the-container-registry)。 18 | 19 | 由于某些原因,在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务(`Registry Mirror`),这些镜像服务被称为 **加速器**。常见的有 [阿里云加速器](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu)、[DaoCloud 加速器](https://www.daocloud.io/mirror#accelerator-doc) 等。使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从 Docker Hub 下载速度会提高很多。在 [安装 Docker](../install/mirror.md) 一节中有详细的配置方法。 20 | 21 | 国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 [网易云镜像服务](https://c.163.com/hub#/m/library/)、[DaoCloud 镜像市场](https://hub.daocloud.io/)、[阿里云镜像库](https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu) 等。 22 | 23 | ## 私有 Docker Registry 24 | 25 | 除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 [Docker Registry](https://hub.docker.com/_/registry/) 镜像,可以直接使用做为私有 Registry 服务。在 [私有仓库](../repository/registry.md) 一节中,会有进一步的搭建私有 Registry 服务的讲解。 26 | 27 | 开源的 Docker Registry 镜像只提供了 [Docker Registry API](https://docs.docker.com/registry/spec/api/) 的服务端实现,足以支持 `docker` 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。 28 | 29 | 除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,[Harbor](https://github.com/goharbor/harbor) 和 [Sonatype Nexus](../repository/nexus3_registry.md)。 30 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Docker -- 从入门到实践", 3 | "author": "yeasy", 4 | "language": "zh-hans", 5 | "links": { 6 | "sidebar": { 7 | "GitHub": "https://github.com/yeasy/docker_practice" 8 | } 9 | }, 10 | "plugins": [ 11 | "-livereload", 12 | "image-captions", 13 | "github", 14 | "page-treeview@2.9.8", 15 | "editlink" 16 | ], 17 | "pluginsConfig": { 18 | "image-captions": { 19 | "attributes": { 20 | "width": "600" 21 | }, 22 | "caption": "图 _PAGE_LEVEL_._PAGE_IMAGE_NUMBER_ - _CAPTION_" 23 | }, 24 | "github": { 25 | "url": "https://github.com/yeasy/docker_practice" 26 | }, 27 | "editlink": { 28 | "base": "https://github.com/yeasy/docker_practice/blob/master/", 29 | "label": "编辑本页" 30 | }, 31 | "page-treeview": { 32 | "copyright": "Copyright © yeasy", 33 | "minHeaderCount": "2", 34 | "minHeaderDeep": "2" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /buildx/README.md: -------------------------------------------------------------------------------- 1 | # Docker Buildx 2 | 3 | Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 [Moby BuildKit](buildkit.md) 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。 4 | 5 | > 该功能仅适用于 Docker v19.03+ 版本 6 | -------------------------------------------------------------------------------- /buildx/buildx.md: -------------------------------------------------------------------------------- 1 | # 使用 Buildx 构建镜像 2 | 3 | ## 使用 4 | 5 | 你可以直接使用 `docker buildx build` 命令构建镜像。 6 | 7 | ```bash 8 | $ docker buildx build . 9 | [+] Building 8.4s (23/32) 10 | => ... 11 | ``` 12 | 13 | Buildx 使用 [BuildKit 引擎](buildkit.md) 进行构建,支持许多新的功能,具体参考 [Buildkit](buildkit.md) 一节。 14 | 15 | ## 官方文档 16 | 17 | * https://docs.docker.com/engine/reference/commandline/buildx/ 18 | -------------------------------------------------------------------------------- /cases/ci/README.md: -------------------------------------------------------------------------------- 1 | # CI/CD 2 | 3 | **持续集成(Continuous integration)** 是一种软件开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 4 | 5 | **持续部署(continuous deployment)** 是通过自动化的构建、测试和部署循环来快速交付高质量的产品。 6 | 7 | 与 `Jenkins` 不同的是,基于 Docker 的 CI/CD 每一步都运行在 Docker 容器中,所以理论上支持所有的编程语言。 8 | -------------------------------------------------------------------------------- /cases/ci/actions/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions 2 | 3 | GitHub [Actions](https://github.com/features/actions) 是 GitHub 推出的一款 CI/CD 工具。 4 | 5 | 我们可以在每个 `job` 的 `step` 中使用 Docker 执行构建步骤。 6 | 7 | ```yaml 8 | on: push 9 | 10 | name: CI 11 | 12 | jobs: 13 | my-job: 14 | name: Build 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@master 18 | with: 19 | fetch-depth: 2 20 | - name: run docker container 21 | uses: docker://golang:alpine 22 | with: 23 | args: go version 24 | ``` 25 | 26 | ## 参考资料 27 | 28 | * [Actions Docs](https://docs.github.com/en/actions) 29 | -------------------------------------------------------------------------------- /cases/ci/drone/.env.example: -------------------------------------------------------------------------------- 1 | DRONE_SERVER_HOST= 2 | DRONE_SERVER_PROTO= 3 | DRONE_RPC_SECRET= 4 | HOSTNAME= 5 | DRONE_GITHUB_CLIENT_ID= 6 | DRONE_GITHUB_CLIENT_SECRET= 7 | -------------------------------------------------------------------------------- /cases/ci/drone/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | ssl/* 3 | -------------------------------------------------------------------------------- /cases/ci/drone/README.md: -------------------------------------------------------------------------------- 1 | # Drone 2 | 3 | 基于 `Docker` 的 `CI/CD` 工具 `Drone` 所有编译、测试的流程都在 `Docker` 容器中进行。 4 | 5 | 开发者只需在项目中包含 `.drone.yml` 文件,将代码推送到 git 仓库,`Drone` 就能够自动化的进行编译、测试、发布。 6 | 7 | 本小节以 `GitHub` + `Drone` 来演示 `Drone` 的工作流程。当然在实际开发过程中,你的代码也许不在 GitHub 托管,那么你可以尝试使用 `Gogs` + `Drone` 来进行 `CI/CD`。 8 | 9 | ## Drone 关联项目 10 | 11 | 在 Github 新建一个名为 `drone-demo` 的仓库。 12 | 13 | 打开我们已经 [部署好的 Drone 网站](install.md) 或者 [Drone Cloud](https://cloud.drone.io),使用 GitHub 账号登录,在界面中关联刚刚新建的 `drone-demo` 仓库。 14 | 15 | ## 编写项目源代码 16 | 17 | 初始化一个 git 仓库 18 | 19 | ```bash 20 | $ mkdir drone-demo 21 | 22 | $ cd drone-demo 23 | 24 | $ git init 25 | 26 | $ git remote add origin git@github.com:username/drone-demo.git 27 | ``` 28 | 29 | 这里以一个简单的 `Go` 程序为例,该程序输出 `Hello World!` 30 | 31 | 编写 `app.go` 文件 32 | 33 | ```go 34 | package main 35 | 36 | import "fmt" 37 | 38 | func main(){ 39 | fmt.Printf("Hello World!\n"); 40 | } 41 | ``` 42 | 43 | 编写 `.drone.yml` 文件 44 | 45 | ```yaml 46 | kind: pipeline 47 | type: docker 48 | name: build 49 | steps: 50 | - name: build 51 | image: golang:alpine 52 | pull: if-not-exists # always never 53 | environment: 54 | KEY: VALUE 55 | commands: 56 | - echo $KEY 57 | - pwd 58 | - ls 59 | - CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . 60 | - ./app 61 | 62 | trigger: 63 | branch: 64 | - master 65 | ``` 66 | 67 | 现在目录结构如下 68 | 69 | ```bash 70 | . 71 | ├── .drone.yml 72 | └── app.go 73 | ``` 74 | 75 | ## 推送项目源代码到 GitHub 76 | 77 | ```bash 78 | $ git add . 79 | 80 | $ git commit -m "test drone ci" 81 | 82 | $ git push origin master 83 | ``` 84 | 85 | ## 查看项目构建过程及结果 86 | 87 | 打开我们部署好的 `Drone` 网站或者 Drone Cloud,即可看到构建结果。 88 | 89 | ![](./_images/drone-build.png) 90 | 91 | 当然我们也可以把构建结果上传到 GitHub,Docker Registry,云服务商提供的对象存储,或者生产环境中。 92 | 93 | 本书 GitBook 也使用 Drone 进行 CI/CD,具体配置信息请查看本书根目录 [`.drone.yml`](https://github.com/yeasy/docker_practice/blob/master/.drone.yml) 文件。 94 | 95 | ## 参考链接 96 | 97 | * [Drone Github](https://github.com/drone/drone) 98 | * [Drone 文档](https://docs.drone.io/) 99 | * [Drone 示例](https://github.com/docker-practice/drone-demo) 100 | -------------------------------------------------------------------------------- /cases/ci/drone/_images/drone-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/ci/drone/_images/drone-build.png -------------------------------------------------------------------------------- /cases/ci/drone/demo/.drone.yml: -------------------------------------------------------------------------------- 1 | kind: pipeline 2 | type: docker 3 | name: build 4 | steps: 5 | - name: build 6 | image: golang:alpine 7 | pull: if-not-exists # always never 8 | environment: 9 | KEY: VALUE 10 | commands: 11 | - echo $KEY 12 | - pwd 13 | - ls 14 | - CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . 15 | - ./app 16 | 17 | trigger: 18 | branch: 19 | - master 20 | -------------------------------------------------------------------------------- /cases/ci/drone/demo/README.md: -------------------------------------------------------------------------------- 1 | # Drone Demo 2 | -------------------------------------------------------------------------------- /cases/ci/drone/demo/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main(){ 6 | fmt.Printf("Hello World!\n"); 7 | } 8 | -------------------------------------------------------------------------------- /cases/ci/drone/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | drone-server: 6 | image: drone/drone:2.3.1 7 | ports: 8 | - 443:443 9 | - 80:80 10 | volumes: 11 | - drone-data:/data:rw 12 | - ./ssl:/etc/certs 13 | restart: always 14 | environment: 15 | - DRONE_SERVER_HOST=${DRONE_SERVER_HOST:-drone.domain.com} 16 | - DRONE_SERVER_PROTO=${DRONE_SERVER_PROTO:-https} 17 | - DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret} 18 | - DRONE_GITHUB_SERVER=https://github.com 19 | - DRONE_GITHUB_CLIENT_ID=${DRONE_GITHUB_CLIENT_ID} 20 | - DRONE_GITHUB_CLIENT_SECRET=${DRONE_GITHUB_CLIENT_SECRET} 21 | 22 | drone-agent: 23 | image: drone/drone-runner-docker:1 24 | restart: always 25 | depends_on: 26 | - drone-server 27 | volumes: 28 | - /var/run/docker.sock:/var/run/docker.sock:rw 29 | environment: 30 | - DRONE_RPC_PROTO=http 31 | - DRONE_RPC_HOST=drone-server 32 | - DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret} 33 | - DRONE_RUNNER_NAME=${HOSTNAME:-demo} 34 | - DRONE_RUNNER_CAPACITY=2 35 | dns: 114.114.114.114 36 | 37 | volumes: 38 | drone-data: 39 | -------------------------------------------------------------------------------- /cases/ci/drone/install.md: -------------------------------------------------------------------------------- 1 | # 部署 Drone 2 | 3 | ## 要求 4 | 5 | * 拥有公网 IP、域名 (如果你不满足要求,可以尝试在本地使用 Gogs + Drone) 6 | 7 | * 域名 SSL 证书 (目前国内有很多云服务商提供免费证书) 8 | 9 | * 熟悉 `Docker` 以及 `Docker Compose` 10 | 11 | * 熟悉 `Git` 基本命令 12 | 13 | * 对 `CI/CD` 有一定了解 14 | 15 | ## 新建 GitHub 应用 16 | 17 | 登录 GitHub,在 https://github.com/settings/applications/new 新建一个应用。 18 | 19 | ![](https://docs.drone.io/screenshots/github_application_create.png) 20 | 21 | 接下来查看这个应用的详情,记录 `Client ID` 和 `Client Secret`,之后配置 Drone 会用到。 22 | 23 | ## 配置 Drone 24 | 25 | 我们通过使用 `Docker Compose` 来启动 `Drone`,编写 `docker-compose.yml` 文件。 26 | 27 | ```yaml 28 | version: '3' 29 | 30 | services: 31 | 32 | drone-server: 33 | image: drone/drone:2.3.1 34 | ports: 35 | - 443:443 36 | - 80:80 37 | volumes: 38 | - drone-data:/data:rw 39 | - ./ssl:/etc/certs 40 | restart: always 41 | environment: 42 | - DRONE_SERVER_HOST=${DRONE_SERVER_HOST:-https://drone.yeasy.com} 43 | - DRONE_SERVER_PROTO=${DRONE_SERVER_PROTO:-https} 44 | - DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret} 45 | - DRONE_GITHUB_SERVER=https://github.com 46 | - DRONE_GITHUB_CLIENT_ID=${DRONE_GITHUB_CLIENT_ID} 47 | - DRONE_GITHUB_CLIENT_SECRET=${DRONE_GITHUB_CLIENT_SECRET} 48 | 49 | drone-agent: 50 | image: drone/drone-runner-docker:1 51 | restart: always 52 | depends_on: 53 | - drone-server 54 | volumes: 55 | - /var/run/docker.sock:/var/run/docker.sock:rw 56 | environment: 57 | - DRONE_RPC_PROTO=http 58 | - DRONE_RPC_HOST=drone-server 59 | - DRONE_RPC_SECRET=${DRONE_RPC_SECRET:-secret} 60 | - DRONE_RUNNER_NAME=${HOSTNAME:-demo} 61 | - DRONE_RUNNER_CAPACITY=2 62 | dns: 114.114.114.114 63 | 64 | volumes: 65 | drone-data: 66 | ``` 67 | 68 | 新建 `.env` 文件,输入变量及其值 69 | 70 | ```bash 71 | # 必填 服务器地址,例如 drone.domain.com 72 | DRONE_SERVER_HOST= 73 | DRONE_SERVER_PROTO=https 74 | DRONE_RPC_SECRET=secret 75 | HOSTNAME=demo 76 | # 必填 在 GitHub 应用页面查看 77 | DRONE_GITHUB_CLIENT_ID= 78 | # 必填 在 GitHub 应用页面查看 79 | DRONE_GITHUB_CLIENT_SECRET= 80 | ``` 81 | 82 | ### 启动 Drone 83 | 84 | ```bash 85 | $ docker compose up -d 86 | ``` 87 | -------------------------------------------------------------------------------- /cases/os/README.md: -------------------------------------------------------------------------------- 1 | # 操作系统 2 | 3 | 目前常用的 Linux 发行版主要包括 `Debian/Ubuntu` 系列和 `CentOS/Fedora` 系列。 4 | 5 | 前者以自带软件包版本较新而出名;后者则宣称运行更稳定一些。选择哪个操作系统取决于读者的具体需求。 6 | 7 | 使用 Docker,读者只需要一个命令就能快速获取一个 Linux 发行版镜像,这是以往包括各种虚拟化技术都难以实现的。这些镜像一般都很精简,但是可以支持完整 Linux 系统的大部分功能。 8 | 9 | 本章将介绍如何使用 Docker 安装和使用 `Busybox`、`Alphine`、`Debian/Ubuntu`、`CentOS/Fedora` 等操作系统。 10 | -------------------------------------------------------------------------------- /cases/os/_images/alpinelinux-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/alpinelinux-logo.png -------------------------------------------------------------------------------- /cases/os/_images/busybox-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/busybox-logo.png -------------------------------------------------------------------------------- /cases/os/_images/centos-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/centos-logo.png -------------------------------------------------------------------------------- /cases/os/_images/coreos-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/coreos-login.png -------------------------------------------------------------------------------- /cases/os/_images/coreos-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/coreos-logo.jpg -------------------------------------------------------------------------------- /cases/os/_images/coreos_crt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/coreos_crt.png -------------------------------------------------------------------------------- /cases/os/_images/coreos_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/coreos_list.png -------------------------------------------------------------------------------- /cases/os/_images/coreos_run_ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/coreos_run_ip.png -------------------------------------------------------------------------------- /cases/os/_images/debian-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/debian-logo.png -------------------------------------------------------------------------------- /cases/os/_images/docker_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/docker_version.png -------------------------------------------------------------------------------- /cases/os/_images/fedora-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/fedora-logo.png -------------------------------------------------------------------------------- /cases/os/_images/php_pulling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/php_pulling.png -------------------------------------------------------------------------------- /cases/os/_images/ubuntu-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/ubuntu-logo.jpg -------------------------------------------------------------------------------- /cases/os/_images/vmware_coreos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cases/os/_images/vmware_coreos.png -------------------------------------------------------------------------------- /cases/os/alpine.md: -------------------------------------------------------------------------------- 1 | # Alpine 2 | 3 | ## 简介 4 | 5 | ![Alpine Linux 操作系统](./_images/alpinelinux-logo.png) 6 | 7 | `Alpine` 操作系统是一个面向安全的轻型 `Linux` 发行版。它不同于通常 `Linux` 发行版,`Alpine` 采用了 `musl libc` 和 `busybox` 以减小系统的体积和运行时资源消耗,但功能上比 `busybox` 又完善的多,因此得到开源社区越来越多的青睐。在保持瘦身的同时,`Alpine` 还提供了自己的包管理工具 `apk`,可以通过 `https://pkgs.alpinelinux.org/packages` 网站上查询包信息,也可以直接通过 `apk` 命令直接查询和安装各种软件。 8 | 9 | `Alpine` 由非商业组织维护的,支持广泛场景的 `Linux`发行版,它特别为资深/重度`Linux`用户而优化,关注安全,性能和资源效能。`Alpine` 镜像可以适用于更多常用场景,并且是一个优秀的可以适用于生产的基础系统/环境。 10 | 11 | `Alpine` Docker 镜像也继承了 `Alpine Linux` 发行版的这些优势。相比于其他 `Docker` 镜像,它的容量非常小,仅仅只有 **5 MB** 左右(对比 `Ubuntu` 系列镜像接近 `200 MB`),且拥有非常友好的包管理机制。官方镜像来自 `docker-alpine` 项目。 12 | 13 | 目前 Docker 官方已开始推荐使用 `Alpine` 替代之前的 `Ubuntu` 做为基础镜像环境。这样会带来多个好处。包括镜像下载速度加快,镜像安全性提高,主机之间的切换更方便,占用更少磁盘空间等。 14 | 15 | 下表是官方镜像的大小比较: 16 | 17 | ```bash 18 | REPOSITORY TAG IMAGE ID VIRTUAL SIZE 19 | alpine latest 4e38e38c8ce0 4.799 MB 20 | debian latest 4d6ce913b130 84.98 MB 21 | ubuntu latest b39b81afc8ca 188.3 MB 22 | centos latest 8efe422e6104 210 MB 23 | ``` 24 | 25 | ## 获取并使用官方镜像 26 | 27 | 由于镜像很小,下载时间往往很短,读者可以直接使用 `docker run` 指令直接运行一个 `Alpine` 容器,并指定运行的 Linux 指令,例如: 28 | 29 | ```bash 30 | $ docker run alpine echo '123' 31 | 123 32 | ``` 33 | 34 | ## 迁移至 `Alpine` 基础镜像 35 | 36 | 目前,大部分 Docker 官方镜像都已经支持 `Alpine` 作为基础镜像,可以很容易进行迁移。 37 | 38 | 例如: 39 | 40 | * `ubuntu/debian` -> `alpine` 41 | * `python:3` -> `python:3-alpine` 42 | * `ruby:2.6` -> `ruby:2.6-alpine` 43 | 44 | 另外,如果使用 `Alpine` 镜像替换 `Ubuntu` 基础镜像,安装软件包时需要用 `apk` 包管理器替换 `apt` 工具,如 45 | 46 | ```bash 47 | $ apk add --no-cache 48 | ``` 49 | 50 | `Alpine` 中软件安装包的名字可能会与其他发行版有所不同,可以在 `https://pkgs.alpinelinux.org/packages` 网站搜索并确定安装包名称。如果需要的安装包不在主索引内,但是在测试或社区索引中。那么可以按照以下方法使用这些安装包。 51 | 52 | ```bash 53 | $ echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories 54 | $ apk --update add --no-cache 55 | ``` 56 | 57 | 由于在国内访问 `apk` 仓库较缓慢,建议在使用 `apk` 之前先替换仓库地址为国内镜像。 58 | 59 | ```docker 60 | RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \ 61 | && apk add --no-cache 62 | ``` 63 | 64 | ## 相关资源 65 | 66 | * `Alpine` 官网:https://www.alpinelinux.org/ 67 | * `Alpine` 官方仓库:https://github.com/alpinelinux 68 | * `Alpine` 官方镜像:https://hub.docker.com/_/alpine/ 69 | * `Alpine` 官方镜像仓库:https://github.com/gliderlabs/docker-alpine 70 | -------------------------------------------------------------------------------- /cases/os/centos.md: -------------------------------------------------------------------------------- 1 | # CentOS/Fedora 2 | 3 | ## CentOS 系统简介 4 | 5 | `CentOS` 和 `Fedora` 都是基于 `Redhat` 的常见 Linux 分支。`CentOS` 是目前企业级服务器的常用操作系统;`Fedora` 则主要面向个人桌面用户。 6 | 7 | ![CentOS 操作系统](./_images/centos-logo.png) 8 | 9 | CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统),它是基于 `Red Hat Enterprise Linux` 源代码编译而成。由于 `CentOS` 与 `Redhat Linux` 源于相同的代码基础,所以很多成本敏感且需要高稳定性的公司就使用 `CentOS` 来替代商业版 `Red Hat Enterprise Linux`。`CentOS` 自身不包含闭源软件。 10 | 11 | ### 使用 CentOS 官方镜像 12 | 13 | 使用 `docker run` 直接运行 `CentOS 7` 镜像,并登录 `bash`。 14 | 15 | ```bash 16 | $ docker run -it centos:7 bash 17 | Unable to find image 'centos:latest' locally 18 | latest: Pulling from library/centos 19 | 3d8673bd162a: Pull complete 20 | Digest: sha256:a66ffcb73930584413de83311ca11a4cb4938c9b2521d331026dad970c19adf4 21 | Status: Downloaded newer image for centos:latest 22 | [root@43eb3b194d48 /]# cat /etc/redhat-release 23 | CentOS Linux release 7.9.2009 (Core) 24 | ``` 25 | 26 | ## Fedora 系统简介 27 | 28 | ![Fedora 操作系统](./_images/fedora-logo.png) 29 | 30 | `Fedora` 由 `Fedora Project` 社区开发,红帽公司赞助的 `Linux` 发行版。它的目标是创建一套新颖、多功能并且自由和开源的操作系统。`Fedora` 的功能对于用户而言,它是一套功能完备的,可以更新的免费操作系统,而对赞助商 `Red Hat` 而言,它是许多新技术的测试平台。被认为可用的技术最终会加入到 `Red Hat Enterprise Linux` 中。 31 | 32 | ### 使用 Fedora 官方镜像 33 | 34 | 使用 `docker run` 命令直接运行 `Fedora` 官方镜像,并登录 `bash`。 35 | 36 | ```bash 37 | $ docker run -it fedora bash 38 | Unable to find image 'fedora:latest' locally 39 | latest: Pulling from library/fedora 40 | 2bf01635e2a0: Pull complete 41 | Digest: sha256:64a02df6aac27d1200c2572fe4b9949f1970d05f74d367ce4af994ba5dc3669e 42 | Status: Downloaded newer image for fedora:latest 43 | [root@196ca341419b /]# cat /etc/redhat-release 44 | Fedora release 24 (Twenty Four) 45 | ``` 46 | 47 | ## 相关资源 48 | 49 | * `Fedora` 官网:https://getfedora.org/ 50 | * `Fedora` 官方仓库:https://github.com/fedora-infra 51 | * `Fedora` 官方镜像:https://hub.docker.com/_/fedora/ 52 | * `Fedora` 官方镜像仓库:https://github.com/fedora-cloud/docker-brew-fedora 53 | * `CentOS` 官网:https://www.centos.org 54 | * `CentOS` 官方仓库:https://github.com/CentOS 55 | * `CentOS` 官方镜像:https://hub.docker.com/_/centos/ 56 | * `CentOS` 官方镜像仓库:https://github.com/CentOS/CentOS-Dockerfiles 57 | -------------------------------------------------------------------------------- /cases/os/summary.md: -------------------------------------------------------------------------------- 1 | # 本章小结 2 | 3 | 本章讲解了典型操作系统镜像的下载和使用。 4 | 5 | 除了官方的镜像外,在 `Docker Hub` 上还有许多第三方组织或个人上传的 Docker 镜像。 6 | 7 | 读者可以根据具体情况来选择。一般来说: 8 | 9 | * 官方镜像体积都比较小,只带有一些基本的组件。 精简的系统有利于安全、稳定和高效的运行,也适合进行个性化定制。 10 | 11 | * 出于安全考虑,几乎所有官方制作的镜像都没有安装 SSH 服务,无法通过用户名和密码直接登录到容器中。 12 | -------------------------------------------------------------------------------- /cloud/README.md: -------------------------------------------------------------------------------- 1 | # 容器与云计算 2 | 3 | Docker 目前已经得到了众多公有云平台的支持,并成为除虚拟机之外的核心云业务。 4 | 5 | 除了 AWS、Google、Azure 等,国内的各大公有云厂商,基本上都同时支持了虚拟机服务和基于 Kubernetes 的容器云业务。有的还推出了其他服务,例如 [容器镜像服务](https://cloud.tencent.com/act/cps/redirect?redirect=11588&cps_key=3a5255852d5db99dcd5da4c72f05df61) 让用户在云上享有安全高效的镜像托管、分发等服务。 6 | -------------------------------------------------------------------------------- /cloud/_images/ECS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cloud/_images/ECS.jpg -------------------------------------------------------------------------------- /cloud/_images/aliyun-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cloud/_images/aliyun-logo.png -------------------------------------------------------------------------------- /cloud/_images/aws-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cloud/_images/aws-logo.jpg -------------------------------------------------------------------------------- /cloud/_images/qcloud-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cloud/_images/qcloud-logo.jpg -------------------------------------------------------------------------------- /cloud/alicloud.md: -------------------------------------------------------------------------------- 1 | # 阿里云 2 | 3 | ![阿里云](./_images/aliyun-logo.png) 4 | 5 | [阿里云](https://www.aliyun.com?source=5176.11533457&userCode=8lx5zmtu&type=copy) 创立于 2009 年,是中国较早的云计算平台。阿里云致力于提供安全、可靠的计算和数据处理能力。 6 | 7 | [阿里云](https://www.aliyun.com?source=5176.11533457&userCode=8lx5zmtu&type=copy) 的客户群体中,活跃着微博、虎牙、魅族、优酷等一大批明星互联网公司。在天猫双 11 全球狂欢节等极富挑战的应用场景中,阿里云保持着良好的运行纪录。 8 | 9 | [阿里云容器服务 Kubernetes 版 ACK](https://www.aliyun.com/product/kubernetes?source=5176.11533457&userCode=8lx5zmtu&type=copy) 提供了高性能、可伸缩的容器应用管理服务,支持在一组云服务器上通过 Docker 容器来进行应用生命周期管理。容器服务极大简化了用户对容器管理集群的搭建工作,无缝整合了阿里云虚拟化、存储、网络和安全能力。容器服务提供了多种应用发布方式和流水线般的持续交付能力,原生支持微服务架构,助力用户无缝上云和跨云管理。 10 | 11 | ![](https://img.alicdn.com/tps/TB10yjtPpXXXXacXXXXXXXXXXXX-1531-1140.png) 12 | -------------------------------------------------------------------------------- /cloud/aws.md: -------------------------------------------------------------------------------- 1 | # 亚马逊云 2 | 3 | ![AWS](./_images/aws-logo.jpg) 4 | 5 | [AWS](https://www.amazonaws.cn),即 Amazon Web Services,是亚马逊(Amazon)公司的 IaaS 和 PaaS 平台服务。AWS 提供了一整套基础设施和应用程序服务,使用户几乎能够在云中运行一切应用程序:从企业应用程序和大数据项目,到社交游戏和移动应用程序。AWS 面向用户提供包括弹性计算、存储、数据库、应用程序在内的一整套云计算服务,能够帮助企业降低 IT 投入成本和维护成本。 6 | 7 | 自 2006 年初起,亚马逊 AWS 开始在云中为各种规模的公司提供技术服务平台。利用亚马逊 AWS,软件开发人员可以轻松购买计算、存储、数据库和其他基于 Internet 的服务来支持其应用程序。开发人员能够灵活选择任何开发平台或编程环境,以便于其尝试解决问题。由于开发人员只需按使用量付费,无需前期资本支出,亚马逊 AWS 是向最终用户交付计算资源、保存的数据和其他应用程序的一种经济划算的方式。 8 | 9 | 2015 年 AWS 正式发布了 EC2 容器服务(ECS)。ECS 的目的是让 Docker 容器变的更加简单,它提供了一个集群和编排的层,用来控制主机上的容器部署,以及部署之后的集群内的容器的生命周期管理。ECS 是诸如 Docker Swarm、Kubernetes、Mesos 等工具的替代,它们工作在同一个层,除了作为一个服务来提供。这些工具和 ECS 不同的地方在于,前者需要用户自己来部署和管理,而 ECS 是“作为服务”来提供的。 10 | 11 | ![AWS 容器服务](./_images/ECS.jpg) 12 | -------------------------------------------------------------------------------- /cloud/intro.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 目前与容器相关的云计算主要分为两种类型。 4 | 5 | 一种是传统的 IaaS 服务商提供对容器相关的服务,包括镜像下载、容器托管等。 6 | 7 | 另一种是直接基于容器技术对外提供容器云服务,所谓 Container as a Service(CaaS)。 8 | -------------------------------------------------------------------------------- /cloud/summary.md: -------------------------------------------------------------------------------- 1 | # 本章小结 2 | 3 | 本章介绍了公有云服务对 Docker 的积极支持,以及新出现的容器云平台。 4 | 5 | 事实上,Docker 技术的出现自身就极大推动了云计算行业的发展。 6 | 7 | 通过整合公有云的虚拟机和 Docker 方式,可能获得更多的好处,包括 8 | 9 | * 更快速的持续交付和部署能力; 10 | * 利用内核级虚拟化,对公有云中服务器资源进行更加高效地利用; 11 | * 利用公有云和 Docker 的特性更加方便的迁移和扩展应用。 12 | 13 | 同时,容器将作为与虚拟机类似的业务直接提供给用户使用,极大的丰富了应用开发和部署的场景。 14 | -------------------------------------------------------------------------------- /cloud/tencentCloud.md: -------------------------------------------------------------------------------- 1 | # 腾讯云 2 | 3 | ![腾讯云](./_images/qcloud-logo.jpg) 4 | 5 | [腾讯云](https://cloud.tencent.com/act/cps/redirect?redirect=1040&cps_key=3a5255852d5db99dcd5da4c72f05df61&from=console) 在架构方面经过多年积累,并且有着多年对海量互联网服务的经验。不管是社交、游戏还是其他领域,都有多年的成熟产品来提供产品服务。腾讯在云端完成重要部署,为开发者及企业提供云服务、云数据、云运营等整体一站式服务方案。 6 | 7 | 具体包括 [云服务器](https://cloud.tencent.com/act/cps/redirect?redirect=1001&cps_key=3a5255852d5db99dcd5da4c72f05df61&from=console)、[云存储](https://cloud.tencent.com/act/cps/redirect?redirect=1020&cps_key=3a5255852d5db99dcd5da4c72f05df61&from=console)、[云数据库](https://cloud.tencent.com/act/cps/redirect?redirect=1003&cps_key=3a5255852d5db99dcd5da4c72f05df61&from=console)、[视频与CDN](https://cloud.tencent.com/act/cps/redirect?redirect=1019&cps_key=3a5255852d5db99dcd5da4c72f05df61&from=console) 和 [域名注册](https://dnspod.cloud.tencent.com) 等基础云服务;腾讯云分析(MTA)、腾讯云推送(信鸽)等腾讯整体大数据能力;以及 QQ互联、QQ 空间、微云、微社区等云端链接社交体系。这些正是腾讯云可以提供给这个行业的差异化优势,造就了可支持各种互联网使用场景的高品质的腾讯云技术平台。 8 | 9 | [腾讯云容器服务 TKE](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61) 是高度可扩展的高性能容器管理服务,用户可以在托管的云服务器实例集群上轻松运行应用程序。使用该服务,将无需安装、运维、扩展用户的集群管理基础设施,只需进行简单的 API 调用,便可启动和停止 Docker 应用程序,查询集群的完整状态,以及使用各种云服务。用户可以根据用户的资源需求和可用性要求在用户的集群中安排容器的置放,满足业务或应用程序的特定要求。 10 | 11 | ![](https://mc.qcloudimg.com/static/img/0581dbeb97c869bbe6e62025dbc592d7/image.png) 12 | -------------------------------------------------------------------------------- /compose/README.md: -------------------------------------------------------------------------------- 1 | # Docker Compose 项目 2 | 3 | `Docker Compose` 是 Docker 官方编排(Orchestration)项目之一,负责快速的部署分布式应用。 4 | 5 | 本章将介绍 `Compose` 项目情况以及安装和使用。 6 | -------------------------------------------------------------------------------- /compose/demo/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6-alpine 2 | ADD . /code 3 | WORKDIR /code 4 | RUN pip install redis flask 5 | CMD ["python", "app.py"] 6 | -------------------------------------------------------------------------------- /compose/demo/app/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from redis import Redis 3 | 4 | app = Flask(__name__) 5 | redis = Redis(host='redis', port=6379) 6 | 7 | @app.route('/') 8 | def hello(): 9 | count = redis.incr('hits') 10 | return 'Hello World! 该页面已被访问 {} 次。\n'.format(count) 11 | 12 | if __name__ == "__main__": 13 | app.run(host="0.0.0.0", debug=True) 14 | -------------------------------------------------------------------------------- /compose/demo/app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | web: 5 | build: . 6 | ports: 7 | - "5000:5000" 8 | 9 | redis: 10 | image: "redis:alpine" 11 | -------------------------------------------------------------------------------- /compose/demo/django/.gitignore: -------------------------------------------------------------------------------- 1 | django_example 2 | manage.py 3 | -------------------------------------------------------------------------------- /compose/demo/django/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | ENV PYTHONUNBUFFERED 1 3 | RUN mkdir /code 4 | WORKDIR /code 5 | ADD requirements.txt /code/ 6 | RUN pip install -r requirements.txt 7 | ADD . /code/ 8 | -------------------------------------------------------------------------------- /compose/demo/django/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | 4 | db: 5 | image: postgres 6 | environment: 7 | POSTGRES_PASSWORD: 'postgres' 8 | 9 | web: 10 | build: . 11 | command: python manage.py runserver 0.0.0.0:8000 12 | volumes: 13 | - .:/code 14 | ports: 15 | - "8000:8000" 16 | -------------------------------------------------------------------------------- /compose/demo/django/requirements.txt: -------------------------------------------------------------------------------- 1 | Django>=2.0,<3.0 2 | psycopg2>=2.7,<3.0 3 | -------------------------------------------------------------------------------- /compose/demo/wordpress/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | 4 | db: 5 | image: mysql:8.0 6 | command: 7 | - --default_authentication_plugin=mysql_native_password 8 | - --character-set-server=utf8mb4 9 | - --collation-server=utf8mb4_unicode_ci 10 | volumes: 11 | - db_data:/var/lib/mysql 12 | restart: always 13 | environment: 14 | MYSQL_ROOT_PASSWORD: somewordpress 15 | MYSQL_DATABASE: wordpress 16 | MYSQL_USER: wordpress 17 | MYSQL_PASSWORD: wordpress 18 | 19 | wordpress: 20 | depends_on: 21 | - db 22 | image: wordpress:latest 23 | ports: 24 | - "8000:80" 25 | restart: always 26 | environment: 27 | WORDPRESS_DB_HOST: db:3306 28 | WORDPRESS_DB_USER: wordpress 29 | WORDPRESS_DB_PASSWORD: wordpress 30 | volumes: 31 | db_data: 32 | -------------------------------------------------------------------------------- /compose/install.md: -------------------------------------------------------------------------------- 1 | # 安装与卸载 2 | 3 | `Compose` 支持 Linux、macOS、Windows 三大平台。 4 | 5 | `Docker Desktop for Mac/Windows` 自带 `compose`,安装 Docker 之后可以直接使用。 6 | 7 | ```bash 8 | $ docker compose version 9 | 10 | Docker Compose version v2.6.0 11 | ``` 12 | 13 | Linux 系统请使用以下介绍的方法安装。 14 | 15 | ## 二进制包 16 | 17 | 在 Linux 上的也安装十分简单,从 [官方 GitHub Release](https://github.com/docker/compose/releases) 处直接下载编译好的二进制文件即可。 18 | 19 | 例如,在 Linux 64 位系统上直接下载对应的二进制包。 20 | 21 | ```bash 22 | $ DOCKER_CONFIG=/usr/local/lib/docker/cli-plugins 23 | $ sudo mkdir -p $DOCKER_CONFIG/cli-plugins 24 | $ sudo curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose 25 | $ sudo chmod +x $DOCKER_CONFIG/cli-plugins 26 | $ docker compose version 27 | 28 | # 国内用户可以使用以下方式加快下载 29 | $ sudo curl -SL https://download.fastgit.org/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose 30 | ``` 31 | -------------------------------------------------------------------------------- /compose/introduction.md: -------------------------------------------------------------------------------- 1 | # Compose 简介 2 | 3 | `Compose` 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 `OpenStack` 中的 `Heat` 十分类似。 4 | 5 | 其代码目前在 [https://github.com/docker/compose](https://github.com/docker/compose) 上开源。 6 | 7 | `Compose` 定位是 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,其前身是开源项目 Fig。 8 | 9 | 通过第一部分中的介绍,我们知道使用一个 `Dockerfile` 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。 10 | 11 | `Compose` 恰好满足了这样的需求。它允许用户通过一个单独的 `docker-compose.yml` 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。 12 | 13 | `Compose` 中有两个重要的概念: 14 | 15 | * 服务 (`service`):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。 16 | 17 | * 项目 (`project`):由一组关联的应用容器组成的一个完整业务单元,在 `docker-compose.yml` 文件中定义。 18 | 19 | `Compose` 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。 20 | 21 | `Compose` 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 `Compose` 来进行编排管理。 22 | -------------------------------------------------------------------------------- /compose/lnmp.md: -------------------------------------------------------------------------------- 1 | # 使用 compose 搭建 LNMP 环境 2 | 3 | 本项目的维护者 [khs1994](https://github.com/khs1994) 的开源项目 [khs1994-docker/lnmp](https://github.com/khs1994-docker/lnmp) 使用 Docker Compose 搭建了一套 LNMP 环境,各位开发者可以参考该项目在 Docker 或 Kubernetes 中运行 LNMP。 4 | -------------------------------------------------------------------------------- /compose/rails.md: -------------------------------------------------------------------------------- 1 | # 使用 Rails 2 | 3 | > 本小节内容适合 `Ruby` 开发人员阅读。 4 | 5 | 我们现在将使用 `Compose` 配置并运行一个 `Rails/PostgreSQL` 应用。 6 | 7 | 在一切工作开始前,需要先设置好三个必要的文件。 8 | 9 | 首先,因为应用将要运行在一个满足所有环境依赖的 Docker 容器里面,那么我们可以通过编辑 `Dockerfile` 文件来指定 Docker 容器要安装内容。内容如下: 10 | 11 | ```docker 12 | FROM ruby 13 | RUN apt-get update -qq && apt-get install -y build-essential libpq-dev 14 | RUN mkdir /myapp 15 | WORKDIR /myapp 16 | ADD Gemfile /myapp/Gemfile 17 | RUN bundle install 18 | ADD . /myapp 19 | ``` 20 | 21 | 以上内容指定应用将使用安装了 Ruby、Bundler 以及其依赖件的镜像。更多关于如何编写 Dockerfile 文件的信息可以查看 [Dockerfile 使用](../image/dockerfile/README.md)。 22 | 23 | 下一步,我们需要一个引导加载 Rails 的文件 `Gemfile` 。 等一会儿它还会被 `rails new` 命令覆盖重写。 24 | 25 | ```bash 26 | source 'https://rubygems.org' 27 | gem 'rails', '4.0.2' 28 | ``` 29 | 30 | 最后,`docker-compose.yml` 文件才是最神奇的地方。 `docker-compose.yml` 文件将把所有的东西关联起来。它描述了应用的构成(一个 web 服务和一个数据库)、每个镜像的来源(数据库运行在使用预定义的 PostgreSQL 镜像,web 应用侧将从本地目录创建)、镜像之间的连接,以及服务开放的端口。 31 | 32 | ```yaml 33 | version: "3" 34 | services: 35 | 36 | db: 37 | image: postgres 38 | ports: 39 | - "5432" 40 | 41 | web: 42 | build: . 43 | command: bundle exec rackup -p 3000 44 | volumes: 45 | - .:/myapp 46 | ports: 47 | - "3000:3000" 48 | ``` 49 | 50 | 所有文件就绪后,我们就可以通过使用 `docker compose run` 命令生成应用的骨架了。 51 | 52 | ```bash 53 | $ docker compose run web rails new . --force --database=postgresql --skip-bundle 54 | ``` 55 | 56 | `Compose` 会先使用 `Dockerfile` 为 web 服务创建一个镜像,接着使用这个镜像在容器里运行 `rails new ` 和它之后的命令。一旦这个命令运行完后,应该就可以看一个崭新的应用已经生成了。 57 | 58 | ```bash 59 | $ ls 60 | Dockerfile app docker-compose.yml tmp 61 | Gemfile bin lib vendor 62 | Gemfile.lock condocker-compose log 63 | README.rdoc condocker-compose.ru public 64 | Rakefile db test 65 | ``` 66 | 67 | 在新的 `Gemfile` 文件去掉加载 `therubyracer` 的行的注释,这样我们便可以使用 Javascript 运行环境: 68 | 69 | ```bash 70 | gem 'therubyracer', platforms: :ruby 71 | ``` 72 | 73 | 现在我们已经有一个新的 `Gemfile` 文件,需要再重新创建镜像。(这个会步骤会改变 Dockerfile 文件本身,所以需要重建一次)。 74 | 75 | ```bash 76 | $ docker compose build 77 | ``` 78 | 79 | 应用现在就可以启动了,但配置还未完成。Rails 默认读取的数据库目标是 `localhost` ,我们需要手动指定容器的 `db` 。同样的,还需要把用户名修改成和 postgres 镜像预定的一致。 80 | 打开最新生成的 `database.yml` 文件。用以下内容替换: 81 | 82 | ```bash 83 | development: &default 84 | adapter: postgresql 85 | encoding: unicode 86 | database: postgres 87 | pool: 5 88 | username: postgres 89 | password: 90 | host: db 91 | 92 | test: 93 | <<: *default 94 | database: myapp_test 95 | ``` 96 | 97 | 现在就可以启动应用了。 98 | 99 | ```bash 100 | $ docker compose up 101 | ``` 102 | 103 | 如果一切正常,你应该可以看到 PostgreSQL 的输出,几秒后可以看到这样的重复信息: 104 | 105 | ```bash 106 | myapp_web_1 | [2014-01-17 17:16:29] INFO WEBrick 1.3.1 107 | myapp_web_1 | [2014-01-17 17:16:29] INFO ruby 2.0.0 (2013-11-22) [x86_64-linux-gnu] 108 | myapp_web_1 | [2014-01-17 17:16:29] INFO WEBrick::HTTPServer#start: pid=1 port=3000 109 | ``` 110 | 111 | 最后, 我们需要做的是创建数据库,打开另一个终端,运行: 112 | 113 | ```bash 114 | $ docker compose run web rake db:create 115 | ``` 116 | 117 | 这个 web 应用已经开始在你的 docker 守护进程里面监听着 3000 端口了。 118 | -------------------------------------------------------------------------------- /compose/usage.md: -------------------------------------------------------------------------------- 1 | # 使用 2 | 3 | ## 术语 4 | 5 | 首先介绍几个术语。 6 | 7 | * 服务 (`service`):一个应用容器,实际上可以运行多个相同镜像的实例。 8 | 9 | * 项目 (`project`):由一组关联的应用容器组成的一个完整业务单元。 10 | 11 | 可见,一个项目可以由多个服务(容器)关联而成,`Compose` 面向项目进行管理。 12 | 13 | ## 场景 14 | 15 | 最常见的项目是 web 网站,该项目应该包含 web 应用和缓存。 16 | 17 | 下面我们用 `Python` 来建立一个能够记录页面访问次数的 web 网站。 18 | 19 | ### web 应用 20 | 21 | 新建文件夹,在该目录中编写 `app.py` 文件 22 | 23 | ```python 24 | from flask import Flask 25 | from redis import Redis 26 | 27 | app = Flask(__name__) 28 | redis = Redis(host='redis', port=6379) 29 | 30 | @app.route('/') 31 | def hello(): 32 | count = redis.incr('hits') 33 | return 'Hello World! 该页面已被访问 {} 次。\n'.format(count) 34 | 35 | if __name__ == "__main__": 36 | app.run(host="0.0.0.0", debug=True) 37 | ``` 38 | 39 | ### Dockerfile 40 | 41 | 编写 `Dockerfile` 文件,内容为 42 | 43 | ```docker 44 | FROM python:3.6-alpine 45 | ADD . /code 46 | WORKDIR /code 47 | RUN pip install redis flask 48 | CMD ["python", "app.py"] 49 | ``` 50 | 51 | ### docker-compose.yml 52 | 53 | 编写 `docker-compose.yml` 文件,这个是 Compose 使用的主模板文件。 54 | 55 | ```yaml 56 | version: '3' 57 | services: 58 | 59 | web: 60 | build: . 61 | ports: 62 | - "5000:5000" 63 | 64 | redis: 65 | image: "redis:alpine" 66 | ``` 67 | 68 | ### 运行 compose 项目 69 | 70 | ```bash 71 | $ docker compose up 72 | ``` 73 | 74 | 此时访问本地 `5000` 端口,每次刷新页面,计数就会加 1。 75 | -------------------------------------------------------------------------------- /compose/wordpress.md: -------------------------------------------------------------------------------- 1 | # 使用 WordPress 2 | 3 | > 本小节内容适合 `PHP` 开发人员阅读。 4 | 5 | `Compose` 可以很便捷的让 `Wordpress` 运行在一个独立的环境中。 6 | 7 | ## 创建空文件夹 8 | 9 | 假设新建一个名为 `wordpress` 的文件夹,然后进入这个文件夹。 10 | 11 | ## 创建 `docker-compose.yml` 文件 12 | 13 | [`docker-compose.yml`](https://github.com/yeasy/docker_practice/blob/master/compose/demo/wordpress/docker-compose.yml) 文件将开启一个 `wordpress` 服务和一个独立的 `MySQL` 实例: 14 | 15 | ```yaml 16 | version: "3" 17 | services: 18 | 19 | db: 20 | image: mysql:8.0 21 | command: 22 | - --default_authentication_plugin=mysql_native_password 23 | - --character-set-server=utf8mb4 24 | - --collation-server=utf8mb4_unicode_ci 25 | volumes: 26 | - db_data:/var/lib/mysql 27 | restart: always 28 | environment: 29 | MYSQL_ROOT_PASSWORD: somewordpress 30 | MYSQL_DATABASE: wordpress 31 | MYSQL_USER: wordpress 32 | MYSQL_PASSWORD: wordpress 33 | 34 | wordpress: 35 | depends_on: 36 | - db 37 | image: wordpress:latest 38 | ports: 39 | - "8000:80" 40 | restart: always 41 | environment: 42 | WORDPRESS_DB_HOST: db:3306 43 | WORDPRESS_DB_USER: wordpress 44 | WORDPRESS_DB_PASSWORD: wordpress 45 | volumes: 46 | db_data: 47 | ``` 48 | 49 | ## 构建并运行项目 50 | 51 | 运行 `docker compose up -d` Compose 就会拉取镜像再创建我们所需要的镜像,然后启动 `wordpress` 和数据库容器。 接着浏览器访问 `127.0.0.1:8000` 端口就能看到 `WordPress` 安装界面了。 52 | -------------------------------------------------------------------------------- /container/README.md: -------------------------------------------------------------------------------- 1 | # 操作 Docker 容器 2 | 3 | 容器是 Docker 又一核心概念。 4 | 5 | 简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。 6 | 7 | 本章将具体介绍如何来管理一个容器,包括创建、启动和停止等。 8 | -------------------------------------------------------------------------------- /container/attach_exec.md: -------------------------------------------------------------------------------- 1 | # 进入容器 2 | 3 | 在使用 `-d` 参数时,容器启动后会进入后台。 4 | 5 | 某些时候需要进入容器进行操作,包括使用 `docker attach` 命令或 `docker exec` 命令,推荐大家使用 `docker exec` 命令,原因会在下面说明。 6 | 7 | ## `attach` 命令 8 | 9 | 下面示例如何使用 `docker attach` 命令。 10 | 11 | ```bash 12 | $ docker run -dit ubuntu 13 | 243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550 14 | 15 | $ docker container ls 16 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 17 | 243c32535da7 ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds nostalgic_hypatia 18 | 19 | $ docker attach 243c 20 | root@243c32535da7:/# 21 | ``` 22 | 23 | *注意:* 如果从这个 stdin 中 exit,会导致容器的停止。 24 | 25 | ## `exec` 命令 26 | 27 | ### `-i` `-t` 参数 28 | 29 | `docker exec` 后边可以跟多个参数,这里主要说明 `-i` `-t` 参数。 30 | 31 | 只用 `-i` 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。 32 | 33 | 当 `-i` `-t` 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。 34 | 35 | ```bash 36 | $ docker run -dit ubuntu 37 | 69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6 38 | 39 | $ docker container ls 40 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 41 | 69d137adef7a ubuntu:latest "/bin/bash" 18 seconds ago Up 17 seconds zealous_swirles 42 | 43 | $ docker exec -i 69d1 bash 44 | ls 45 | bin 46 | boot 47 | dev 48 | ... 49 | 50 | $ docker exec -it 69d1 bash 51 | root@69d137adef7a:/# 52 | ``` 53 | 54 | 如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 `docker exec` 的原因。 55 | 56 | 更多参数说明请使用 `docker exec --help` 查看。 57 | -------------------------------------------------------------------------------- /container/daemon.md: -------------------------------------------------------------------------------- 1 | # 后台运行 2 | 3 | 更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 `-d` 参数来实现。 4 | 5 | 下面举两个例子来说明一下。 6 | 7 | 如果不使用 `-d` 参数运行容器。 8 | 9 | ```bash 10 | $ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 11 | hello world 12 | hello world 13 | hello world 14 | hello world 15 | ``` 16 | 17 | 容器会把输出的结果 (STDOUT) 打印到宿主机上面 18 | 19 | 如果使用了 `-d` 参数运行容器。 20 | 21 | ```bash 22 | $ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 23 | 77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a 24 | ``` 25 | 26 | 此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用 `docker logs` 查看)。 27 | 28 | **注:** 容器是否会长久运行,是和 `docker run` 指定的命令有关,和 `-d` 参数无关。 29 | 30 | 使用 `-d` 参数启动后会返回一个唯一的 id,也可以通过 `docker container ls` 命令来查看容器信息。 31 | 32 | ``` 33 | $ docker container ls 34 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 35 | 77b2dc01fe0f ubuntu:18.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright 36 | ``` 37 | 38 | 要获取容器的输出信息,可以通过 `docker container logs` 命令。 39 | 40 | ```bash 41 | $ docker container logs [container ID or NAMES] 42 | hello world 43 | hello world 44 | hello world 45 | . . . 46 | ``` 47 | -------------------------------------------------------------------------------- /container/import_export.md: -------------------------------------------------------------------------------- 1 | # 导出和导入容器 2 | 3 | ## 导出容器 4 | 5 | 如果要导出本地某个容器,可以使用 `docker export` 命令。 6 | ```bash 7 | $ docker container ls -a 8 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9 | 7691a814370e ubuntu:18.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test 10 | $ docker export 7691a814370e > ubuntu.tar 11 | ``` 12 | 13 | 这样将导出容器快照到本地文件。 14 | 15 | ## 导入容器快照 16 | 17 | 可以使用 `docker import` 从容器快照文件中再导入为镜像,例如 18 | 19 | ```bash 20 | $ cat ubuntu.tar | docker import - test/ubuntu:v1.0 21 | $ docker image ls 22 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 23 | test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB 24 | ``` 25 | 26 | 此外,也可以通过指定 URL 或者某个目录来导入,例如 27 | 28 | ```bash 29 | $ docker import http://example.com/exampleimage.tgz example/imagerepo 30 | ``` 31 | 32 | *注:用户既可以使用 `docker load` 来导入镜像存储文件到本地镜像库,也可以使用 `docker import` 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。* 33 | -------------------------------------------------------------------------------- /container/rm.md: -------------------------------------------------------------------------------- 1 | # 删除容器 2 | 3 | 可以使用 `docker container rm` 来删除一个处于终止状态的容器。例如 4 | 5 | ```bash 6 | $ docker container rm trusting_newton 7 | trusting_newton 8 | ``` 9 | 10 | 如果要删除一个运行中的容器,可以添加 `-f` 参数。Docker 会发送 `SIGKILL` 信号给容器。 11 | 12 | # 清理所有处于终止状态的容器 13 | 14 | 用 `docker container ls -a` 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。 15 | 16 | ```bash 17 | $ docker container prune 18 | ``` 19 | -------------------------------------------------------------------------------- /container/run.md: -------------------------------------------------------------------------------- 1 | # 启动容器 2 | 3 | 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(`exited`)的容器重新启动。 4 | 5 | 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。 6 | 7 | ## 新建并启动 8 | 9 | 所需要的命令主要为 `docker run`。 10 | 11 | 例如,下面的命令输出一个 “Hello World”,之后终止容器。 12 | 13 | ```bash 14 | $ docker run ubuntu:18.04 /bin/echo 'Hello world' 15 | Hello world 16 | ``` 17 | 18 | 这跟在本地直接执行 `/bin/echo 'hello world'` 几乎感觉不出任何区别。 19 | 20 | 下面的命令则启动一个 bash 终端,允许用户进行交互。 21 | 22 | ```bash 23 | $ docker run -t -i ubuntu:18.04 /bin/bash 24 | root@af8bae53bdd3:/# 25 | ``` 26 | 27 | 其中,`-t` 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, `-i` 则让容器的标准输入保持打开。 28 | 29 | 在交互模式下,用户可以通过所创建的终端来输入命令,例如 30 | 31 | ```bash 32 | root@af8bae53bdd3:/# pwd 33 | / 34 | root@af8bae53bdd3:/# ls 35 | bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var 36 | ``` 37 | 38 | 当利用 `docker run` 来创建容器时,Docker 在后台运行的标准操作包括: 39 | 40 | * 检查本地是否存在指定的镜像,不存在就从 [registry](../repository/README.md) 下载 41 | * 利用镜像创建并启动一个容器 42 | * 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层 43 | * 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去 44 | * 从地址池配置一个 ip 地址给容器 45 | * 执行用户指定的应用程序 46 | * 执行完毕后容器被终止 47 | 48 | ## 启动已终止容器 49 | 50 | 可以利用 `docker container start` 命令,直接将一个已经终止(`exited`)的容器启动运行。 51 | 52 | 容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 `ps` 或 `top` 来查看进程信息。 53 | 54 | ```bash 55 | root@ba267838cc1b:/# ps 56 | PID TTY TIME CMD 57 | 1 ? 00:00:00 bash 58 | 11 ? 00:00:00 ps 59 | ``` 60 | 61 | 可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。 62 | -------------------------------------------------------------------------------- /container/stop.md: -------------------------------------------------------------------------------- 1 | # 终止容器 2 | 3 | 可以使用 `docker container stop` 来终止一个运行中的容器。 4 | 5 | 此外,当 Docker 容器中指定的应用终结时,容器也自动终止。 6 | 7 | 例如对于上一章节中只启动了一个终端的容器,用户通过 `exit` 命令或 `Ctrl+d` 来退出终端时,所创建的容器立刻终止。 8 | 9 | 终止状态的容器可以用 `docker container ls -a` 命令看到。例如 10 | 11 | ```bash 12 | $ docker container ls -a 13 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 14 | ba267838cc1b ubuntu:18.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton 15 | ``` 16 | 17 | 处于终止状态的容器,可以通过 `docker container start` 命令来重新启动。 18 | 19 | 此外,`docker container restart` 命令会将一个运行态的容器终止,然后再重新启动它。 20 | -------------------------------------------------------------------------------- /coreos/README.md: -------------------------------------------------------------------------------- 1 | # Fedora CoreOS 2 | 3 | `CoreOS` 是一个专门为安全和大规模运行容器化工作负载而构建的新 Fedora 版本,它继承了 Fedora Atomic Host 和 CoreOS Container Linux 的优势。 4 | 5 | `CoreOS` 的安装文件和运行依赖非常小,它提供了精简的 Linux 系统。它使用 Linux 容器在更高的抽象层来管理你的服务,而不是通过常规的包管理工具 `yum` 或 `apt` 来安装包。 6 | 7 | 同时,`CoreOS` 几乎可以运行在任何平台:`VirtualBox` `Amazon EC2` `QEMU/KVM` `VMware` `Bare Metal` 和 `OpenStack` 等 。 8 | -------------------------------------------------------------------------------- /coreos/demo/example.fcc: -------------------------------------------------------------------------------- 1 | variant: fcos 2 | version: 1.0.0 3 | passwd: 4 | users: 5 | - name: core 6 | ssh_authorized_keys: 7 | - ssh-rsa AAAA... 8 | -------------------------------------------------------------------------------- /coreos/install.md: -------------------------------------------------------------------------------- 1 | # 安装 Fedora CoreOS 2 | 3 | ## 下载 ISO 4 | 5 | 在 [下载页面](https://getfedora.org/coreos/download/) `Bare Metal & Virtualized` 标签页下载 ISO。 6 | 7 | ## 编写 FCC 8 | 9 | FCC 是 Fedora CoreOS Configuration (Fedora CoreOS 配置)的简称。 10 | 11 | ```yaml 12 | # example.fcc 13 | variant: fcos 14 | version: 1.0.0 15 | passwd: 16 | users: 17 | - name: core 18 | ssh_authorized_keys: 19 | - ssh-rsa AAAA... 20 | ``` 21 | 22 | 将 `ssh-rsa AAAA...` 替换为自己的 SSH 公钥(位于 `~/.ssh/id_rsa.pub`)。 23 | 24 | ## 转换 FCC 为 Ignition 25 | 26 | ```bash 27 | $ docker run -i --rm quay.io/coreos/fcct:v0.5.0 --pretty --strict < example.fcc > example.ign 28 | ``` 29 | 30 | ## 挂载 ISO 启动虚拟机并安装 31 | 32 | > 虚拟机需要分配 3GB 以上内存,否则会无法启动。 33 | 34 | 在虚拟机终端执行以下命令安装: 35 | 36 | ```bash 37 | $ sudo coreos-installer install /dev/sda --ignition-file example.ign 38 | ``` 39 | 40 | 安装之后重新启动即可使用。 41 | 42 | ## 使用 43 | 44 | ```bash 45 | $ ssh core@虚拟机IP 46 | 47 | $ docker --version 48 | ``` 49 | 50 | ## 参考链接 51 | 52 | * [官方文档](https://docs.fedoraproject.org/en-US/fedora-coreos/bare-metal/) 53 | -------------------------------------------------------------------------------- /coreos/intro.md: -------------------------------------------------------------------------------- 1 | # Fedora CoreOS 介绍 2 | 3 | [Fedora CoreOS](https://getfedora.org/coreos/) 是一个自动更新的,最小的,整体的,以容器为中心的操作系统,不仅适用于集群,而且可独立运行,并针对运行 Kubernetes 进行了优化。它旨在结合 CoreOS Container Linux 和 Fedora Atomic Host 的优点,将 Container Linux 中的 [Ignition](https://github.com/coreos/ignition) 与 [rpm-ostree](https://github.com/coreos/rpm-ostree) 和 Project Atomic 中的 SELinux 强化等技术相集成。其目标是提供最佳的容器主机,以安全,大规模地运行容器化的工作负载。 4 | 5 | ## FCOS 特性 6 | 7 | ### 一个最小化操作系统 8 | 9 | FCOS 被设计成一个基于容器的最小化的现代操作系统。它比现有的 Linux 安装平均节省 40% 的 RAM(大约 114M )并允许从 PXE 或 iPXE 非常快速的启动。 10 | 11 | ### 系统初始化 12 | 13 | Ignition 是一种配置实用程序,可读取配置文件(JSON 格式)并根据该配置配置 FCOS 系统。可配置的组件包括存储,文件系统,systemd 和用户。 14 | 15 | Ignition 在系统首次启动期间(在 initramfs 中)仅运行一次。由于 Ignition 在启动过程中的早期运行,因此它可以在用户空间开始启动之前重新对磁盘分区,格式化文件系统,创建用户并写入文件。当 systemd 启动时,systemd 服务已被写入磁盘,从而加快了启动时间。 16 | 17 | ### 自动更新 18 | 19 | FCOS 使用 rpm-ostree 系统进行事务性升级。无需像 yum 升级那样升级单个软件包,而是 rpm-ostree 将 OS 升级作为一个原子单元进行。新的 OS 部署在升级期间进行,并在下次重新引导时生效。如果升级出现问题,则一次回滚和重新启动会使系统返回到先前的状态。确保了系统升级对群集容量的影响降到最小。 20 | 21 | ### 容器工具 22 | 23 | 对于诸如构建,复制和其他管理容器的任务,FCOS 用一组容器工具代替了 **Docker CLI**。**podman CLI** 工具支持许多容器运行时功能,例如运行,启动,停止,列出和删除容器和镜像。**skopeo CLI** 工具可以复制,认证和签名镜像。您还可以使用 **crictl CLI** 工具来处理 CRI-O 容器引擎中的容器和镜像。 24 | 25 | ## 参考文档 26 | 27 | * [官方文档](https://docs.fedoraproject.org/en-US/fedora-coreos/) 28 | * [openshift 官方文档](https://docs.openshift.com/container-platform/4.3/architecture/architecture-rhcos.html) 29 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/cover.jpg -------------------------------------------------------------------------------- /data_management/README.md: -------------------------------------------------------------------------------- 1 | # Docker 数据管理 2 | 3 | ![](./_images/types-of-mounts.png) 4 | 5 | 这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式: 6 | 7 | * 数据卷(Volumes) 8 | 9 | * 挂载主机目录 (Bind mounts) 10 | -------------------------------------------------------------------------------- /data_management/_images/types-of-mounts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/data_management/_images/types-of-mounts.png -------------------------------------------------------------------------------- /data_management/bind-mounts.md: -------------------------------------------------------------------------------- 1 | # 挂载主机目录 2 | 3 | ## 挂载一个主机目录作为数据卷 4 | 5 | 使用 `--mount` 标记可以指定挂载一个本地主机的目录到容器中去。 6 | 7 | ```bash 8 | $ docker run -d -P \ 9 | --name web \ 10 | # -v /src/webapp:/usr/share/nginx/html \ 11 | --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \ 12 | nginx:alpine 13 | ``` 14 | 15 | 上面的命令加载主机的 `/src/webapp` 目录到容器的 `/usr/share/nginx/html`目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 `-v` 参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 `--mount` 参数时如果本地目录不存在,Docker 会报错。 16 | 17 | Docker 挂载主机目录的默认权限是 `读写`,用户也可以通过增加 `readonly` 指定为 `只读`。 18 | 19 | ```bash 20 | $ docker run -d -P \ 21 | --name web \ 22 | # -v /src/webapp:/usr/share/nginx/html:ro \ 23 | --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html,readonly \ 24 | nginx:alpine 25 | ``` 26 | 27 | 加了 `readonly` 之后,就挂载为 `只读` 了。如果你在容器内 `/usr/share/nginx/html` 目录新建文件,会显示如下错误 28 | 29 | ```bash 30 | /usr/share/nginx/html # touch new.txt 31 | touch: new.txt: Read-only file system 32 | ``` 33 | 34 | ## 查看数据卷的具体信息 35 | 36 | 在主机里使用以下命令可以查看 `web` 容器的信息 37 | 38 | ```bash 39 | $ docker inspect web 40 | ``` 41 | 42 | `挂载主机目录` 的配置信息在 "Mounts" Key 下面 43 | 44 | ```json 45 | "Mounts": [ 46 | { 47 | "Type": "bind", 48 | "Source": "/src/webapp", 49 | "Destination": "/usr/share/nginx/html", 50 | "Mode": "", 51 | "RW": true, 52 | "Propagation": "rprivate" 53 | } 54 | ], 55 | ``` 56 | 57 | ## 挂载一个本地主机文件作为数据卷 58 | 59 | `--mount` 标记也可以从主机挂载单个文件到容器中 60 | 61 | ```bash 62 | $ docker run --rm -it \ 63 | # -v $HOME/.bash_history:/root/.bash_history \ 64 | --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \ 65 | ubuntu:18.04 \ 66 | bash 67 | 68 | root@2affd44b4667:/# history 69 | 1 ls 70 | 2 diskutil list 71 | ``` 72 | 73 | 这样就可以记录在容器输入过的命令了。 74 | -------------------------------------------------------------------------------- /data_management/volume.md: -------------------------------------------------------------------------------- 1 | # 数据卷 2 | 3 | `数据卷` 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性: 4 | 5 | * `数据卷` 可以在容器之间共享和重用 6 | 7 | * 对 `数据卷` 的修改会立马生效 8 | 9 | * 对 `数据卷` 的更新,不会影响镜像 10 | 11 | * `数据卷` 默认会一直存在,即使容器被删除 12 | 13 | >注意:`数据卷` 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会复制到数据卷中(仅数据卷为空时会复制)。 14 | 15 | ## 创建一个数据卷 16 | 17 | ```bash 18 | $ docker volume create my-vol 19 | ``` 20 | 21 | 查看所有的 `数据卷` 22 | 23 | ```bash 24 | $ docker volume ls 25 | 26 | DRIVER VOLUME NAME 27 | local my-vol 28 | ``` 29 | 30 | 在主机里使用以下命令可以查看指定 `数据卷` 的信息 31 | 32 | ```bash 33 | $ docker volume inspect my-vol 34 | [ 35 | { 36 | "Driver": "local", 37 | "Labels": {}, 38 | "Mountpoint": "/var/lib/docker/volumes/my-vol/_data", 39 | "Name": "my-vol", 40 | "Options": {}, 41 | "Scope": "local" 42 | } 43 | ] 44 | ``` 45 | 46 | ## 启动一个挂载数据卷的容器 47 | 48 | 在用 `docker run` 命令的时候,使用 `--mount` 标记来将 `数据卷` 挂载到容器里。在一次 `docker run` 中可以挂载多个 `数据卷`。 49 | 50 | 下面创建一个名为 `web` 的容器,并加载一个 `数据卷` 到容器的 `/usr/share/nginx/html` 目录。 51 | 52 | ```bash 53 | $ docker run -d -P \ 54 | --name web \ 55 | # -v my-vol:/usr/share/nginx/html \ 56 | --mount source=my-vol,target=/usr/share/nginx/html \ 57 | nginx:alpine 58 | ``` 59 | 60 | ## 查看数据卷的具体信息 61 | 62 | 在主机里使用以下命令可以查看 `web` 容器的信息 63 | 64 | ```bash 65 | $ docker inspect web 66 | ``` 67 | 68 | `数据卷` 信息在 "Mounts" Key 下面 69 | 70 | ```json 71 | "Mounts": [ 72 | { 73 | "Type": "volume", 74 | "Name": "my-vol", 75 | "Source": "/var/lib/docker/volumes/my-vol/_data", 76 | "Destination": "/usr/share/nginx/html", 77 | "Driver": "local", 78 | "Mode": "", 79 | "RW": true, 80 | "Propagation": "" 81 | } 82 | ], 83 | ``` 84 | 85 | ## 删除数据卷 86 | 87 | ```bash 88 | $ docker volume rm my-vol 89 | ``` 90 | 91 | `数据卷` 是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 `数据卷`,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 `数据卷`。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 `docker rm -v` 这个命令。 92 | 93 | 无主的数据卷可能会占据很多空间,要清理请使用以下命令 94 | 95 | ```bash 96 | $ docker volume prune 97 | ``` 98 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | 5 | gitbook-build: 6 | &gitbook-build 7 | image: yeasy/docker_practice:latest 8 | volumes: 9 | - ./:/srv/gitbook-src 10 | command: build 11 | 12 | gitbook-server: 13 | << : *gitbook-build 14 | ports: 15 | - 4000:4000 16 | command: server 17 | 18 | # docker run -it --rm -p 4000:80 dockerpracticesig/docker_practice 19 | gitbook-offline: 20 | &gitbook-offline 21 | # this image build by GitHub Action 22 | image: dockerpracticesig/docker_practice:gitbook 23 | ports: 24 | - 4000:80 25 | 26 | vuepress-offline: 27 | << : *gitbook-offline 28 | image: dockerpracticesig/docker_practice:vuepress 29 | 30 | # developer test docker image 31 | 32 | development: 33 | build: ./.travis 34 | image: yeasy/docker_practice:latest 35 | ports: 36 | - 4000:4000 37 | volumes: 38 | - ./:/srv/gitbook-src 39 | command: server 40 | # command: build 41 | -------------------------------------------------------------------------------- /etcd/README.md: -------------------------------------------------------------------------------- 1 | # etcd 2 | 3 | `etcd` 是 `CoreOS` 团队发起的一个管理配置信息和服务发现(`Service Discovery`)的项目,在这一章里面,我们将基于 `etcd 3.x` 版本介绍该项目的目标,安装和使用,以及实现的技术。 4 | -------------------------------------------------------------------------------- /etcd/_images/etcd_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/etcd/_images/etcd_logo.png -------------------------------------------------------------------------------- /etcd/demo/cluster/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.6" 2 | services: 3 | 4 | node1: 5 | image: quay.io/coreos/etcd:v3.4.0 6 | volumes: 7 | - node1-data:/etcd-data 8 | expose: 9 | - 2379 10 | - 2380 11 | networks: 12 | cluster_net: 13 | ipv4_address: 172.16.238.100 14 | environment: 15 | - ETCDCTL_API=3 16 | command: 17 | - /usr/local/bin/etcd 18 | - --data-dir=/etcd-data 19 | - --name 20 | - node1 21 | - --initial-advertise-peer-urls 22 | - http://172.16.238.100:2380 23 | - --listen-peer-urls 24 | - http://0.0.0.0:2380 25 | - --advertise-client-urls 26 | - http://172.16.238.100:2379 27 | - --listen-client-urls 28 | - http://0.0.0.0:2379 29 | - --initial-cluster 30 | - node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380 31 | - --initial-cluster-state 32 | - new 33 | - --initial-cluster-token 34 | - docker-etcd 35 | 36 | node2: 37 | image: quay.io/coreos/etcd:v3.4.0 38 | volumes: 39 | - node2-data:/etcd-data 40 | networks: 41 | cluster_net: 42 | ipv4_address: 172.16.238.101 43 | environment: 44 | - ETCDCTL_API=3 45 | expose: 46 | - 2379 47 | - 2380 48 | command: 49 | - /usr/local/bin/etcd 50 | - --data-dir=/etcd-data 51 | - --name 52 | - node2 53 | - --initial-advertise-peer-urls 54 | - http://172.16.238.101:2380 55 | - --listen-peer-urls 56 | - http://0.0.0.0:2380 57 | - --advertise-client-urls 58 | - http://172.16.238.101:2379 59 | - --listen-client-urls 60 | - http://0.0.0.0:2379 61 | - --initial-cluster 62 | - node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380 63 | - --initial-cluster-state 64 | - new 65 | - --initial-cluster-token 66 | - docker-etcd 67 | 68 | node3: 69 | image: quay.io/coreos/etcd:v3.4.0 70 | volumes: 71 | - node3-data:/etcd-data 72 | networks: 73 | cluster_net: 74 | ipv4_address: 172.16.238.102 75 | environment: 76 | - ETCDCTL_API=3 77 | expose: 78 | - 2379 79 | - 2380 80 | command: 81 | - /usr/local/bin/etcd 82 | - --data-dir=/etcd-data 83 | - --name 84 | - node3 85 | - --initial-advertise-peer-urls 86 | - http://172.16.238.102:2380 87 | - --listen-peer-urls 88 | - http://0.0.0.0:2380 89 | - --advertise-client-urls 90 | - http://172.16.238.102:2379 91 | - --listen-client-urls 92 | - http://0.0.0.0:2379 93 | - --initial-cluster 94 | - node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380 95 | - --initial-cluster-state 96 | - new 97 | - --initial-cluster-token 98 | - docker-etcd 99 | 100 | volumes: 101 | node1-data: 102 | node2-data: 103 | node3-data: 104 | 105 | networks: 106 | cluster_net: 107 | driver: bridge 108 | ipam: 109 | driver: default 110 | config: 111 | - 112 | subnet: 172.16.238.0/24 113 | -------------------------------------------------------------------------------- /etcd/install.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | `etcd` 基于 `Go` 语言实现,因此,用户可以从 [项目主页](https://github.com/etcd-io/etcd) 下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 `Docker` 镜像文件来体验。 4 | 5 | >注意:本章节内容基于 etcd `3.4.x` 版本 6 | 7 | ## 二进制文件方式下载 8 | 9 | 编译好的二进制文件都在 [github.com/etcd-io/etcd/releases](https://github.com/etcd-io/etcd/releases/) 页面,用户可以选择需要的版本,或通过下载工具下载。 10 | 11 | 例如,使用 `curl` 工具下载压缩包,并解压。 12 | 13 | ```bash 14 | $ curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz 15 | 16 | # 国内用户可以使用以下方式加快下载 17 | $ curl -L https://download.fastgit.org/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz 18 | 19 | $ tar xzvf etcd-v3.4.0-linux-amd64.tar.gz 20 | $ cd etcd-v3.4.0-linux-amd64 21 | ``` 22 | 23 | 解压后,可以看到文件包括 24 | 25 | ```bash 26 | $ ls 27 | Documentation README-etcdctl.md README.md READMEv2-etcdctl.md etcd etcdctl 28 | ``` 29 | 30 | 其中 `etcd` 是服务主文件,`etcdctl` 是提供给用户的命令客户端,其他文件是支持文档。 31 | 32 | 下面将 `etcd` `etcdctl` 文件放到系统可执行目录(例如 `/usr/local/bin/`)。 33 | 34 | ```bash 35 | $ sudo cp etcd* /usr/local/bin/ 36 | ``` 37 | 38 | 默认 `2379` 端口处理客户端的请求,`2380` 端口用于集群各成员间的通信。启动 `etcd` 显示类似如下的信息: 39 | 40 | ```bash 41 | $ etcd 42 | ... 43 | 2017-12-03 11:18:34.411579 I | embed: listening for peers on http://localhost:2380 44 | 2017-12-03 11:18:34.411938 I | embed: listening for client requests on localhost:2379 45 | ``` 46 | 47 | 此时,可以使用 `etcdctl` 命令进行测试,设置和获取键值 `testkey: "hello world"`,检查 `etcd` 服务是否启动成功: 48 | 49 | ```bash 50 | $ ETCDCTL_API=3 etcdctl member list 51 | 8e9e05c52164694d, started, default, http://localhost:2380, http://localhost:2379 52 | 53 | $ ETCDCTL_API=3 etcdctl put testkey "hello world" 54 | OK 55 | 56 | $ etcdctl get testkey 57 | testkey 58 | hello world 59 | ``` 60 | 61 | 说明 etcd 服务已经成功启动了。 62 | 63 | ## Docker 镜像方式运行 64 | 65 | 镜像名称为 `quay.io/coreos/etcd`,可以通过下面的命令启动 `etcd` 服务监听到 `2379` 和 `2380` 端口。 66 | 67 | ```bash 68 | $ docker run \ 69 | -p 2379:2379 \ 70 | -p 2380:2380 \ 71 | --mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \ 72 | --name etcd-gcr-v3.4.0 \ 73 | quay.io/coreos/etcd:v3.4.0 \ 74 | /usr/local/bin/etcd \ 75 | --name s1 \ 76 | --data-dir /etcd-data \ 77 | --listen-client-urls http://0.0.0.0:2379 \ 78 | --advertise-client-urls http://0.0.0.0:2379 \ 79 | --listen-peer-urls http://0.0.0.0:2380 \ 80 | --initial-advertise-peer-urls http://0.0.0.0:2380 \ 81 | --initial-cluster s1=http://0.0.0.0:2380 \ 82 | --initial-cluster-token tkn \ 83 | --initial-cluster-state new \ 84 | --log-level info \ 85 | --logger zap \ 86 | --log-outputs stderr 87 | ``` 88 | 89 | 打开新的终端按照上一步的方法测试 `etcd` 是否成功启动。 90 | 91 | ## macOS 中运行 92 | 93 | ```bash 94 | $ brew install etcd 95 | 96 | $ etcd 97 | 98 | $ etcdctl member list 99 | ``` 100 | -------------------------------------------------------------------------------- /etcd/intro.md: -------------------------------------------------------------------------------- 1 | # 什么是 etcd 2 | 3 | ![](./_images/etcd_logo.png) 4 | 5 | `etcd` 是 `CoreOS` 团队于 2013 年 6 月发起的开源项目,它的目标是构建一个高可用的分布式键值(`key-value`)数据库,基于 `Go` 语言实现。我们知道,在分布式系统中,各种服务的配置信息的管理分享,服务的发现是一个很基本同时也是很重要的问题。`CoreOS` 项目就希望基于 `etcd` 来解决这一问题。 6 | 7 | `etcd` 目前在 [github.com/etcd-io/etcd](https://github.com/etcd-io/etcd) 进行维护。 8 | 9 | 受到 [Apache ZooKeeper](https://zookeeper.apache.org/) 项目和 [doozer](https://github.com/ha/doozerd) 项目的启发,`etcd` 在设计的时候重点考虑了下面四个要素: 10 | 11 | * 简单:具有定义良好、面向用户的 `API` ([gRPC](https://github.com/grpc/grpc)) 12 | 13 | * 安全:支持 `HTTPS` 方式的访问 14 | 15 | * 快速:支持并发 `10 k/s` 的写操作 16 | 17 | * 可靠:支持分布式结构,基于 `Raft` 的一致性算法 18 | 19 | *Apache ZooKeeper 是一套知名的分布式系统中进行同步和一致性管理的工具。* 20 | 21 | *doozer 是一个一致性分布式数据库。* 22 | 23 | *[Raft](https://raft.github.io/) 是一套通过选举主节点来实现分布式系统一致性的算法,相比于大名鼎鼎的 Paxos 算法,它的过程更容易被人理解,由 Stanford 大学的 Diego Ongaro 和 John Ousterhout 提出。更多细节可以参考 [raftconsensus.github.io](http://raftconsensus.github.io)。* 24 | 25 | 一般情况下,用户使用 `etcd` 可以在多个节点上启动多个实例,并添加它们为一个集群。同一个集群中的 `etcd` 实例将会保持彼此信息的一致性。 26 | -------------------------------------------------------------------------------- /ide/README.md: -------------------------------------------------------------------------------- 1 | # 在 IDE 中使用 Docker 2 | 3 | 使用 IDE 进行开发,往往要求本地安装好工具链。一些 IDE 支持 Docker 容器中的工具链,这样充分利用了 Docker 的优点,而无需在本地安装。 4 | -------------------------------------------------------------------------------- /ide/vsCode.md: -------------------------------------------------------------------------------- 1 | # VS Code 中使用 Docker 2 | 3 | ## 将 Docker 容器作为远程开发环境 4 | 5 | 无需本地安装开发工具,直接将 Docker 容器作为开发环境,具体参考 [官方文档](https://code.visualstudio.com/docs/remote/containers)。 6 | -------------------------------------------------------------------------------- /image/README.md: -------------------------------------------------------------------------------- 1 | # 使用 Docker 镜像 2 | 3 | 在之前的介绍中,我们知道镜像是 Docker 的三大组件之一。 4 | 5 | Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。 6 | 7 | 本章将介绍更多关于镜像的内容,包括: 8 | 9 | * 从仓库获取镜像; 10 | 11 | * 管理本地主机上的镜像; 12 | 13 | * 介绍镜像实现的基本原理。 14 | -------------------------------------------------------------------------------- /image/_images/images-create-nginx-docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/image/_images/images-create-nginx-docker.png -------------------------------------------------------------------------------- /image/_images/images-mac-example-nginx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/image/_images/images-mac-example-nginx.png -------------------------------------------------------------------------------- /image/demo/buildkit/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine as builder 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json /app/ 6 | 7 | RUN npm i --registry=https://registry.npmmirror.com \ 8 | && rm -rf ~/.npm 9 | 10 | COPY src /app/src 11 | 12 | RUN npm run build 13 | 14 | FROM nginx:alpine 15 | 16 | COPY --from=builder /app/dist /app/dist 17 | -------------------------------------------------------------------------------- /image/demo/buildkit/Dockerfile.buildkit: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:experimental 2 | 3 | FROM node:alpine as builder 4 | 5 | WORKDIR /app 6 | 7 | COPY package.json /app/ 8 | 9 | RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \ 10 | --mount=type=cache,target=/root/.npm,id=npm_cache \ 11 | npm i --registry=https://registry.npmmirror.com 12 | 13 | COPY src /app/src 14 | 15 | RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \ 16 | # --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \ 17 | npm run build 18 | 19 | FROM nginx:alpine 20 | 21 | # COPY --from=builder /app/dist /app/dist 22 | 23 | # 为了更直观的说明 from 和 source 指令,这里使用 RUN 指令 24 | RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \ 25 | # --mount=type=cache,target/tmp/dist,from=my_app_dist,sharing=locked \ 26 | mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist 27 | 28 | RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \ 29 | cat /docker-php-entrypoint 30 | 31 | RUN --mount=type=tmpfs,target=/temp \ 32 | mount | grep /temp 33 | 34 | RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \ 35 | cat /root/.aws/credentials 36 | 37 | # docker build -t test --secret id=aws,src=$PWD/aws.txt --progress=plain -f Dockerfile.buildkit . 38 | -------------------------------------------------------------------------------- /image/demo/buildkit/aws.txt: -------------------------------------------------------------------------------- 1 | awskey 2 | -------------------------------------------------------------------------------- /image/demo/buildkit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my_app", 3 | "version": "19.6.0", 4 | "devDependencies": { 5 | "webpack": "*", 6 | "webpack-cli": "*" 7 | }, 8 | "scripts": { 9 | "build": "mkdir -p $PWD/dist && cp -r src/* dist/" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /image/demo/buildkit/src/index.js: -------------------------------------------------------------------------------- 1 | console.log(1); 2 | -------------------------------------------------------------------------------- /image/demo/multi-arch/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=$TARGETPLATFORM alpine 2 | 3 | RUN uname -a > /os.txt 4 | 5 | CMD cat /os.txt 6 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/.gitignore: -------------------------------------------------------------------------------- 1 | app 2 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine as builder 2 | 3 | RUN apk --no-cache add git 4 | 5 | WORKDIR /go/src/github.com/go/helloworld/ 6 | 7 | RUN go get -d -v github.com/go-sql-driver/mysql 8 | 9 | COPY app.go . 10 | 11 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . 12 | 13 | FROM alpine:latest as prod 14 | 15 | RUN apk --no-cache add ca-certificates 16 | 17 | WORKDIR /root/ 18 | 19 | COPY --from=0 /go/src/github.com/go/helloworld/app . 20 | 21 | CMD ["./app"] 22 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/Dockerfile.build: -------------------------------------------------------------------------------- 1 | FROM golang:alpine 2 | 3 | RUN apk --no-cache add git 4 | 5 | WORKDIR /go/src/github.com/go/helloworld 6 | 7 | COPY app.go . 8 | 9 | RUN go get -d -v github.com/go-sql-driver/mysql \ 10 | && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . 11 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/Dockerfile.copy: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk --no-cache add ca-certificates 4 | 5 | WORKDIR /root/ 6 | 7 | COPY app . 8 | 9 | CMD ["./app"] 10 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/Dockerfile.one: -------------------------------------------------------------------------------- 1 | FROM golang:alpine 2 | 3 | RUN apk --no-cache add git ca-certificates 4 | 5 | WORKDIR /go/src/github.com/go/helloworld/ 6 | 7 | COPY app.go . 8 | 9 | RUN go get -d -v github.com/go-sql-driver/mysql \ 10 | && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ 11 | && cp /go/src/github.com/go/helloworld/app /root 12 | 13 | WORKDIR /root/ 14 | 15 | CMD ["./app"] 16 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main(){ 6 | fmt.Printf("Hello World!"); 7 | } 8 | -------------------------------------------------------------------------------- /image/demo/multistage-builds/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo Building go/helloworld:build 4 | 5 | docker build -t go/helloworld:build . -f Dockerfile.build 6 | 7 | docker create --name extract go/helloworld:build 8 | docker cp extract:/go/src/github.com/go/helloworld/app ./app 9 | docker rm -f extract 10 | 11 | echo Building go/helloworld:2 12 | 13 | docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy 14 | rm ./app 15 | -------------------------------------------------------------------------------- /image/dockerfile/README.md: -------------------------------------------------------------------------------- 1 | # Dockerfile 指令详解 2 | 3 | 我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。 4 | -------------------------------------------------------------------------------- /image/dockerfile/add.md: -------------------------------------------------------------------------------- 1 | # ADD 更高级的复制文件 2 | 3 | `ADD` 指令和 `COPY` 的格式和性质基本一致。但是在 `COPY` 基础上增加了一些功能。 4 | 5 | 比如 `<源路径>` 可以是一个 `URL`,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 `<目标路径>` 去。下载后的文件权限自动设置为 `600`,如果这并不是想要的权限,那么还需要增加额外的一层 `RUN` 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 `RUN` 指令进行解压缩。所以不如直接使用 `RUN` 指令,然后使用 `wget` 或者 `curl` 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。 6 | 7 | 如果 `<源路径>` 为一个 `tar` 压缩文件的话,压缩格式为 `gzip`, `bzip2` 以及 `xz` 的情况下,`ADD` 指令将会自动解压缩这个压缩文件到 `<目标路径>` 去。 8 | 9 | 在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 `ubuntu` 中: 10 | 11 | ```docker 12 | FROM scratch 13 | ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / 14 | ... 15 | ``` 16 | 17 | 但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 `ADD` 命令了。 18 | 19 | 在 Docker 官方的 [Dockerfile 最佳实践文档](../../appendix/best_practices.md) 中要求,尽可能的使用 `COPY`,因为 `COPY` 的语义很明确,就是复制文件而已,而 `ADD` 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 `ADD` 的场合,就是所提及的需要自动解压缩的场合。 20 | 21 | 另外需要注意的是,`ADD` 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。 22 | 23 | 因此在 `COPY` 和 `ADD` 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 `COPY` 指令,仅在需要自动解压缩的场合使用 `ADD`。 24 | 25 | 在使用该指令的时候还可以加上 `--chown=:` 选项来改变文件的所属用户及所属组。 26 | 27 | ```docker 28 | ADD --chown=55:mygroup files* /mydir/ 29 | ADD --chown=bin files* /mydir/ 30 | ADD --chown=1 files* /mydir/ 31 | ADD --chown=10:11 files* /mydir/ 32 | ``` 33 | -------------------------------------------------------------------------------- /image/dockerfile/arg.md: -------------------------------------------------------------------------------- 1 | # ARG 构建参数 2 | 3 | 格式:`ARG <参数名>[=<默认值>]` 4 | 5 | 构建参数和 `ENV` 的效果一样,都是设置环境变量。所不同的是,`ARG` 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 `ARG` 保存密码之类的信息,因为 `docker history` 还是可以看到所有值的。 6 | 7 | `Dockerfile` 中的 `ARG` 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 `docker build` 中用 `--build-arg <参数名>=<值>` 来覆盖。 8 | 9 | 灵活的使用 `ARG` 指令,能够在不修改 Dockerfile 的情况下,构建出不同的镜像。 10 | 11 | ARG 指令有生效范围,如果在 `FROM` 指令之前指定,那么只能用于 `FROM` 指令中。 12 | 13 | ```docker 14 | ARG DOCKER_USERNAME=library 15 | 16 | FROM ${DOCKER_USERNAME}/alpine 17 | 18 | RUN set -x ; echo ${DOCKER_USERNAME} 19 | ``` 20 | 21 | 使用上述 Dockerfile 会发现无法输出 `${DOCKER_USERNAME}` 变量的值,要想正常输出,你必须在 `FROM` 之后再次指定 `ARG` 22 | 23 | ```docker 24 | # 只在 FROM 中生效 25 | ARG DOCKER_USERNAME=library 26 | 27 | FROM ${DOCKER_USERNAME}/alpine 28 | 29 | # 要想在 FROM 之后使用,必须再次指定 30 | ARG DOCKER_USERNAME=library 31 | 32 | RUN set -x ; echo ${DOCKER_USERNAME} 33 | ``` 34 | 35 | 对于多阶段构建,尤其要注意这个问题 36 | 37 | ```docker 38 | # 这个变量在每个 FROM 中都生效 39 | ARG DOCKER_USERNAME=library 40 | 41 | FROM ${DOCKER_USERNAME}/alpine 42 | 43 | RUN set -x ; echo 1 44 | 45 | FROM ${DOCKER_USERNAME}/alpine 46 | 47 | RUN set -x ; echo 2 48 | ``` 49 | 50 | 对于上述 Dockerfile 两个 `FROM` 指令都可以使用 `${DOCKER_USERNAME}`,对于在各个阶段中使用的变量都必须在每个阶段分别指定: 51 | 52 | ```docker 53 | ARG DOCKER_USERNAME=library 54 | 55 | FROM ${DOCKER_USERNAME}/alpine 56 | 57 | # 在FROM 之后使用变量,必须在每个阶段分别指定 58 | ARG DOCKER_USERNAME=library 59 | 60 | RUN set -x ; echo ${DOCKER_USERNAME} 61 | 62 | FROM ${DOCKER_USERNAME}/alpine 63 | 64 | # 在FROM 之后使用变量,必须在每个阶段分别指定 65 | ARG DOCKER_USERNAME=library 66 | 67 | RUN set -x ; echo ${DOCKER_USERNAME} 68 | ``` 69 | -------------------------------------------------------------------------------- /image/dockerfile/cmd.md: -------------------------------------------------------------------------------- 1 | # CMD 容器启动命令 2 | 3 | `CMD` 指令的格式和 `RUN` 相似,也是两种格式: 4 | 5 | * `shell` 格式:`CMD <命令>` 6 | * `exec` 格式:`CMD ["可执行文件", "参数1", "参数2"...]` 7 | * 参数列表格式:`CMD ["参数1", "参数2"...]`。在指定了 `ENTRYPOINT` 指令后,用 `CMD` 指定具体的参数。 8 | 9 | 之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。`CMD` 指令就是用于指定默认的容器主进程的启动命令的。 10 | 11 | 在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,`ubuntu` 镜像默认的 `CMD` 是 `/bin/bash`,如果我们直接 `docker run -it ubuntu` 的话,会直接进入 `bash`。我们也可以在运行时指定运行别的命令,如 `docker run -it ubuntu cat /etc/os-release`。这就是用 `cat /etc/os-release` 命令替换了默认的 `/bin/bash` 命令了,输出了系统版本信息。 12 | 13 | 在指令格式上,一般推荐使用 `exec` 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 `"`,而不要使用单引号。 14 | 15 | 如果使用 `shell` 格式的话,实际的命令会被包装为 `sh -c` 的参数的形式进行执行。比如: 16 | 17 | ```docker 18 | CMD echo $HOME 19 | ``` 20 | 21 | 在实际执行中,会将其变更为: 22 | 23 | ```docker 24 | CMD [ "sh", "-c", "echo $HOME" ] 25 | ``` 26 | 27 | 这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。 28 | 29 | 提到 `CMD` 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。 30 | 31 | Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 `systemd` 去启动后台服务,容器内没有后台服务的概念。 32 | 33 | 一些初学者将 `CMD` 写为: 34 | 35 | ```docker 36 | CMD service nginx start 37 | ``` 38 | 39 | 然后发现容器执行后就立即退出了。甚至在容器内去使用 `systemctl` 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。 40 | 41 | 对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。 42 | 43 | 而使用 `service nginx start` 命令,则是希望 upstart 来以后台守护进程形式启动 `nginx` 服务。而刚才说了 `CMD service nginx start` 会被理解为 `CMD [ "sh", "-c", "service nginx start"]`,因此主进程实际上是 `sh`。那么当 `service nginx start` 命令结束后,`sh` 也就结束了,`sh` 作为主进程退出了,自然就会令容器退出。 44 | 45 | 正确的做法是直接执行 `nginx` 可执行文件,并且要求以前台形式运行。比如: 46 | 47 | ```docker 48 | CMD ["nginx", "-g", "daemon off;"] 49 | ``` 50 | -------------------------------------------------------------------------------- /image/dockerfile/copy.md: -------------------------------------------------------------------------------- 1 | # COPY 复制文件 2 | 3 | 格式: 4 | 5 | * `COPY [--chown=:] <源路径>... <目标路径>` 6 | * `COPY [--chown=:] ["<源路径1>",... "<目标路径>"]` 7 | 8 | 和 `RUN` 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。 9 | 10 | `COPY` 指令将从构建上下文目录中 `<源路径>` 的文件/目录复制到新的一层的镜像内的 `<目标路径>` 位置。比如: 11 | 12 | ```docker 13 | COPY package.json /usr/src/app/ 14 | ``` 15 | 16 | `<源路径>` 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 [`filepath.Match`](https://golang.org/pkg/path/filepath/#Match) 规则,如: 17 | 18 | ```docker 19 | COPY hom* /mydir/ 20 | COPY hom?.txt /mydir/ 21 | ``` 22 | 23 | `<目标路径>` 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 `WORKDIR` 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。 24 | 25 | 此外,还需要注意一点,使用 `COPY` 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。 26 | 27 | 在使用该指令的时候还可以加上 `--chown=:` 选项来改变文件的所属用户及所属组。 28 | 29 | ```docker 30 | COPY --chown=55:mygroup files* /mydir/ 31 | COPY --chown=bin files* /mydir/ 32 | COPY --chown=1 files* /mydir/ 33 | COPY --chown=10:11 files* /mydir/ 34 | ``` 35 | 36 | 如果源路径为文件夹,复制的时候不是直接复制该文件夹,而是将文件夹中的内容复制到目标路径。 37 | -------------------------------------------------------------------------------- /image/dockerfile/env.md: -------------------------------------------------------------------------------- 1 | # ENV 设置环境变量 2 | 3 | 格式有两种: 4 | 5 | * `ENV ` 6 | * `ENV = =...` 7 | 8 | 这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 `RUN`,还是运行时的应用,都可以直接使用这里定义的环境变量。 9 | 10 | ```docker 11 | ENV VERSION=1.0 DEBUG=on \ 12 | NAME="Happy Feet" 13 | ``` 14 | 15 | 这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。 16 | 17 | 定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。比如在官方 `node` 镜像 `Dockerfile` 中,就有类似这样的代码: 18 | 19 | ```docker 20 | ENV NODE_VERSION 7.2.0 21 | 22 | RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \ 23 | && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ 24 | && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \ 25 | && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \ 26 | && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \ 27 | && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ 28 | && ln -s /usr/local/bin/node /usr/local/bin/nodejs 29 | ``` 30 | 31 | 在这里先定义了环境变量 `NODE_VERSION`,其后的 `RUN` 这层里,多次使用 `$NODE_VERSION` 来进行操作定制。可以看到,将来升级镜像构建版本的时候,只需要更新 `7.2.0` 即可,`Dockerfile` 构建维护变得更轻松了。 32 | 33 | 下列指令可以支持环境变量展开: `ADD`、`COPY`、`ENV`、`EXPOSE`、`FROM`、`LABEL`、`USER`、`WORKDIR`、`VOLUME`、`STOPSIGNAL`、`ONBUILD`、`RUN`。 34 | 35 | 可以从这个指令列表里感觉到,环境变量可以使用的地方很多,很强大。通过环境变量,我们可以让一份 `Dockerfile` 制作更多的镜像,只需使用不同的环境变量即可。 36 | -------------------------------------------------------------------------------- /image/dockerfile/expose.md: -------------------------------------------------------------------------------- 1 | # EXPOSE 声明端口 2 | 3 | 格式为 `EXPOSE <端口1> [<端口2>...]`。 4 | 5 | `EXPOSE` 指令是声明容器运行时提供服务的端口,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 `docker run -P` 时,会自动随机映射 `EXPOSE` 的端口。 6 | 7 | 要将 `EXPOSE` 和在运行时使用 `-p <宿主端口>:<容器端口>` 区分开来。`-p`,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 `EXPOSE` 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。 8 | -------------------------------------------------------------------------------- /image/dockerfile/label.md: -------------------------------------------------------------------------------- 1 | # LABEL 指令 2 | 3 | `LABEL` 指令用来给镜像以键值对的形式添加一些元数据(metadata)。 4 | 5 | ```docker 6 | LABEL = = = ... 7 | ``` 8 | 9 | 我们还可以用一些标签来申明镜像的作者、文档地址等: 10 | 11 | ```docker 12 | LABEL org.opencontainers.image.authors="yeasy" 13 | 14 | LABEL org.opencontainers.image.documentation="https://yeasy.gitbooks.io" 15 | ``` 16 | 17 | 具体可以参考 https://github.com/opencontainers/image-spec/blob/master/annotations.md 18 | -------------------------------------------------------------------------------- /image/dockerfile/onbuild.md: -------------------------------------------------------------------------------- 1 | # ONBUILD 为他人做嫁衣裳 2 | 3 | 格式:`ONBUILD <其它指令>`。 4 | 5 | `ONBUILD` 是一个特殊的指令,它后面跟的是其它指令,比如 `RUN`, `COPY` 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。 6 | 7 | `Dockerfile` 中的其它指令都是为了定制当前镜像而准备的,唯有 `ONBUILD` 是为了帮助别人定制自己而准备的。 8 | 9 | 假设我们要制作 Node.js 所写的应用的镜像。我们都知道 Node.js 使用 `npm` 进行包管理,所有依赖、配置、启动信息等会放到 `package.json` 文件里。在拿到程序代码后,需要先进行 `npm install` 才可以获得所有需要的依赖。然后就可以通过 `npm start` 来启动应用。因此,一般来说会这样写 `Dockerfile`: 10 | 11 | ```docker 12 | FROM node:slim 13 | RUN mkdir /app 14 | WORKDIR /app 15 | COPY ./package.json /app 16 | RUN [ "npm", "install" ] 17 | COPY . /app/ 18 | CMD [ "npm", "start" ] 19 | ``` 20 | 21 | 把这个 `Dockerfile` 放到 Node.js 项目的根目录,构建好镜像后,就可以直接拿来启动容器运行。但是如果我们还有第二个 Node.js 项目也差不多呢?好吧,那就再把这个 `Dockerfile` 复制到第二个项目里。那如果有第三个项目呢?再复制么?文件的副本越多,版本控制就越困难,让我们继续看这样的场景维护的问题。 22 | 23 | 如果第一个 Node.js 项目在开发过程中,发现这个 `Dockerfile` 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 `Dockerfile`,再次构建,问题解决。第一个项目没问题了,但是第二个项目呢?虽然最初 `Dockerfile` 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 `Dockerfile`,而第二个项目的 `Dockerfile` 就会被自动修复。 24 | 25 | 那么我们可不可以做一个基础镜像,然后各个项目使用这个基础镜像呢?这样基础镜像更新,各个项目不用同步 `Dockerfile` 的变化,重新构建后就继承了基础镜像的更新?好吧,可以,让我们看看这样的结果。那么上面的这个 `Dockerfile` 就会变为: 26 | 27 | ```docker 28 | FROM node:slim 29 | RUN mkdir /app 30 | WORKDIR /app 31 | CMD [ "npm", "start" ] 32 | ``` 33 | 34 | 这里我们把项目相关的构建指令拿出来,放到子项目里去。假设这个基础镜像的名字为 `my-node` 的话,各个项目内的自己的 `Dockerfile` 就变为: 35 | 36 | ```docker 37 | FROM my-node 38 | COPY ./package.json /app 39 | RUN [ "npm", "install" ] 40 | COPY . /app/ 41 | ``` 42 | 43 | 基础镜像变化后,各个项目都用这个 `Dockerfile` 重新构建镜像,会继承基础镜像的更新。 44 | 45 | 那么,问题解决了么?没有。准确说,只解决了一半。如果这个 `Dockerfile` 里面有些东西需要调整呢?比如 `npm install` 都需要加一些参数,那怎么办?这一行 `RUN` 是不可能放入基础镜像的,因为涉及到了当前项目的 `./package.json`,难道又要一个个修改么?所以说,这样制作基础镜像,只解决了原来的 `Dockerfile` 的前4条指令的变化问题,而后面三条指令的变化则完全没办法处理。 46 | 47 | `ONBUILD` 可以解决这个问题。让我们用 `ONBUILD` 重新写一下基础镜像的 `Dockerfile`: 48 | 49 | ```docker 50 | FROM node:slim 51 | RUN mkdir /app 52 | WORKDIR /app 53 | ONBUILD COPY ./package.json /app 54 | ONBUILD RUN [ "npm", "install" ] 55 | ONBUILD COPY . /app/ 56 | CMD [ "npm", "start" ] 57 | ``` 58 | 59 | 这次我们回到原始的 `Dockerfile`,但是这次将项目相关的指令加上 `ONBUILD`,这样在构建基础镜像的时候,这三行并不会被执行。然后各个项目的 `Dockerfile` 就变成了简单地: 60 | 61 | ```docker 62 | FROM my-node 63 | ``` 64 | 65 | 是的,只有这么一行。当在各个项目目录中,用这个只有一行的 `Dockerfile` 构建镜像时,之前基础镜像的那三行 `ONBUILD` 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 `npm install`,生成应用镜像。 66 | -------------------------------------------------------------------------------- /image/dockerfile/references.md: -------------------------------------------------------------------------------- 1 | # 参考文档 2 | 3 | * `Dockerfie` 官方文档:https://docs.docker.com/engine/reference/builder/ 4 | 5 | * `Dockerfile` 最佳实践文档:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ 6 | 7 | * `Docker` 官方镜像 `Dockerfile`:https://github.com/docker-library/docs 8 | -------------------------------------------------------------------------------- /image/dockerfile/shell.md: -------------------------------------------------------------------------------- 1 | # SHELL 指令 2 | 3 | 格式:`SHELL ["executable", "parameters"]` 4 | 5 | `SHELL` 指令可以指定 `RUN` `ENTRYPOINT` `CMD` 指令的 shell,Linux 中默认为 `["/bin/sh", "-c"]` 6 | 7 | ```docker 8 | SHELL ["/bin/sh", "-c"] 9 | 10 | RUN lll ; ls 11 | 12 | SHELL ["/bin/sh", "-cex"] 13 | 14 | RUN lll ; ls 15 | ``` 16 | 17 | 两个 `RUN` 运行同一命令,第二个 `RUN` 运行的命令会打印出每条命令并当遇到错误时退出。 18 | 19 | 当 `ENTRYPOINT` `CMD` 以 shell 格式指定时,`SHELL` 指令所指定的 shell 也会成为这两个指令的 shell 20 | 21 | ```docker 22 | SHELL ["/bin/sh", "-cex"] 23 | 24 | # /bin/sh -cex "nginx" 25 | ENTRYPOINT nginx 26 | ``` 27 | 28 | ```docker 29 | SHELL ["/bin/sh", "-cex"] 30 | 31 | # /bin/sh -cex "nginx" 32 | CMD nginx 33 | ``` 34 | -------------------------------------------------------------------------------- /image/dockerfile/user.md: -------------------------------------------------------------------------------- 1 | # USER 指定当前用户 2 | 3 | 格式:`USER <用户名>[:<用户组>]` 4 | 5 | `USER` 指令和 `WORKDIR` 相似,都是改变环境状态并影响以后的层。`WORKDIR` 是改变工作目录,`USER` 则是改变之后层的执行 `RUN`, `CMD` 以及 `ENTRYPOINT` 这类命令的身份。 6 | 7 | 注意,`USER` 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。 8 | 9 | ```docker 10 | RUN groupadd -r redis && useradd -r -g redis redis 11 | USER redis 12 | RUN [ "redis-server" ] 13 | ``` 14 | 15 | 如果以 `root` 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 `su` 或者 `sudo`,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 [`gosu`](https://github.com/tianon/gosu)。 16 | 17 | ```docker 18 | # 建立 redis 用户,并使用 gosu 换另一个用户执行命令 19 | RUN groupadd -r redis && useradd -r -g redis redis 20 | # 下载 gosu 21 | RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.12/gosu-amd64" \ 22 | && chmod +x /usr/local/bin/gosu \ 23 | && gosu nobody true 24 | # 设置 CMD,并以另外的用户执行 25 | CMD [ "exec", "gosu", "redis", "redis-server" ] 26 | ``` 27 | -------------------------------------------------------------------------------- /image/dockerfile/volume.md: -------------------------------------------------------------------------------- 1 | # VOLUME 定义匿名卷 2 | 3 | 格式为: 4 | 5 | * `VOLUME ["<路径1>", "<路径2>"...]` 6 | * `VOLUME <路径>` 7 | 8 | 之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 `Dockerfile` 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。 9 | 10 | ```docker 11 | VOLUME /data 12 | ``` 13 | 14 | 这里的 `/data` 目录就会在容器运行时自动挂载为匿名卷,任何向 `/data` 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行容器时可以覆盖这个挂载设置。比如: 15 | 16 | ```bash 17 | $ docker run -d -v mydata:/data xxxx 18 | ``` 19 | 20 | 在这行命令中,就使用了 `mydata` 这个命名卷挂载到了 `/data` 这个位置,替代了 `Dockerfile` 中定义的匿名卷的挂载配置。 21 | -------------------------------------------------------------------------------- /image/dockerfile/workdir.md: -------------------------------------------------------------------------------- 1 | # WORKDIR 指定工作目录 2 | 3 | 格式为 `WORKDIR <工作目录路径>`。 4 | 5 | 使用 `WORKDIR` 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,`WORKDIR` 会帮你建立目录。 6 | 7 | 之前提到一些初学者常犯的错误是把 `Dockerfile` 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误: 8 | 9 | ```docker 10 | RUN cd /app 11 | RUN echo "hello" > world.txt 12 | ``` 13 | 14 | 如果将这个 `Dockerfile` 进行构建镜像运行后,会发现找不到 `/app/world.txt` 文件,或者其内容不是 `hello`。原因其实很简单,在 Shell 中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 `Dockerfile` 中,这两行 `RUN` 命令的执行环境根本不同,是两个完全不同的容器。这就是对 `Dockerfile` 构建分层存储的概念不了解所导致的错误。 15 | 16 | 之前说过每一个 `RUN` 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 `RUN cd /app` 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。 17 | 18 | 因此如果需要改变以后各层的工作目录的位置,那么应该使用 `WORKDIR` 指令。 19 | 20 | ```docker 21 | WORKDIR /app 22 | 23 | RUN echo "hello" > world.txt 24 | ``` 25 | 26 | 如果你的 `WORKDIR` 指令使用的相对路径,那么所切换的路径与之前的 `WORKDIR` 有关: 27 | 28 | ```docker 29 | WORKDIR /a 30 | WORKDIR b 31 | WORKDIR c 32 | 33 | RUN pwd 34 | ``` 35 | 36 | `RUN pwd` 的工作目录为 `/a/b/c`。 37 | -------------------------------------------------------------------------------- /image/internal.md: -------------------------------------------------------------------------------- 1 | # 镜像的实现原理 2 | 3 | Docker 镜像是怎么实现增量的修改和维护的? 4 | 5 | 每个镜像都由很多层次构成,Docker 使用 [Union FS](https://en.wikipedia.org/wiki/UnionFS) 将这些不同的层结合到一个镜像中去。 6 | 7 | 通常 Union FS 有两个用途, 一方面可以实现不借助 LVM、RAID 将多个 disk 挂到同一个目录下,另一个更常用的就是将一个只读的分支和一个可写的分支联合在一起,Live CD 正是基于此方法可以允许在镜像不变的基础上允许用户在其上进行一些写操作。 8 | 9 | Docker 在 OverlayFS 上构建的容器也是利用了类似的原理。 10 | -------------------------------------------------------------------------------- /image/multistage-builds/example/laravel/.dockerignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .git/ 3 | 4 | vendor/ 5 | 6 | node_modules/ 7 | 8 | public/js/ 9 | public/css/ 10 | public/mix-manifest.json 11 | 12 | yarn-error.log 13 | 14 | bootstrap/cache/* 15 | storage/ 16 | 17 | # 自行添加其他需要排除的文件,例如 .env.* 文件 18 | -------------------------------------------------------------------------------- /image/multistage-builds/example/laravel/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine as frontend 2 | 3 | COPY package.json /app/ 4 | 5 | RUN set -x ; cd /app \ 6 | && npm install --registry=https://registry.npm.taobao.org 7 | 8 | COPY webpack.mix.js webpack.config.js tailwind.config.js /app/ 9 | COPY resources/ /app/resources/ 10 | 11 | RUN set -x ; cd /app \ 12 | && touch artisan \ 13 | && mkdir -p public \ 14 | && npm run production 15 | 16 | FROM composer as composer 17 | 18 | COPY database/ /app/database/ 19 | COPY composer.json /app/ 20 | 21 | RUN set -x ; cd /app \ 22 | && composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ \ 23 | && composer install \ 24 | --ignore-platform-reqs \ 25 | --no-interaction \ 26 | --no-plugins \ 27 | --no-scripts \ 28 | --prefer-dist 29 | 30 | FROM php:7.4-fpm-alpine as laravel 31 | 32 | ARG LARAVEL_PATH=/app/laravel 33 | 34 | COPY --from=composer /app/vendor/ ${LARAVEL_PATH}/vendor/ 35 | COPY . ${LARAVEL_PATH} 36 | COPY --from=frontend /app/public/js/ ${LARAVEL_PATH}/public/js/ 37 | COPY --from=frontend /app/public/css/ ${LARAVEL_PATH}/public/css/ 38 | COPY --from=frontend /app/public/mix-manifest.json ${LARAVEL_PATH}/public/mix-manifest.json 39 | 40 | RUN set -x ; cd ${LARAVEL_PATH} \ 41 | && mkdir -p storage \ 42 | && mkdir -p storage/framework/cache \ 43 | && mkdir -p storage/framework/sessions \ 44 | && mkdir -p storage/framework/testing \ 45 | && mkdir -p storage/framework/views \ 46 | && mkdir -p storage/logs \ 47 | && chmod -R 777 storage \ 48 | && php artisan package:discover 49 | 50 | FROM nginx:alpine as nginx 51 | 52 | ARG LARAVEL_PATH=/app/laravel 53 | 54 | COPY laravel.conf /etc/nginx/conf.d/ 55 | COPY --from=laravel ${LARAVEL_PATH}/public ${LARAVEL_PATH}/public 56 | -------------------------------------------------------------------------------- /image/multistage-builds/example/laravel/laravel.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | root /app/laravel/public; 4 | index index.php index.html; 5 | 6 | location / { 7 | try_files $uri $uri/ /index.php?$query_string; 8 | } 9 | 10 | location ~ .*\.php(\/.*)*$ { 11 | fastcgi_pass laravel:9000; 12 | include fastcgi.conf; 13 | 14 | # fastcgi_connect_timeout 300; 15 | # fastcgi_send_timeout 300; 16 | # fastcgi_read_timeout 300; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /image/other.md: -------------------------------------------------------------------------------- 1 | # 其它制作镜像的方式 2 | 3 | 除了标准的使用 `Dockerfile` 生成镜像的方法外,由于各种特殊需求和历史原因,还提供了一些其它方法用以生成镜像。 4 | 5 | ## 从 rootfs 压缩包导入 6 | 7 | 格式:`docker import [选项] <文件>||- [<仓库名>[:<标签>]]` 8 | 9 | 压缩包可以是本地文件、远程 Web 文件,甚至是从标准输入中得到。压缩包将会在镜像 `/` 目录展开,并直接作为镜像第一层提交。 10 | 11 | 比如我们想要创建一个 [OpenVZ](https://openvz.org) 的 Ubuntu 16.04 [模板](https://wiki.openvz.org/Download/template/precreated)的镜像: 12 | 13 | ```bash 14 | $ docker import \ 15 | http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz \ 16 | openvz/ubuntu:16.04 17 | 18 | Downloading from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz 19 | sha256:412b8fc3e3f786dca0197834a698932b9c51b69bd8cf49e100c35d38c9879213 20 | ``` 21 | 22 | 这条命令自动下载了 `ubuntu-16.04-x86_64.tar.gz` 文件,并且作为根文件系统展开导入,并保存为镜像 `openvz/ubuntu:16.04`。 23 | 24 | 导入成功后,我们可以用 `docker image ls` 看到这个导入的镜像: 25 | 26 | ```bash 27 | $ docker image ls openvz/ubuntu 28 | REPOSITORY TAG IMAGE ID CREATED SIZE 29 | openvz/ubuntu 16.04 412b8fc3e3f7 55 seconds ago 505MB 30 | ``` 31 | 32 | 如果我们查看其历史的话,会看到描述中有导入的文件链接: 33 | 34 | ```bash 35 | $ docker history openvz/ubuntu:16.04 36 | IMAGE CREATED CREATED BY SIZE COMMENT 37 | f477a6e18e98 About a minute ago 214.9 MB Imported from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz 38 | ``` 39 | 40 | ## Docker 镜像的导入和导出 `docker save` 和 `docker load` 41 | 42 | Docker 还提供了 `docker save` 和 `docker load` 命令,用以将镜像保存为一个文件,然后传输到另一个位置上,再加载进来。这是在没有 Docker Registry 时的做法,现在已经不推荐,镜像迁移应该直接使用 Docker Registry,无论是直接使用 Docker Hub 还是使用内网私有 Registry 都可以。 43 | 44 | ### 保存镜像 45 | 46 | 使用 `docker save` 命令可以将镜像保存为归档文件。 47 | 48 | 比如我们希望保存这个 `alpine` 镜像。 49 | 50 | ```bash 51 | $ docker image ls alpine 52 | REPOSITORY TAG IMAGE ID CREATED SIZE 53 | alpine latest baa5d63471ea 5 weeks ago 4.803 MB 54 | ``` 55 | 56 | 保存镜像的命令为: 57 | 58 | ```bash 59 | $ docker save alpine -o filename 60 | $ file filename 61 | filename: POSIX tar archive 62 | ``` 63 | 64 | 这里的 filename 可以为任意名称甚至任意后缀名,但文件的本质都是归档文件 65 | 66 | **注意:如果同名则会覆盖(没有警告)** 67 | 68 | 若使用 `gzip` 压缩: 69 | 70 | ```bash 71 | $ docker save alpine | gzip > alpine-latest.tar.gz 72 | ``` 73 | 74 | 然后我们将 `alpine-latest.tar.gz` 文件复制到了到了另一个机器上,可以用下面这个命令加载镜像: 75 | 76 | ```bash 77 | $ docker load -i alpine-latest.tar.gz 78 | Loaded image: alpine:latest 79 | ``` 80 | 81 | 如果我们结合这两个命令以及 `ssh` 甚至 `pv` 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能: 82 | 83 | ```bash 84 | docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load' 85 | ``` 86 | -------------------------------------------------------------------------------- /image/pull.md: -------------------------------------------------------------------------------- 1 | # 获取镜像 2 | 3 | 之前提到过,[Docker Hub](https://hub.docker.com/search?q=&type=image) 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。 4 | 5 | 从 Docker 镜像仓库获取镜像的命令是 `docker pull`。其命令格式为: 6 | 7 | ```bash 8 | $ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] 9 | ``` 10 | 11 | 具体的选项可以通过 `docker pull --help` 命令看到,这里我们说一下镜像名称的格式。 12 | 13 | * Docker 镜像仓库地址:地址的格式一般是 `<域名/IP>[:端口号]`。默认地址是 Docker Hub(`docker.io`)。 14 | * 仓库名:如之前所说,这里的仓库名是两段式名称,即 `<用户名>/<软件名>`。对于 Docker Hub,如果不给出用户名,则默认为 `library`,也就是官方镜像。 15 | 16 | 比如: 17 | 18 | ```bash 19 | $ docker pull ubuntu:18.04 20 | 18.04: Pulling from library/ubuntu 21 | 92dc2a97ff99: Pull complete 22 | be13a9d27eb8: Pull complete 23 | c8299583700a: Pull complete 24 | Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26 25 | Status: Downloaded newer image for ubuntu:18.04 26 | docker.io/library/ubuntu:18.04 27 | ``` 28 | 29 | 上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub (`docker.io`)获取镜像。而镜像名称是 `ubuntu:18.04`,因此将会获取官方镜像 `library/ubuntu` 仓库中标签为 `18.04` 的镜像。`docker pull` 命令的输出结果最后一行给出了镜像的完整名称,即: `docker.io/library/ubuntu:18.04`。 30 | 31 | 从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 `sha256` 的摘要,以确保下载一致性。 32 | 33 | 在使用上面命令的时候,你可能会发现,你所看到的层 ID 以及 `sha256` 的摘要和这里的不一样。这是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。 34 | 35 | *如果从 Docker Hub 下载镜像非常缓慢,可以参照 [镜像加速器](/install/mirror.md) 一节配置加速器。* 36 | 37 | ## 运行 38 | 39 | 有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 `ubuntu:18.04` 为例,如果我们打算启动里面的 `bash` 并且进行交互式操作的话,可以执行下面的命令。 40 | 41 | ```bash 42 | $ docker run -it --rm ubuntu:18.04 bash 43 | 44 | root@e7009c6ce357:/# cat /etc/os-release 45 | NAME="Ubuntu" 46 | VERSION="18.04.1 LTS (Bionic Beaver)" 47 | ID=ubuntu 48 | ID_LIKE=debian 49 | PRETTY_NAME="Ubuntu 18.04.1 LTS" 50 | VERSION_ID="18.04" 51 | HOME_URL="https://www.ubuntu.com/" 52 | SUPPORT_URL="https://help.ubuntu.com/" 53 | BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" 54 | PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" 55 | VERSION_CODENAME=bionic 56 | UBUNTU_CODENAME=bionic 57 | ``` 58 | 59 | `docker run` 就是运行容器的命令,具体格式我们会在 [容器](../container) 一节进行详细讲解,我们这里简要的说明一下上面用到的参数。 60 | 61 | * `-it`:这是两个参数,一个是 `-i`:交互式操作,一个是 `-t` 终端。我们这里打算进入 `bash` 执行一些命令并查看返回结果,因此我们需要交互式终端。 62 | * `--rm`:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 `docker rm`。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 `--rm` 可以避免浪费空间。 63 | * `ubuntu:18.04`:这是指用 `ubuntu:18.04` 镜像为基础来启动容器。 64 | * `bash`:放在镜像名后的是 **命令**,这里我们希望有个交互式 Shell,因此用的是 `bash`。 65 | 66 | 进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 `cat /etc/os-release`,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 `Ubuntu 18.04.1 LTS` 系统。 67 | 68 | 最后我们通过 `exit` 退出了这个容器。 69 | -------------------------------------------------------------------------------- /install/README.md: -------------------------------------------------------------------------------- 1 | # 安装 Docker 2 | 3 | Docker 分为 `stable` `test` 和 `nightly` 三个更新频道。 4 | 5 | 官方网站上有各种环境下的 [安装指南](https://docs.docker.com/get-docker/),这里主要介绍 Docker 在 `Linux` 、`Windows 10` 和 `macOS` 上的安装。 6 | -------------------------------------------------------------------------------- /install/_images/image-20200412202617411.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/image-20200412202617411.png -------------------------------------------------------------------------------- /install/_images/install-mac-apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-mac-apps.png -------------------------------------------------------------------------------- /install/_images/install-mac-dmg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-mac-dmg.png -------------------------------------------------------------------------------- /install/_images/install-mac-example-nginx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-mac-example-nginx.png -------------------------------------------------------------------------------- /install/_images/install-mac-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-mac-menu.png -------------------------------------------------------------------------------- /install/_images/install-mac-menubar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-mac-menubar.png -------------------------------------------------------------------------------- /install/_images/install-win-docker-app-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-win-docker-app-search.png -------------------------------------------------------------------------------- /install/_images/install-win-taskbar-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/install/_images/install-win-taskbar-circle.png -------------------------------------------------------------------------------- /install/experimental.md: -------------------------------------------------------------------------------- 1 | # 开启实验特性 2 | 3 | 一些 docker 命令或功能仅当 **实验特性** 开启时才能使用,请按照以下方法进行设置。 4 | 5 | ## Docker CLI 的实验特性 6 | 7 | 从 `v20.10` 版本开始,Docker CLI 所有实验特性的命令均默认开启,无需再进行配置或设置系统环境变量。 8 | 9 | ## 开启 dockerd 的实验特性 10 | 11 | 编辑 `/etc/docker/daemon.json`,新增如下条目 12 | 13 | ```json 14 | { 15 | "experimental": true 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /install/mac.md: -------------------------------------------------------------------------------- 1 | # macOS 安装 Docker 2 | 3 | ## 系统要求 4 | 5 | [Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/) 要求系统最低为 macOS Mojave 10.14。 6 | 7 | ## 安装 8 | 9 | ### 使用 Homebrew 安装 10 | 11 | [Homebrew](https://brew.sh/) 的 [Cask](https://github.com/Homebrew/homebrew-cask) 已经支持 Docker Desktop for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装: 12 | 13 | ```bash 14 | $ brew install --cask docker 15 | ``` 16 | 17 | ### 手动下载安装 18 | 19 | 如果需要手动下载,请点击以下 [链接](https://desktop.docker.com/mac/main/amd64/Docker.dmg) 下载 Docker Desktop for Mac。 20 | 21 | > 如果你的电脑搭载的是 M1 芯片(`arm64` 架构),请点击以下 [链接](https://desktop.docker.com/mac/main/arm64/Docker.dmg) 下载 Docker Desktop for Mac。你可以在 [官方文档](https://docs.docker.com/docker-for-mac/apple-silicon/) 查阅已知的问题。 22 | 23 | 如同 macOS 其它软件一样,安装也非常简单,双击下载的 `.dmg` 文件,然后将那只叫 [Moby](https://www.docker.com/blog/call-me-moby-dock/) 的鲸鱼图标拖拽到 `Application` 文件夹即可(其间需要输入用户密码)。 24 | 25 | ![](./_images/install-mac-dmg.png) 26 | 27 | ## 运行 28 | 29 | 从应用中找到 Docker 图标并点击运行。 30 | 31 | ![](./_images/install-mac-apps.png) 32 | 33 | 运行之后,会在右上角菜单栏看到多了一个鲸鱼图标,这个图标表明了 Docker 的运行状态。 34 | 35 | ![](./_images/install-mac-menubar.png) 36 | 37 | 每次点击鲸鱼图标会弹出操作菜单。 38 | 39 | ![](./_images/install-mac-menu.png) 40 | 41 | 之后,你可以在终端通过命令检查安装后的 Docker 版本。 42 | 43 | ```bash 44 | $ docker --version 45 | Docker version 20.10.0, build 7287ab3 46 | ``` 47 | 48 | 如果 `docker version`、`docker info` 都正常的话,可以尝试运行一个 [Nginx 服务器](https://hub.docker.com/_/nginx/): 49 | 50 | ```bash 51 | $ docker run -d -p 80:80 --name webserver nginx 52 | ``` 53 | 54 | 服务运行后,可以访问 ,如果看到了 "Welcome to nginx!",就说明 Docker Desktop for Mac 安装成功了。 55 | 56 | ![](./_images/install-mac-example-nginx.png) 57 | 58 | 要停止 Nginx 服务器并删除执行下面的命令: 59 | 60 | ```bash 61 | $ docker stop webserver 62 | $ docker rm webserver 63 | ``` 64 | 65 | ## 镜像加速 66 | 67 | 如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。 68 | 69 | ## 参考链接 70 | 71 | * [官方文档](https://docs.docker.com/docker-for-mac/install/) 72 | -------------------------------------------------------------------------------- /install/windows.md: -------------------------------------------------------------------------------- 1 | # Windows 10 安装 Docker 2 | 3 | ## 系统要求 4 | 5 | [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/install/) 支持 64 位版本的 Windows 10 Pro,且必须开启 Hyper-V(若版本为 v1903 及以上则无需开启 Hyper-V),或者 64 位版本的 Windows 10 Home v1903 及以上版本。 6 | 7 | ## 安装 8 | 9 | **手动下载安装** 10 | 11 | 点击以下 [链接](https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe) 下载 Docker Desktop for Windows。 12 | 13 | 下载好之后双击 `Docker Desktop Installer.exe` 开始安装。 14 | 15 | **使用 [winget](https://docs.microsoft.com/zh-cn/windows/package-manager/) 安装** 16 | 17 | ```powershell 18 | $ winget install Docker.DockerDesktop 19 | ``` 20 | 21 | ## 在 WSL2 运行 Docker 22 | 23 | 若你的 Windows 版本为 Windows 10 专业版或家庭版 v1903 及以上版本可以使用 WSL2 运行 Docker,具体请查看 [Docker Desktop WSL 2 backend](https://docs.docker.com/docker-for-windows/wsl/)。 24 | 25 | ## 运行 26 | 27 | 在 Windows 搜索栏输入 **Docker** 点击 **Docker Desktop** 开始运行。 28 | 29 | ![](./_images/install-win-docker-app-search.png) 30 | 31 | Docker 启动之后会在 Windows 任务栏出现鲸鱼图标。 32 | 33 | ![](./_images/install-win-taskbar-circle.png) 34 | 35 | 等待片刻,当鲸鱼图标静止时,说明 Docker 启动成功,之后你可以打开 PowerShell 使用 Docker。 36 | 37 | > 推荐使用 [Windows Terminal](https://docs.microsoft.com/zh-cn/windows/terminal/get-started) 在终端使用 Docker。 38 | 39 | ## 镜像加速 40 | 41 | 如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](mirror.md)。 42 | 43 | ## 参考链接 44 | 45 | * [官方文档](https://docs.docker.com/docker-for-windows/install/) 46 | * [WSL 2 Support is coming to Windows 10 Versions 1903 and 1909](https://devblogs.microsoft.com/commandline/wsl-2-support-is-coming-to-windows-10-versions-1903-and-1909/) 47 | -------------------------------------------------------------------------------- /introduction/README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 本章将带领你进入 **Docker** 的世界。 4 | 5 | 什么是 **Docker**? 6 | 7 | 用它会带来什么样的好处? 8 | 9 | 好吧,让我们带着问题开始这神奇之旅。 10 | -------------------------------------------------------------------------------- /introduction/_images/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/introduction/_images/docker.png -------------------------------------------------------------------------------- /introduction/_images/virtualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/introduction/_images/virtualization.png -------------------------------------------------------------------------------- /introduction/what.md: -------------------------------------------------------------------------------- 1 | # 什么是 Docker 2 | 3 | **Docker** 最初是 `dotCloud` 公司创始人 [Solomon Hykes](https://github.com/shykes) 在法国期间发起的一个公司内部项目,它是基于 `dotCloud` 公司多年云服务技术的一次革新,并于 [2013 年 3 月以 Apache 2.0 授权协议开源][docker-soft],主要项目代码在 [GitHub](https://github.com/moby/moby) 上进行维护。`Docker` 项目后来还加入了 Linux 基金会,并成立推动 [开放容器联盟(OCI)](https://opencontainers.org/)。 4 | 5 | **Docker** 自开源后受到广泛的关注和讨论,至今其 [GitHub 项目](https://github.com/moby/moby) 已经超过 5 万 7 千个星标和一万多个 `fork`。甚至由于 `Docker` 项目的火爆,在 `2013` 年底,[dotCloud 公司决定改名为 Docker](https://www.docker.com/blog/dotcloud-is-becoming-docker-inc/)。`Docker` 最初是在 `Ubuntu 12.04` 上开发实现的;`Red Hat` 则从 `RHEL 6.5` 开始对 `Docker` 进行支持;`Google` 也在其 `PaaS` 产品中广泛应用 `Docker`。 6 | 7 | **Docker** 使用 `Google` 公司推出的 [Go 语言](https://golang.google.cn/) 进行开发实现,基于 `Linux` 内核的 [cgroup](https://zh.wikipedia.org/wiki/Cgroups),[namespace](https://en.wikipedia.org/wiki/Linux_namespaces),以及 [OverlayFS](https://docs.docker.com/storage/storagedriver/overlayfs-driver/) 类的 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 等技术,对进程进行封装隔离,属于 [操作系统层面的虚拟化技术](https://en.wikipedia.org/wiki/Operating-system-level_virtualization)。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 [LXC](https://linuxcontainers.org/lxc/introduction/),从 `0.7` 版本以后开始去除 `LXC`,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer),从 `1.11` 版本开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。 8 | 9 | ![Docker 架构](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/media/docker-on-linux.png) 10 | 11 | > `runc` 是一个 Linux 命令行工具,用于根据 [OCI容器运行时规范](https://github.com/opencontainers/runtime-spec) 创建和运行容器。 12 | 13 | > `containerd` 是一个守护程序,它管理容器生命周期,提供了在一个节点上执行容器和管理镜像的最小功能集。 14 | 15 | **Docker** 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 `Docker` 技术比虚拟机技术更为轻便、快捷。 16 | 17 | 下面的图片比较了 **Docker** 和传统虚拟化方式的不同之处。传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。 18 | 19 | ![传统虚拟化](./_images/virtualization.png) 20 | 21 | ![Docker](./_images/docker.png) 22 | 23 | [docker-soft]:https://en.wikipedia.org/wiki/Docker_(software) 24 | -------------------------------------------------------------------------------- /introduction/why.md: -------------------------------------------------------------------------------- 1 | # 为什么要使用 Docker? 2 | 3 | 作为一种新兴的虚拟化方式,`Docker` 跟传统的虚拟化方式相比具有众多的优势。 4 | 5 | ## 更高效的利用系统资源 6 | 7 | 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,`Docker` 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 8 | 9 | ## 更快速的启动时间 10 | 11 | 传统的虚拟机技术启动应用服务往往需要数分钟,而 `Docker` 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。 12 | 13 | ## 一致的运行环境 14 | 15 | 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 `Docker` 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 *「这段代码在我机器上没问题啊」* 这类问题。 16 | 17 | ## 持续交付和部署 18 | 19 | 对开发和运维([DevOps](https://zh.wikipedia.org/wiki/DevOps))人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。 20 | 21 | 使用 `Docker` 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 [Dockerfile](../image/dockerfile/) 来进行镜像构建,并结合 [持续集成(Continuous Integration)](https://en.wikipedia.org/wiki/Continuous_integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 [持续部署(Continuous Delivery/Deployment)](https://en.wikipedia.org/wiki/Continuous_delivery) 系统进行自动部署。 22 | 23 | 而且使用 [`Dockerfile`](../image/build.md) 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。 24 | 25 | ## 更轻松的迁移 26 | 27 | 由于 `Docker` 确保了执行环境的一致性,使得应用的迁移更加容易。`Docker` 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。 28 | 29 | ## 更轻松的维护和扩展 30 | 31 | `Docker` 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,`Docker` 团队同各个开源项目团队一起维护了一大批高质量的 [官方镜像](https://hub.docker.com/search/?type=image&image_filter=official),既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。 32 | 33 | ## 对比传统虚拟机总结 34 | 35 | | 特性 | 容器 | 虚拟机 | 36 | | :-------- | :-------- | :---------- | 37 | | 启动 | 秒级 | 分钟级 | 38 | | 硬盘使用 | 一般为 `MB` | 一般为 `GB` | 39 | | 性能 | 接近原生 | 弱于 | 40 | | 系统支持量 | 单机支持上千个容器 | 一般几十个 | 41 | -------------------------------------------------------------------------------- /kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes 2 | 3 | `Kubernetes` 是 Google 团队发起并维护的基于 Docker 的开源容器集群管理系统,它不仅支持常见的云平台,而且支持内部数据中心。 4 | 5 | 建于 Docker 之上的 `Kubernetes` 可以构建一个容器的调度服务,其目的是让用户透过 `Kubernetes` 集群来进行云端容器集群的管理,而无需用户进行复杂的设置工作。系统会自动选取合适的工作节点来执行具体的容器集群调度处理工作。其核心概念是 `Container Pod`。一个 `Pod` 由一组工作于同一物理工作节点的容器构成。这些组容器拥有相同的网络命名空间、IP以及存储配额,也可以根据实际情况对每一个 `Pod` 进行端口映射。此外,`Kubernetes` 工作节点会由主系统进行管理,节点包含了能够运行 Docker 容器所用到的服务。 6 | 7 | 本章将分为 5 节介绍 `Kubernetes`,包括 8 | 9 | * 项目简介 10 | * 快速入门 11 | * 基本概念 12 | * 实践例子 13 | * 架构分析等高级话题 14 | -------------------------------------------------------------------------------- /kubernetes/_images/k8s-singlenode-docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/_images/k8s-singlenode-docker.png -------------------------------------------------------------------------------- /kubernetes/_images/k8s_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/_images/k8s_architecture.png -------------------------------------------------------------------------------- /kubernetes/_images/kube-proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/_images/kube-proxy.png -------------------------------------------------------------------------------- /kubernetes/_images/kubernetes_design.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/_images/kubernetes_design.jpg -------------------------------------------------------------------------------- /kubernetes/_images/kubernetes_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/_images/kubernetes_logo.png -------------------------------------------------------------------------------- /kubernetes/advanced.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/advanced.md -------------------------------------------------------------------------------- /kubernetes/design.md: -------------------------------------------------------------------------------- 1 | # 基本架构 2 | 3 | 任何优秀的项目都离不开优秀的架构设计。本小节将介绍 Kubernetes 在架构方面的设计考虑。 4 | 5 | ## 基本考虑 6 | 如果让我们自己从头设计一套容器管理平台,有如下几个方面是很容易想到的: 7 | * 分布式架构,保证扩展性; 8 | * 逻辑集中式的控制平面 + 物理分布式的运行平面; 9 | * 一套资源调度系统,管理哪个容器该分配到哪个节点上; 10 | * 一套对容器内服务进行抽象和 HA 的系统。 11 | 12 | ## 运行原理 13 | 14 | 下面这张图完整展示了 Kubernetes 的运行原理。 15 | 16 | ![Kubernetes 架构](./_images/k8s_architecture.png) 17 | 18 | 可见,Kubernetes 首先是一套分布式系统,由多个节点组成,节点分为两类:一类是属于管理平面的主节点/控制节点(Master Node);一类是属于运行平面的工作节点(Worker Node)。 19 | 20 | 显然,复杂的工作肯定都交给控制节点去做了,工作节点负责提供稳定的操作接口和能力抽象即可。 21 | 22 | 从这张图上,我们没有能发现 Kubernetes 中对于控制平面的分布式实现,但是由于数据后端自身就是一套分布式的数据库 Etcd,因此可以很容易扩展到分布式实现。 23 | 24 | ## 控制平面 25 | ### 主节点服务 26 | 27 | 主节点上需要提供如下的管理服务: 28 | 29 | * `apiserver` 是整个系统的对外接口,提供一套 RESTful 的 [Kubernetes API](https://kubernetes.io/zh/docs/concepts/overview/kubernetes-api/),供客户端和其它组件调用; 30 | * `scheduler` 负责对资源进行调度,分配某个 pod 到某个节点上。是 pluggable 的,意味着很容易选择其它实现方式; 31 | * `controller-manager` 负责管理控制器,包括 endpoint-controller(刷新服务和 pod 的关联信息)和 replication-controller(维护某个 pod 的复制为配置的数值)。 32 | 33 | ### Etcd 34 | 这里 Etcd 即作为数据后端,又作为消息中间件。 35 | 36 | 通过 Etcd 来存储所有的主节点上的状态信息,很容易实现主节点的分布式扩展。 37 | 38 | 组件可以自动的去侦测 Etcd 中的数值变化来获得通知,并且获得更新后的数据来执行相应的操作。 39 | 40 | ## 工作节点 41 | * kubelet 是工作节点执行操作的 agent,负责具体的容器生命周期管理,根据从数据库中获取的信息来管理容器,并上报 pod 运行状态等; 42 | * kube-proxy 是一个简单的网络访问代理,同时也是一个 Load Balancer。它负责将访问到某个服务的请求具体分配给工作节点上的 Pod(同一类标签)。 43 | 44 | ![Proxy 代理对服务的请求](./_images/kube-proxy.png) 45 | -------------------------------------------------------------------------------- /kubernetes/intro.md: -------------------------------------------------------------------------------- 1 | # 项目简介 2 | 3 | ![](./_images/kubernetes_logo.png) 4 | 5 | Kubernetes 是 Google 团队发起的开源项目,它的目标是管理跨多个主机的容器,提供基本的部署,维护以及应用伸缩,主要实现语言为 Go 语言。Kubernetes 是: 6 | 7 | * 易学:轻量级,简单,容易理解 8 | * 便携:支持公有云,私有云,混合云,以及多种云平台 9 | * 可拓展:模块化,可插拔,支持钩子,可任意组合 10 | * 自修复:自动重调度,自动重启,自动复制 11 | 12 | Kubernetes 构建于 Google 数十年经验,一大半来源于 Google 生产环境规模的经验。结合了社区最佳的想法和实践。 13 | 14 | 在分布式系统中,部署,调度,伸缩一直是最为重要的也最为基础的功能。Kubernetes 就是希望解决这一序列问题的。 15 | 16 | Kubernetes 目前在[GitHub](https://github.com/kubernetes/kubernetes)进行维护。 17 | 18 | ### Kubernetes 能够运行在任何地方! 19 | 20 | 虽然 Kubernetes 最初是为 GCE 定制的,但是在后续版本中陆续增加了其他云平台的支持,以及本地数据中心的支持。 21 | -------------------------------------------------------------------------------- /kubernetes/kubectl/README.md: -------------------------------------------------------------------------------- 1 | # kubectl 使用 2 | 3 | [kubectl](https://github.com/kubernetes/kubernetes) 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes。 4 | 5 | 使用格式有两种: 6 | ```bash 7 | kubectl [flags] 8 | kubectl [command] 9 | ``` 10 | 11 | ## get 12 | 13 | 显示一个或多个资源 14 | 15 | ## describe 16 | 17 | 显示资源详情 18 | 19 | ## create 20 | 21 | 从文件或标准输入创建资源 22 | 23 | ## update 24 | 25 | 从文件或标准输入更新资源 26 | 27 | ## delete 28 | 29 | 通过文件名、标准输入、资源名或者 label selector 删除资源 30 | 31 | ## log 32 | 33 | 输出 pod 中一个容器的日志 34 | 35 | ## rolling-update 36 | 37 | 对指定的 replication controller 执行滚动升级 38 | 39 | ## exec 40 | 41 | 在容器内部执行命令 42 | 43 | ## port-forward 44 | 45 | 将本地端口转发到Pod 46 | 47 | ## proxy 48 | 49 | 为 Kubernetes API server 启动代理服务器 50 | 51 | ## run 52 | 53 | 在集群中使用指定镜像启动容器 54 | 55 | ## expose 56 | 57 | 将 replication controller service 或 pod 暴露为新的 kubernetes service 58 | 59 | ## label 60 | 61 | 更新资源的 label 62 | 63 | ## config 64 | 65 | 修改 kubernetes 配置文件 66 | 67 | ## cluster-info 68 | 69 | 显示集群信息 70 | 71 | ## api-versions 72 | 73 | 以 "组/版本" 的格式输出服务端支持的 API 版本 74 | 75 | ## version 76 | 77 | 输出服务端和客户端的版本信息 78 | 79 | ## help 80 | 81 | 显示各个命令的帮助信息 82 | -------------------------------------------------------------------------------- /kubernetes/practice.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/practice.md -------------------------------------------------------------------------------- /kubernetes/setup/README.md: -------------------------------------------------------------------------------- 1 | # 部署 Kubernetes 2 | 3 | 目前,Kubernetes 支持在多种环境下使用,包括本地主机(Ubuntu、Debian、CentOS、Fedora 等)、云服务([腾讯云](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61)、[阿里云](https://www.aliyun.com/product/kubernetes?source=5176.11533457&userCode=8lx5zmtu&type=copy)、[百度云](https://cloud.baidu.com/product/cce.html) 等)。 4 | 5 | 你可以使用以下几种方式部署 Kubernetes: 6 | 7 | * kubeadm 8 | * docker-desktop 9 | * k3s 10 | 11 | 接下来的小节会对以上几种方式进行详细介绍。 12 | -------------------------------------------------------------------------------- /kubernetes/setup/dashboard.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Dashboard 2 | 3 | [Kubernetes Dashboard](https://github.com/kubernetes/dashboard) 是基于网页的 Kubernetes 用户界面。 4 | 5 | ![](https://d33wubrfki0l68.cloudfront.net/349824f68836152722dab89465835e604719caea/6e0b7/images/docs/ui-dashboard.png) 6 | 7 | ## 部署 8 | 9 | 执行以下命令即可部署 Dashboard: 10 | 11 | ```bash 12 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml 13 | ``` 14 | 15 | ## 访问 16 | 17 | 通过命令行代理访问,执行以下命令: 18 | 19 | ```bash 20 | $ kubectl proxy 21 | ``` 22 | 23 | 到 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 即可访问。 24 | 25 | ## 登录 26 | 27 | 目前,Dashboard 仅支持使用 Bearer 令牌登录。下面教大家如何创建该令牌: 28 | 29 | ```bash 30 | $ kubectl create sa dashboard-admin -n kube-system 31 | 32 | $ kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin 33 | 34 | $ ADMIN_SECRET=$(kubectl get secrets -n kube-system | grep dashboard-admin | awk '{print $1}') 35 | 36 | $ DASHBOARD_LOGIN_TOKEN=$(kubectl describe secret -n kube-system ${ADMIN_SECRET} | grep -E '^token' | awk '{print $2}') 37 | 38 | echo ${DASHBOARD_LOGIN_TOKEN} 39 | ``` 40 | 41 | 将结果粘贴到登录页面,即可登录。 42 | 43 | ## 参考文档 44 | 45 | * [官方文档](https://kubernetes.io/zh/docs/tasks/access-application-cluster/web-ui-dashboard/) 46 | -------------------------------------------------------------------------------- /kubernetes/setup/docker-desktop.md: -------------------------------------------------------------------------------- 1 | # Docker Desktop 启用 Kubernetes 2 | 3 | 使用 Docker Desktop 可以很方便的启用 Kubernetes,由于国内获取不到 `k8s.gcr.io` 镜像,我们必须首先解决这一问题。 4 | 5 | ## 获取 `k8s.gcr.io` 镜像 6 | 7 | 由于国内拉取不到 `k8s.gcr.io` 镜像,我们可以使用开源项目 [AliyunContainerService/k8s-for-docker-desktop](https://github.com/AliyunContainerService/k8s-for-docker-desktop) 来获取所需的镜像。 8 | 9 | ## 启用 Kubernetes 10 | 11 | 在 Docker Desktop 设置页面,点击 `Kubernetes`,选择 `Enable Kubernetes`,稍等片刻,看到左下方 `Kubernetes` 变为 `running`,Kubernetes 启动成功。 12 | 13 | ![](https://github.com/AliyunContainerService/k8s-for-docker-desktop/raw/master/images/k8s.png) 14 | 15 | ## 测试 16 | 17 | ```bash 18 | $ kubectl version 19 | ``` 20 | 21 | 如果正常输出信息,则证明 Kubernetes 成功启动。 22 | -------------------------------------------------------------------------------- /kubernetes/setup/k3s.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/setup/k3s.md -------------------------------------------------------------------------------- /kubernetes/setup/kind.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/kubernetes/setup/kind.md -------------------------------------------------------------------------------- /kubernetes/setup/systemd.md: -------------------------------------------------------------------------------- 1 | # 一步步部署 kubernetes 集群 2 | 3 | 可以参考 [opsnull/follow-me-install-kubernetes-cluster](https://github.com/opsnull/follow-me-install-kubernetes-cluster) 项目一步步部署 kubernetes 集群。 4 | -------------------------------------------------------------------------------- /manifest: -------------------------------------------------------------------------------- 1 | DOCKER_VERSION=20.10.0 2 | DOCKER_COMPOSE_VERSION=1.27.4 3 | ETCD_VERSION=3.4.0 4 | KUBERNETES_VERSION=1.14.3 5 | KUBERNETES_DASHBOARD=2.0.0 6 | UBUNTU=18.04 7 | DEBIAN=9 8 | NGINX_VERSION=1.18.x 9 | NODE_VERSION=14.x 10 | PHP_VERSION=7.x 11 | REDIS_VERSION=6.x 12 | -------------------------------------------------------------------------------- /network/README.md: -------------------------------------------------------------------------------- 1 | # Docker 中的网络功能介绍 2 | 3 | Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。 4 | -------------------------------------------------------------------------------- /network/dns.md: -------------------------------------------------------------------------------- 1 | # 配置 DNS 2 | 3 | 如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。 4 | 5 | 在容器中使用 `mount` 命令可以看到挂载信息: 6 | 7 | ```bash 8 | $ mount 9 | /dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ... 10 | /dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ... 11 | tmpfs on /etc/resolv.conf type tmpfs ... 12 | ``` 13 | 14 | 这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 `/etc/resolv.conf` 文件立刻得到更新。 15 | 16 | 配置全部容器的 DNS ,也可以在 `/etc/docker/daemon.json` 文件中增加以下内容来设置。 17 | 18 | ```json 19 | { 20 | "dns" : [ 21 | "114.114.114.114", 22 | "8.8.8.8" 23 | ] 24 | } 25 | ``` 26 | 27 | 这样每次启动的容器 DNS 自动配置为 `114.114.114.114` 和 `8.8.8.8`。使用以下命令来证明其已经生效。 28 | 29 | ```bash 30 | $ docker run -it --rm ubuntu:18.04 cat etc/resolv.conf 31 | 32 | nameserver 114.114.114.114 33 | nameserver 8.8.8.8 34 | ``` 35 | 36 | 如果用户想要手动指定容器的配置,可以在使用 `docker run` 命令启动容器时加入如下参数: 37 | 38 | `-h HOSTNAME` 或者 `--hostname=HOSTNAME` 设定容器的主机名,它会被写到容器内的 `/etc/hostname` 和 `/etc/hosts`。但它在容器外部看不到,既不会在 `docker container ls` 中显示,也不会在其他的容器的 `/etc/hosts` 看到。 39 | 40 | `--dns=IP_ADDRESS` 添加 DNS 服务器到容器的 `/etc/resolv.conf` 中,让容器用这个服务器来解析所有不在 `/etc/hosts` 中的主机名。 41 | 42 | `--dns-search=DOMAIN` 设定容器的搜索域,当设定搜索域为 `.example.com` 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 `host.example.com`。 43 | 44 | >注意:如果在容器启动时没有指定最后两个参数,Docker 会默认用主机上的 `/etc/resolv.conf` 来配置容器。 45 | -------------------------------------------------------------------------------- /network/linking.md: -------------------------------------------------------------------------------- 1 | # 容器互联 2 | 3 | 如果你之前有 `Docker` 使用经验,你可能已经习惯了使用 `--link` 参数来使容器互联。 4 | 5 | 随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 `--link` 参数。 6 | 7 | ## 新建网络 8 | 9 | 下面先创建一个新的 Docker 网络。 10 | 11 | ```bash 12 | $ docker network create -d bridge my-net 13 | ``` 14 | 15 | `-d` 参数指定 Docker 网络类型,有 `bridge` `overlay`。其中 `overlay` 网络类型用于 [Swarm mode](../swarm_mode/),在本小节中你可以忽略它。 16 | 17 | ## 连接容器 18 | 19 | 运行一个容器并连接到新建的 `my-net` 网络 20 | 21 | ```bash 22 | $ docker run -it --rm --name busybox1 --network my-net busybox sh 23 | ``` 24 | 25 | 打开新的终端,再运行一个容器并加入到 `my-net` 网络 26 | 27 | ```bash 28 | $ docker run -it --rm --name busybox2 --network my-net busybox sh 29 | ``` 30 | 31 | 再打开一个新的终端查看容器信息 32 | 33 | ```bash 34 | $ docker container ls 35 | 36 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 37 | b47060aca56b busybox "sh" 11 minutes ago Up 11 minutes busybox2 38 | 8720575823ec busybox "sh" 16 minutes ago Up 16 minutes busybox1 39 | ``` 40 | 41 | 下面通过 `ping` 来证明 `busybox1` 容器和 `busybox2` 容器建立了互联关系。 42 | 43 | 在 `busybox1` 容器输入以下命令 44 | 45 | ```bash 46 | / # ping busybox2 47 | PING busybox2 (172.19.0.3): 56 data bytes 48 | 64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms 49 | 64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms 50 | ``` 51 | 52 | 用 ping 来测试连接 `busybox2` 容器,它会解析成 `172.19.0.3`。 53 | 54 | 同理在 `busybox2` 容器执行 `ping busybox1`,也会成功连接到。 55 | 56 | ```bash 57 | / # ping busybox1 58 | PING busybox1 (172.19.0.2): 56 data bytes 59 | 64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms 60 | 64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms 61 | ``` 62 | 63 | 这样,`busybox1` 容器和 `busybox2` 容器建立了互联关系。 64 | 65 | ## Docker Compose 66 | 67 | 如果你有多个容器之间需要互相连接,推荐使用 [Docker Compose](../compose)。 68 | -------------------------------------------------------------------------------- /network/port_mapping.md: -------------------------------------------------------------------------------- 1 | # 外部访问容器 2 | 3 | 容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 `-P` 或 `-p` 参数来指定端口映射。 4 | 5 | 当使用 `-P` 标记时,Docker 会随机映射一个端口到内部容器开放的网络端口。 6 | 7 | 使用 `docker container ls` 可以看到,本地主机的 32768 被映射到了容器的 80 端口。此时访问本机的 32768 端口即可访问容器内 NGINX 默认页面。 8 | 9 | ```bash 10 | $ docker run -d -P nginx:alpine 11 | 12 | $ docker container ls -l 13 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 14 | fae320d08268 nginx:alpine "/docker-entrypoint.…" 24 seconds ago Up 20 seconds 0.0.0.0:32768->80/tcp bold_mcnulty 15 | ``` 16 | 17 | 同样的,可以通过 `docker logs` 命令来查看访问记录。 18 | 19 | ```bash 20 | $ docker logs fa 21 | 172.17.0.1 - - [25/Aug/2020:08:34:04 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-" 22 | ``` 23 | 24 | `-p` 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort`。 25 | 26 | ## 映射所有接口地址 27 | 28 | 使用 `hostPort:containerPort` 格式本地的 80 端口映射到容器的 80 端口,可以执行 29 | 30 | ```bash 31 | $ docker run -d -p 80:80 nginx:alpine 32 | ``` 33 | 34 | 此时默认会绑定本地所有接口上的所有地址。 35 | 36 | ## 映射到指定地址的指定端口 37 | 38 | 可以使用 `ip:hostPort:containerPort` 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1 39 | 40 | ```bash 41 | $ docker run -d -p 127.0.0.1:80:80 nginx:alpine 42 | ``` 43 | 44 | ## 映射到指定地址的任意端口 45 | 46 | 使用 `ip::containerPort` 绑定 localhost 的任意端口到容器的 80 端口,本地主机会自动分配一个端口。 47 | 48 | ```bash 49 | $ docker run -d -p 127.0.0.1::80 nginx:alpine 50 | ``` 51 | 52 | 还可以使用 `udp` 标记来指定 `udp` 端口 53 | 54 | ```bash 55 | $ docker run -d -p 127.0.0.1:80:80/udp nginx:alpine 56 | ``` 57 | 58 | ## 查看映射端口配置 59 | 60 | 使用 `docker port` 来查看当前映射的端口配置,也可以查看到绑定的地址 61 | 62 | ```bash 63 | $ docker port fa 80 64 | 0.0.0.0:32768 65 | ``` 66 | 67 | 注意: 68 | * 容器有自己的内部网络和 ip 地址(使用 `docker inspect` 查看,Docker 还可以有一个可变的网络配置。) 69 | 70 | * `-p` 标记可以多次使用来绑定多个端口 71 | 72 | 例如 73 | 74 | ```bash 75 | $ docker run -d \ 76 | -p 80:80 \ 77 | -p 443:443 \ 78 | nginx:alpine 79 | ``` 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docker_practice", 3 | "version": "1.0.0", 4 | "description": "docker_practice", 5 | "main": "index.js", 6 | "devDependencies": { 7 | "chalk": "^4.1.1", 8 | "commander": "^7.2.0", 9 | "esm": "^3.0.0", 10 | "vuepress": "1.8.2", 11 | "vuepress-plugin-container": "^2.1.5", 12 | "vuepress-theme-hope": "^1.0.0" 13 | }, 14 | "scripts": { 15 | "test": "echo \"Error: no test specified\" && exit 1", 16 | "gitbook:help": "gitbook help", 17 | "gitbook:build": "gitbook build", 18 | "gitbook:serve": "gitbook serve", 19 | "vuepress:build": "npx vuepress build", 20 | "vuepress": "npx vuepress" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/yeasy/docker_practice.git" 25 | }, 26 | "author": "", 27 | "license": "ISC", 28 | "bugs": { 29 | "url": "https://github.com/yeasy/docker_practice/issues" 30 | }, 31 | "homepage": "https://github.com/yeasy/docker_practice#readme" 32 | } 33 | -------------------------------------------------------------------------------- /podman/README.md: -------------------------------------------------------------------------------- 1 | # podman 2 | 3 | [`podman`](https://github.com/containers/podman) 是一个无守护程序与 docker 命令兼容的下一代 Linux 容器工具。 4 | 5 | ## 安装 6 | 7 | ```bash 8 | $ sudo yum -y install podman 9 | ``` 10 | 11 | ## 使用 12 | 13 | `podman` 与 docker 命令完全兼容,只需将 `docker` 替换为 `podman` 即可,例如运行一个容器: 14 | 15 | ```bash 16 | # $ docker run -d -p 80:80 nginx:alpine 17 | 18 | $ podman run -d -p 80:80 nginx:alpine 19 | ``` 20 | 21 | ## 参考 22 | 23 | * https://developers.redhat.com/blog/2019/02/21/podman-and-buildah-for-docker-users/ 24 | -------------------------------------------------------------------------------- /repository/README.md: -------------------------------------------------------------------------------- 1 | # 访问仓库 2 | 3 | 仓库(`Repository`)是集中存放镜像的地方。 4 | 5 | 一个容易混淆的概念是注册服务器(`Registry`)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 `docker.io/ubuntu` 来说,`docker.io` 是注册服务器地址,`ubuntu` 是仓库名。 6 | 7 | 大部分时候,并不需要严格区分这两者的概念。 8 | -------------------------------------------------------------------------------- /repository/demo/auth/nginx.htpasswd: -------------------------------------------------------------------------------- 1 | username:$2y$05$TRWvCC6ilpKpY3ICifw32Ok3.8SpG3etq8O5WGdCm9wvyDhtSbRgy 2 | 3 | -------------------------------------------------------------------------------- /repository/demo/config.yml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | log: 3 | accesslog: 4 | disabled: true 5 | level: debug 6 | formatter: text 7 | fields: 8 | service: registry 9 | environment: staging 10 | storage: 11 | delete: 12 | enabled: true 13 | cache: 14 | blobdescriptor: inmemory 15 | filesystem: 16 | rootdirectory: /var/lib/registry 17 | auth: 18 | htpasswd: 19 | realm: basic-realm 20 | path: /etc/docker/registry/auth/nginx.htpasswd 21 | http: 22 | addr: :5000 23 | host: https://docker.domain.com 24 | headers: 25 | X-Content-Type-Options: [nosniff] 26 | http2: 27 | disabled: false 28 | tls: 29 | certificate: /etc/docker/registry/ssl/docker.domain.com.crt 30 | key: /etc/docker/registry/ssl/docker.domain.com.key 31 | health: 32 | storagedriver: 33 | enabled: true 34 | interval: 10s 35 | threshold: 3 36 | -------------------------------------------------------------------------------- /repository/demo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | registry: 5 | image: registry 6 | ports: 7 | - "443:5000" 8 | volumes: 9 | - ./:/etc/docker/registry 10 | - registry-data:/var/lib/registry 11 | 12 | volumes: 13 | registry-data: 14 | -------------------------------------------------------------------------------- /repository/demo/root-ca.cnf: -------------------------------------------------------------------------------- 1 | [root_ca] 2 | basicConstraints = critical,CA:TRUE,pathlen:1 3 | keyUsage = critical, nonRepudiation, cRLSign, keyCertSign 4 | subjectKeyIdentifier=hash 5 | -------------------------------------------------------------------------------- /repository/demo/site.cnf: -------------------------------------------------------------------------------- 1 | [server] 2 | authorityKeyIdentifier=keyid,issuer 3 | basicConstraints = critical,CA:FALSE 4 | extendedKeyUsage=serverAuth 5 | keyUsage = critical, digitalSignature, keyEncipherment 6 | subjectAltName = DNS:docker.domain.com, IP:127.0.0.1 7 | subjectKeyIdentifier=hash 8 | -------------------------------------------------------------------------------- /repository/demo/ssl/docker.domain.com.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIF/zCCA+egAwIBAgIJAMbgVbFo7I6IMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV 3 | BAYTAkNOMQ8wDQYDVQQIDAZTaGFueGkxDzANBgNVBAcMBkRhdG9uZzEaMBgGA1UE 4 | CgwRWW91ciBDb21wYW55IE5hbWUxLTArBgNVBAMMJFlvdXIgQ29tcGFueSBOYW1l 5 | IERvY2tlciBSZWdpc3RyeSBDQTAeFw0xNzEyMTExMTI2NTRaFw0xOTEyMzExMTI2 6 | NTRaMGcxCzAJBgNVBAYTAkNOMQ8wDQYDVQQIDAZTaGFueGkxDzANBgNVBAcMBkRh 7 | dG9uZzEaMBgGA1UECgwRWW91ciBDb21wYW55IE5hbWUxGjAYBgNVBAMMEWRvY2tl 8 | ci5kb21haW4uY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1Hbm 9 | 1tZvAeC8J54pQLHTVCtrICQ8KFTLOZakPHSWox8iQ4i2fkZaSccvE/51LIFnCM1y 10 | yZv88ILucqitG4zvuhDG+cU8w1vRbWf3xfGCCsHyn6LKBHR0Kk6+WRIBZTdRSsW8 11 | ZvpL2Y7eBNAUkC2oeaOJEOQ8D50b3u5jhAFmXuAcTiZh90Ve4JBKZV8dGs8L81vO 12 | vb7tqvJrEvCNKuZO7mEcjXkgiwUdP3pkZYa0tPOV5UrLH/oEvgPDJfXrNntCY1+A 13 | +CBQ7Sq3S2YpNJN7VnK6SboRi7xpOEgQOXwNVJWm/5YBvnbAztNXKcE2q2wREL9T 14 | ulUJCqo2h6NRaGYPfiLZIUHEJ7vQitRBRDpkxcX8XJX3Jm7weRPXLDOG8RN3FzPD 15 | TGL2ZDTWKDIQ20OhYEmENInKkpC2bYpwMzNvBA7AJN6MCYHXl4VP/Df0pPtMM/Di 16 | ZX+68ng3RQXT5VzDYURIH2wP5kcTL0irsNr+L7lHD+5mA1VErdQsh6AHWjrwMrSM 17 | egJpLP11rK4J+P/HHnqsBEi5XZI/hvRmwD7gwskRqXdDMHaWnoIIpPO3TeNYQUjD 18 | xaV5KUQuWVME5Ihuy03FPMChXXB0WF+tclPJxjQyDkwEVL+6d8i5yCPUBS2gBSBy 19 | pQQINFH4hOcx2e9Lujx7dOWfidjX3xssC9bEe60CAwEAAaOBmjCBlzAfBgNVHSME 20 | GDAWgBTS1B3CPFKA/HcI0cdE8YD4zG143DAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM 21 | MAoGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIFoDAiBgNVHREEGzAZghFkb2NrZXIu 22 | ZG9tYWluLmNvbYcEfwAAATAdBgNVHQ4EFgQUSanj6Cs4KVEKaK6/+VA/fNwNg4Ew 23 | DQYJKoZIhvcNAQELBQADggIBAKYtI1WKAL4FoSgH6sTZakw6h90uebrxm9ojeZTA 24 | k0ues8bGTu3w3dsphd9J0V27oz/dGjkwoIzy4QMYC4h6epKVadWfDhnHUPUT1JIC 25 | nGl7qFR539CSPzW+J1mVAGTZ1QONVxe6rFEDRXTsm9oUNq9LUB6a9EBO/9O0x2o7 26 | SZVUJd2WfMGAhqYjKCtMt+8kQgPxayok5IwWLBf03nluoF09Xu1WbY3f9wGNrzQp 27 | ulNlLzkU3f7+dVgF4lvIbr4MPWSQL2A0RYYjqWuwvUlXggtR+Nl6ldotDe7Ae18V 28 | KhQPJzM4muHjRY5dLkzQIIAQifxNprZCYiurUCAmOyOcHYMt5RuiVUPlB/2hoP/E 29 | tuFqq66v0qsE4mCfmJrRq+Yjfgcqsg1quRpjWh9DWOGa9HUeYFkLEKOgXybxVHJQ 30 | ktYba34ZFfBJUMcbZRYrRH6R4zu4LpRiyiXm29F5ml9tarThDZB5g5DJ6BTEt3Zw 31 | +qQHsIAcmHZvJPKEZmM6883gxbGQQ1Xt7iDrp94YRXMguBMbJwEsqI7w+25BHija 32 | Hp4gctdoBvkQBYpXoEsn8wnguofqJt/JhVgu0EQXR4j3U0uI+Oo9ODHFb5t2T26w 33 | EifwcLH+NyUNmUQH45lxaCzb+tqFlP7cbHsdPniaS4AtmBYwKNJMjcrgxnZPtfy1 34 | 7zJA 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /repository/demo/ssl/docker.domain.com.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKgIBAAKCAgEA1Hbm1tZvAeC8J54pQLHTVCtrICQ8KFTLOZakPHSWox8iQ4i2 3 | fkZaSccvE/51LIFnCM1yyZv88ILucqitG4zvuhDG+cU8w1vRbWf3xfGCCsHyn6LK 4 | BHR0Kk6+WRIBZTdRSsW8ZvpL2Y7eBNAUkC2oeaOJEOQ8D50b3u5jhAFmXuAcTiZh 5 | 90Ve4JBKZV8dGs8L81vOvb7tqvJrEvCNKuZO7mEcjXkgiwUdP3pkZYa0tPOV5UrL 6 | H/oEvgPDJfXrNntCY1+A+CBQ7Sq3S2YpNJN7VnK6SboRi7xpOEgQOXwNVJWm/5YB 7 | vnbAztNXKcE2q2wREL9TulUJCqo2h6NRaGYPfiLZIUHEJ7vQitRBRDpkxcX8XJX3 8 | Jm7weRPXLDOG8RN3FzPDTGL2ZDTWKDIQ20OhYEmENInKkpC2bYpwMzNvBA7AJN6M 9 | CYHXl4VP/Df0pPtMM/DiZX+68ng3RQXT5VzDYURIH2wP5kcTL0irsNr+L7lHD+5m 10 | A1VErdQsh6AHWjrwMrSMegJpLP11rK4J+P/HHnqsBEi5XZI/hvRmwD7gwskRqXdD 11 | MHaWnoIIpPO3TeNYQUjDxaV5KUQuWVME5Ihuy03FPMChXXB0WF+tclPJxjQyDkwE 12 | VL+6d8i5yCPUBS2gBSBypQQINFH4hOcx2e9Lujx7dOWfidjX3xssC9bEe60CAwEA 13 | AQKCAgEAqT/6zePOVFGhsXG17Rp7fY6E7PrQjVRW/A470QkTQui3U9MhhWAn5qPs 14 | peHLl+ORn5qCOYawrSuwJdim5c6U3cUlrKzppbqMD7qFz8J+1HECBRcaFQhrzZQi 15 | 4DOOtwGlGYqBdgsnxyyfQng8GUq17ghPVQxrqAiAvktrLSosUaH4Cm1bFy7E0OFA 16 | 0pY9SjDrlTZqcA8bp1Ur5M+JtUX4VL85jp2SRgyR6xJlzdbMN2Xf3+OAAn4ZrwCy 17 | QZgwgpsYHK9kvsSHkxa3IzJD2uUtmIUWT0sRVR6HN1V4z0I6IEqC2RG3W/Gf0GLd 18 | CZ8oHNCem5e+bC33YO6NN+nrHN5Isb+itdbtE392P6FgPbM1um1zuuTTewaUyXS7 19 | ATomznTpYXkHvCdvU5yOEH+yDYfcm99v77qVr0+arecVx2h0M2tqROwEza3Rw5Wp 20 | 928vyxPFde9HFHQG4SWRzCGfKpnvIT/ce2ayWHEDEbvzlwL9lokZqe0YYu5KDYTL 21 | j3DsnzMPiMn6bpQUIBXlO5+eAh94vatPCriNpEkHw3aYQNyux1BmyvKxflj6pg9u 22 | lxKWGng8YOW88ysXvXlAssjpDe+k/Cvaja3ZeV3pyRbMnK3ARHXi3mQ6wBsOVa6e 23 | zt3cpBgXik7m7u6a82FhLafP2UfFIpW6WRTA28ercpKtHRKJJgUCggEBAPWJsfPa 24 | 4movMI6ofySMFm74u779aO5rGMQumR52vwlWyNDmOWNRrQaU/tpyaFOiPeIOGt2V 25 | UM02rdWHbnAhsgYP0cjUs34aJV/Z4nunw5Jc6rrT+dhd3+ZgqM1X/sLt5JfEavHe 26 | bV/cDV+xDp4FAXrLOPeRldvLPT1dmdQnirPGK3A1WWi5GQ+//Kas+lHuqECWYRrU 27 | LVFx0tR/pmdCC5Lb58kuPOxFP4OaeC3PbGyA2y0gv+QR/5Nc0o1y/X6p6XIM5QxY 28 | fg4gDKwSewrZ40+9taRNtgMQz3xKkeYmaNgLKnCBnLhDYdLZPAeYkOUIytzJbaYg 29 | oWHzmdd5FIKCgzcCggEBAN2Ecd7lJRIISuQop5GQ44mRrsDZTxBWnZ9pn3VFWNfA 30 | tF5MHofrtED7mXBSAt88TryqndcyC6qMvaS4Ifk1cNSFdz9FLsNzxJj4wp5Cj+e1 31 | aSY5ARvXTXqTfKZErQNXFk1oCa+ARZIs5SPjh0LH+Iq2pd72cEap7pi3JT5RbOtE 32 | ReDCAKayyejFMKtekzccishIwH/nzYlNaNBkmG7MZG8V+FFlxYSieIa7Ohcbmmj3 33 | D3ssbi+y+peRt14wZB/daScybcIqdu544ZIvJOpm0i9rHxE49bodmTDhAZ9awqls 34 | nRsyI0NNDExPDhCrzPogcRLVHn2KbcZbjGPS5jossjsCggEAazYchaXlhwfj4+ae 35 | 3Y5tnTbug46S6sfIoKDYKv0enS1PsidUl5FqQ517Slb6RspoyvPttyMjjPd7H+lq 36 | x3tvCEaQC2kUltNDzn6M7gFq29XGiJ1WUqtqwGUkT8VEcEj/r2UMbV/50gl7rXTa 37 | NRVqd/uUfEUNclNkAg+Ew6YgYi79eJlS2O85ii8CWqTdCDl1Lf57mANdZlqU/ERg 38 | nGWyOAXdR3LxFxmFiilAoIAZj6cUDLhoEWXqeqXlKe4z0cLPNAV9Xc6l+/Tyk4/e 39 | Ofa50m+7iGqGNwB4GIVW/292CB+YAFgX3j1N0YsZMxfi7J7SNWWegxNsZCDB49vy 40 | oKnsMQKCAQEA0iurbnOyrF050SfRdQcnG4shZs/HeBT2EB3CsR1OocWwXBeUkBlO 41 | OKl+d1cYan1ppw+qGlbdQr+t3u7lLPFLUBghf+I/8CmSyiCbZlR4/LrePOmw551r 42 | YXU1uvtFu/mQq3ieV+k4GOyHq3lhCDd61QFedyESfbkVK8f4ihvvX3izZAAtZfwU 43 | HcmZ174vpwZploWQPsrL9A2B+Na42ccLM2qA45nPwXv1Jr/U6b/CzPw7r/4DvTXv 44 | FIeolrELDkCgWBQ8lxB7Lt96BZy9Rbiwi1TzcP++BQu4IOwbAfq23tCybu8vDde4 45 | Z15KVf7qyBansdqKx0njxWNu2/dpgKCPqQKCAQEAzWV4aajox7eeTi3iudP1Oxu3 46 | OBiu8xie4xq0mlM13tMxAQry/uOAuTxbaQ48mNsSXdeYeSgmT45lUvFWROqdVScK 47 | 8gh04G1NiRAkITzXwCCwKkAQxvQppgypZ+aksBHkFQFBAIg2/mLizS4cicXNEY4G 48 | vb+RImfn8MSqSMLu3cJ8zgFyqfRg6F0oHg9EgEwvbnCLYglN6Xm5KlZutjW4eu7m 49 | Q+1y0lg05e7vFyj2UIVylfzT/aoF/xzXzNt9/LZs0klO3vMmaVyTjuF/71+AyphH 50 | FTmpNs1wpZU2IRqKOMrimIhk6TTxvMSaN4pxKdLPqgHYLWhwkbsdmqtTnCljRg== 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /security/README.md: -------------------------------------------------------------------------------- 1 | # 安全 2 | 3 | 评估 Docker 的安全性时,主要考虑三个方面: 4 | 5 | * 由内核的命名空间和控制组机制提供的容器内在安全 6 | * Docker 程序(特别是服务端)本身的抗攻击性 7 | * 内核安全性的加强机制对容器安全性的影响 8 | -------------------------------------------------------------------------------- /security/control_group.md: -------------------------------------------------------------------------------- 1 | # 控制组 2 | 3 | 控制组是 Linux 容器机制的另外一个关键组件,负责实现资源的审计和限制。 4 | 5 | 它提供了很多有用的特性;以及确保各个容器可以公平地分享主机的内存、CPU、磁盘 IO 等资源;当然,更重要的是,控制组确保了当容器内的资源使用产生压力时不会连累主机系统。 6 | 7 | 尽管控制组不负责隔离容器之间相互访问、处理数据和进程,它在防止拒绝服务(DDOS)攻击方面是必不可少的。尤其是在多用户的平台(比如公有或私有的 PaaS)上,控制组十分重要。例如,当某些应用程序表现异常的时候,可以保证一致地正常运行和性能。 8 | 9 | 控制组机制始于 2006 年,内核从 2.6.24 版本开始被引入。 10 | -------------------------------------------------------------------------------- /security/daemon_sec.md: -------------------------------------------------------------------------------- 1 | # Docker服务端的防护 2 | 3 | 运行一个容器或应用程序的核心是通过 Docker 服务端。Docker 服务的运行目前需要 root 权限,因此其安全性十分关键。 4 | 5 | 首先,确保只有可信的用户才可以访问 Docker 服务。Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。例如,恶意用户启动容器的时候将主机的根目录`/`映射到容器的 `/host` 目录中,那么容器理论上就可以对主机的文件系统进行任意修改了。这听起来很疯狂?但是事实上几乎所有虚拟化系统都允许类似的资源共享,而没法禁止用户共享主机根文件系统到虚拟机系统。 6 | 7 | 这将会造成很严重的安全后果。因此,当提供容器创建服务时(例如通过一个 web 服务器),要更加注意进行参数的安全检查,防止恶意的用户用特定参数来创建一些破坏性的容器。 8 | 9 | 为了加强对服务端的保护,Docker 的 REST API(客户端用来跟服务端通信)在 0.5.2 之后使用本地的 Unix 套接字机制替代了原先绑定在 127.0.0.1 上的 TCP 套接字,因为后者容易遭受跨站脚本攻击。现在用户使用 Unix 权限检查来加强套接字的访问安全。 10 | 11 | 用户仍可以利用 HTTP 提供 REST API 访问。建议使用安全机制,确保只有可信的网络或 VPN,或证书保护机制(例如受保护的 stunnel 和 ssl 认证)下的访问可以进行。此外,还可以使用 [ HTTPS 和证书](https://docs.docker.com/engine/security/https/) 来加强保护。 12 | 13 | 最近改进的 Linux 命名空间机制将可以实现使用非 root 用户来运行全功能的容器。这将从根本上解决了容器和主机之间共享文件系统而引起的安全问题。 14 | 15 | 终极目标是改进 2 个重要的安全特性: 16 | * 将容器的 root 用户 [映射到本地主机上的非 root 用户](https://docs.docker.com/engine/security/userns-remap/),减轻容器和主机之间因权限提升而引起的安全问题; 17 | * 允许 Docker 服务端在 [非 root 权限(rootless 模式)](https://docs.docker.com/engine/security/rootless/) 下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程将只允许在限定范围内进行操作,例如仅仅负责虚拟网络设定或文件系统管理、配置操作等。 18 | 19 | 最后,建议采用专用的服务器来运行 Docker 和相关的管理服务(例如管理服务比如 ssh 监控和进程监控、管理工具 nrpe、collectd 等)。其它的业务服务都放到容器中去运行。 20 | -------------------------------------------------------------------------------- /security/kernel_capability.md: -------------------------------------------------------------------------------- 1 | # 内核能力机制 2 | 3 | [能力机制(Capability)](https://man7.org/linux/man-pages/man7/capabilities.7.html) 是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。 4 | Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。 5 | 6 | 例如,一个 Web 服务进程只需要绑定一个低于 1024 的端口的权限,并不需要 root 权限。那么它只需要被授权 `net_bind_service` 能力即可。此外,还有很多其他的类似能力来避免进程获取 root 权限。 7 | 8 | 默认情况下,Docker 启动的容器被严格限制只允许使用内核的一部分能力。 9 | 10 | 使用能力机制对加强 Docker 容器的安全有很多好处。通常,在服务器上会运行一堆需要特权权限的进程,包括有 ssh、cron、syslogd、硬件管理工具模块(例如负载模块)、网络配置工具等等。容器跟这些进程是不同的,因为几乎所有的特权进程都由容器以外的支持系统来进行管理。 11 | * ssh 访问被主机上ssh服务来管理; 12 | * cron 通常应该作为用户进程执行,权限交给使用它服务的应用来处理; 13 | * 日志系统可由 Docker 或第三方服务管理; 14 | * 硬件管理无关紧要,容器中也就无需执行 udevd 以及类似服务; 15 | * 网络管理也都在主机上设置,除非特殊需求,容器不需要对网络进行配置。 16 | 17 | 从上面的例子可以看出,大部分情况下,容器并不需要“真正的” root 权限,容器只需要少数的能力即可。为了加强安全,容器可以禁用一些没必要的权限。 18 | * 完全禁止任何 mount 操作; 19 | * 禁止直接访问本地主机的套接字; 20 | * 禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等; 21 | * 禁止模块加载。 22 | 23 | 这样,就算攻击者在容器中取得了 root 权限,也不能获得本地主机的较高权限,能进行的破坏也有限。 24 | 25 | 默认情况下,Docker采用 [白名单](https://github.com/moby/moby/blob/master/oci/caps/defaults.go) 机制,禁用必需功能之外的其它权限。 26 | 当然,用户也可以根据自身需求来为 Docker 容器启用额外的权限。 27 | -------------------------------------------------------------------------------- /security/kernel_ns.md: -------------------------------------------------------------------------------- 1 | # 内核命名空间 2 | 3 | Docker 容器和 LXC 容器很相似,所提供的安全特性也差不多。当用 `docker run` 启动一个容器时,在后台 Docker 为容器创建了一个独立的命名空间和控制组集合。 4 | 5 | 命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用。 6 | 7 | 每个容器都有自己独有的网络栈,意味着它们不能访问其他容器的 sockets 或接口。不过,如果主机系统上做了相应的设置,容器可以像跟主机交互一样的和其他容器交互。当指定公共端口或使用 links 来连接 2 个容器时,容器就可以相互通信了(可以根据配置来限制通信的策略)。 8 | 9 | 从网络架构的角度来看,所有的容器通过本地主机的网桥接口相互通信,就像物理机器通过物理交换机通信一样。 10 | 11 | 那么,内核中实现命名空间和私有网络的代码是否足够成熟? 12 | 13 | 内核命名空间从 2.6.15 版本(2008 年 7 月发布)之后被引入,数年间,这些机制的可靠性在诸多大型生产系统中被实践验证。 14 | 15 | 实际上,命名空间的想法和设计提出的时间要更早,最初是为了在内核中引入一种机制来实现 [OpenVZ](https://en.wikipedia.org/wiki/OpenVZ) 的特性。 16 | 而 OpenVZ 项目早在 2005 年就发布了,其设计和实现都已经十分成熟。 17 | -------------------------------------------------------------------------------- /security/other_feature.md: -------------------------------------------------------------------------------- 1 | # 其它安全特性 2 | 3 | 除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, Seccomp, SELinux, GRSEC 等。 4 | 5 | Docker 当前默认只启用了能力机制。用户可以采用多种方案来加强 Docker 主机的安全,例如: 6 | * 在内核中启用 GRSEC 和 PAX,这将增加很多编译和运行时的安全检查;通过地址随机化避免恶意探测等。并且,启用该特性不需要 Docker 进行任何配置。 7 | * 使用一些有增强安全特性的容器模板,比如带 AppArmor 的模板和 Redhat 带 SELinux 策略的模板。这些模板提供了额外的安全特性。 8 | * 用户可以自定义访问控制机制来定制安全策略。 9 | 10 | 跟其它添加到 Docker 容器的第三方工具一样(比如网络拓扑和文件系统共享),有很多类似的机制,在不改变 Docker 内核情况下就可以加固现有的容器。 11 | -------------------------------------------------------------------------------- /security/summary.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | 总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。 4 | 5 | 另外,用户可以使用现有工具,比如 [Apparmor](https://docs.docker.com/engine/security/apparmor/), [Seccomp](https://docs.docker.com/engine/security/seccomp/), SELinux, GRSEC 来增强安全性;甚至自己在内核中实现更复杂的安全机制。 6 | -------------------------------------------------------------------------------- /swarm_mode/README.md: -------------------------------------------------------------------------------- 1 | # Swarm mode 2 | 3 | Docker 1.12 [Swarm mode](https://docs.docker.com/engine/swarm/) 已经内嵌入 Docker 引擎,成为了 docker 子命令 `docker swarm`。请注意与旧的 `Docker Swarm` 区分开来。 4 | 5 | `Swarm mode` 内置 kv 存储功能,提供了众多的新特性,比如:具有容错能力的去中心化设计、内置服务发现、负载均衡、路由网格、动态伸缩、滚动更新、安全传输等。使得 Docker 原生的 `Swarm` 集群具备与 Mesos、Kubernetes 竞争的实力。 6 | -------------------------------------------------------------------------------- /swarm_mode/config.md: -------------------------------------------------------------------------------- 1 | # 在 Swarm 集群中管理配置数据 2 | 3 | 在动态的、大规模的分布式集群上,管理和分发配置文件也是很重要的工作。传统的配置文件分发方式(如配置文件放入镜像中,设置环境变量,volume 动态挂载等)都降低了镜像的通用性。 4 | 5 | 在 Docker 17.06 以上版本中,Docker 新增了 `docker config` 子命令来管理集群中的配置信息,以后你无需将配置文件放入镜像或挂载到容器中就可实现对服务的配置。 6 | 7 | >注意:`config` 仅能在 Swarm 集群中使用。 8 | 9 | 这里我们以在 Swarm 集群中部署 `redis` 服务为例。 10 | 11 | ## 创建 config 12 | 13 | 新建 `redis.conf` 文件 14 | 15 | ```bash 16 | port 6380 17 | ``` 18 | 19 | 此项配置 Redis 监听 `6380` 端口 20 | 21 | 我们使用 `docker config create` 命令创建 `config` 22 | 23 | ```bash 24 | $ docker config create redis.conf redis.conf 25 | ``` 26 | 27 | ## 查看 config 28 | 29 | 使用 `docker config ls` 命令来查看 `config` 30 | 31 | ```bash 32 | $ docker config ls 33 | 34 | ID NAME CREATED UPDATED 35 | yod8fx8iiqtoo84jgwadp86yk redis.conf 4 seconds ago 4 seconds ago 36 | ``` 37 | 38 | ## 创建 redis 服务 39 | 40 | ```bash 41 | $ docker service create \ 42 | --name redis \ 43 | # --config source=redis.conf,target=/etc/redis.conf \ 44 | --config redis.conf \ 45 | -p 6379:6380 \ 46 | redis:latest \ 47 | redis-server /redis.conf 48 | ``` 49 | 50 | 如果你没有在 `target` 中显式的指定路径时,默认的 `redis.conf` 以 `tmpfs` 文件系统挂载到容器的 `/config.conf`。 51 | 52 | 经过测试,redis 可以正常使用。 53 | 54 | 以前我们通过监听主机目录来配置 Redis,就需要在集群的每个节点放置该文件,如果采用 `docker config` 来管理服务的配置信息,我们只需在集群中的管理节点创建 `config`,当部署服务时,集群会自动的将配置文件分发到运行服务的各个节点中,大大降低了配置信息的管理和分发难度。 55 | -------------------------------------------------------------------------------- /swarm_mode/create.md: -------------------------------------------------------------------------------- 1 | # 创建 Swarm 集群 2 | 3 | 阅读 [基本概念](overview.md) 一节我们知道 `Swarm` 集群由 **管理节点** 和 **工作节点** 组成。本节我们来创建一个包含一个管理节点和两个工作节点的最小 `Swarm` 集群。 4 | 5 | ## 初始化集群 6 | 7 | 在已经安装好 Docker 的主机上执行如下命令: 8 | 9 | ```bash 10 | $ docker swarm init --advertise-addr 192.168.99.100 11 | Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager. 12 | 13 | To add a worker to this swarm, run the following command: 14 | 15 | docker swarm join \ 16 | --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 17 | 192.168.99.100:2377 18 | 19 | To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. 20 | ``` 21 | 22 | 如果你的 Docker 主机有多个网卡,拥有多个 IP,必须使用 `--advertise-addr` 指定 IP。 23 | 24 | > 执行 `docker swarm init` 命令的节点自动成为管理节点。 25 | 26 | ## 增加工作节点 27 | 28 | 上一步我们初始化了一个 `Swarm` 集群,拥有了一个管理节点,下面我们继续在两个 Docker 主机中分别执行如下命令,创建工作节点并加入到集群中。 29 | 30 | ```bash 31 | $ docker swarm join \ 32 | --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 33 | 192.168.99.100:2377 34 | 35 | This node joined a swarm as a worker. 36 | ``` 37 | 38 | ## 查看集群 39 | 40 | 经过上边的两步,我们已经拥有了一个最小的 `Swarm` 集群,包含一个管理节点和两个工作节点。 41 | 42 | 在管理节点使用 `docker node ls` 查看集群。 43 | 44 | ```bash 45 | $ docker node ls 46 | ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 47 | 03g1y59jwfg7cf99w4lt0f662 worker2 Ready Active 48 | 9j68exjopxe7wfl6yuxml7a7j worker1 Ready Active 49 | dxn1zf6l61qsb1josjja83ngz * manager Ready Active Leader 50 | ``` 51 | -------------------------------------------------------------------------------- /swarm_mode/demo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | wordpress: 5 | image: wordpress 6 | ports: 7 | - 80:80 8 | networks: 9 | - overlay 10 | environment: 11 | WORDPRESS_DB_HOST: db:3306 12 | WORDPRESS_DB_USER: wordpress 13 | WORDPRESS_DB_PASSWORD: wordpress 14 | deploy: 15 | mode: replicated 16 | replicas: 3 17 | 18 | db: 19 | image: mysql 20 | networks: 21 | - overlay 22 | volumes: 23 | - db-data:/var/lib/mysql 24 | environment: 25 | MYSQL_ROOT_PASSWORD: somewordpress 26 | MYSQL_DATABASE: wordpress 27 | MYSQL_USER: wordpress 28 | MYSQL_PASSWORD: wordpress 29 | deploy: 30 | placement: 31 | constraints: [node.role == manager] 32 | 33 | visualizer: 34 | image: dockersamples/visualizer:stable 35 | ports: 36 | - "8080:8080" 37 | stop_grace_period: 1m30s 38 | volumes: 39 | - "/var/run/docker.sock:/var/run/docker.sock" 40 | deploy: 41 | placement: 42 | constraints: [node.role == manager] 43 | 44 | volumes: 45 | db-data: 46 | networks: 47 | overlay: 48 | -------------------------------------------------------------------------------- /swarm_mode/deploy.md: -------------------------------------------------------------------------------- 1 | # 部署服务 2 | 3 | 我们使用 `docker service` 命令来管理 `Swarm` 集群中的服务,该命令只能在管理节点运行。 4 | 5 | ## 新建服务 6 | 7 | 现在我们在上一节创建的 `Swarm` 集群中运行一个名为 `nginx` 服务。 8 | 9 | ```bash 10 | $ docker service create --replicas 3 -p 80:80 --name nginx nginx:1.13.7-alpine 11 | ``` 12 | 13 | 现在我们使用浏览器,输入任意节点 IP ,即可看到 nginx 默认页面。 14 | 15 | ## 查看服务 16 | 17 | 使用 `docker service ls` 来查看当前 `Swarm` 集群运行的服务。 18 | 19 | ```bash 20 | $ docker service ls 21 | ID NAME MODE REPLICAS IMAGE PORTS 22 | kc57xffvhul5 nginx replicated 3/3 nginx:1.13.7-alpine *:80->80/tcp 23 | ``` 24 | 25 | 使用 `docker service ps` 来查看某个服务的详情。 26 | 27 | ```bash 28 | $ docker service ps nginx 29 | ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 30 | pjfzd39buzlt nginx.1 nginx:1.13.7-alpine swarm2 Running Running about a minute ago 31 | hy9eeivdxlaa nginx.2 nginx:1.13.7-alpine swarm1 Running Running about a minute ago 32 | 36wmpiv7gmfo nginx.3 nginx:1.13.7-alpine swarm3 Running Running about a minute ago 33 | ``` 34 | 35 | 使用 `docker service logs` 来查看某个服务的日志。 36 | 37 | ```bash 38 | $ docker service logs nginx 39 | nginx.3.36wmpiv7gmfo@swarm3 | 10.255.0.4 - - [25/Nov/2017:02:10:30 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-" 40 | nginx.3.36wmpiv7gmfo@swarm3 | 10.255.0.4 - - [25/Nov/2017:02:10:30 +0000] "GET /favicon.ico HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-" 41 | nginx.3.36wmpiv7gmfo@swarm3 | 2017/11/25 02:10:30 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.255.0.4, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.99.102" 42 | nginx.1.pjfzd39buzlt@swarm2 | 10.255.0.2 - - [25/Nov/2017:02:10:26 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-" 43 | nginx.1.pjfzd39buzlt@swarm2 | 10.255.0.2 - - [25/Nov/2017:02:10:27 +0000] "GET /favicon.ico HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0" "-" 44 | nginx.1.pjfzd39buzlt@swarm2 | 2017/11/25 02:10:27 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.255.0.2, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.99.101" 45 | ``` 46 | 47 | ## 服务伸缩 48 | 49 | 我们可以使用 `docker service scale` 对一个服务运行的容器数量进行伸缩。 50 | 51 | 当业务处于高峰期时,我们需要扩展服务运行的容器数量。 52 | 53 | ```bash 54 | $ docker service scale nginx=5 55 | ``` 56 | 57 | 当业务平稳时,我们需要减少服务运行的容器数量。 58 | 59 | ```bash 60 | $ docker service scale nginx=2 61 | ``` 62 | 63 | ## 删除服务 64 | 65 | 使用 `docker service rm` 来从 `Swarm` 集群移除某个服务。 66 | 67 | ```bash 68 | $ docker service rm nginx 69 | ``` 70 | -------------------------------------------------------------------------------- /swarm_mode/image/wordpress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/swarm_mode/image/wordpress.png -------------------------------------------------------------------------------- /swarm_mode/overview.md: -------------------------------------------------------------------------------- 1 | # 基本概念 2 | 3 | `Swarm` 是使用 [`SwarmKit`](https://github.com/docker/swarmkit/) 构建的 Docker 引擎内置(原生)的集群管理和编排工具。 4 | 5 | 使用 `Swarm` 集群之前需要了解以下几个概念。 6 | 7 | ## 节点 8 | 9 | 运行 Docker 的主机可以主动初始化一个 `Swarm` 集群或者加入一个已存在的 `Swarm` 集群,这样这个运行 Docker 的主机就成为一个 `Swarm` 集群的节点 (`node`) 。 10 | 11 | 节点分为管理 (`manager`) 节点和工作 (`worker`) 节点。 12 | 13 | 管理节点用于 `Swarm` 集群的管理,`docker swarm` 命令基本只能在管理节点执行(节点退出集群命令 `docker swarm leave` 可以在工作节点执行)。一个 `Swarm` 集群可以有多个管理节点,但只有一个管理节点可以成为 `leader`,`leader` 通过 `raft` 协议实现。 14 | 15 | 工作节点是任务执行节点,管理节点将服务 (`service`) 下发至工作节点执行。管理节点默认也作为工作节点。你也可以通过配置让服务只运行在管理节点。 16 | 17 | 来自 Docker 官网的这张图片形象的展示了集群中管理节点与工作节点的关系。 18 | 19 | ![](https://docs.docker.com/engine/swarm/images/swarm-diagram.png) 20 | 21 | ## 服务和任务 22 | 23 | 任务 (`Task`)是 `Swarm` 中的最小的调度单位,目前来说就是一个单一的容器。 24 | 25 | 服务 (`Services`) 是指一组任务的集合,服务定义了任务的属性。服务有两种模式: 26 | 27 | * `replicated services` 按照一定规则在各个工作节点上运行指定个数的任务。 28 | 29 | * `global services` 每个工作节点上运行一个任务 30 | 31 | 两种模式通过 `docker service create` 的 `--mode` 参数指定。 32 | 33 | 来自 Docker 官网的这张图片形象的展示了容器、任务、服务的关系。 34 | 35 | ![](https://docs.docker.com/engine/swarm/images/services-diagram.png) 36 | -------------------------------------------------------------------------------- /swarm_mode/rolling_update.md: -------------------------------------------------------------------------------- 1 | # SWarm mode 与滚动升级 2 | 3 | 在 [部署服务](deploy.md) 一节中我们使用 `nginx:1.13.7-alpine` 镜像部署了一个名为 `nginx` 的服务。 4 | 5 | 现在我们想要将 `NGINX` 版本升级到 `1.13.12`,那么在 Swarm mode 中如何升级服务呢? 6 | 7 | 你可能会想到,先停止原来的服务,再使用新镜像部署一个服务,不就完成服务的 “升级” 了吗。 8 | 9 | 这样做的弊端很明显,如果新部署的服务出现问题,原来的服务删除之后,很难恢复,那么在 Swarm mode 中到底该如何对服务进行滚动升级呢? 10 | 11 | 答案就是使用 `docker service update` 命令。 12 | 13 | ```bash 14 | $ docker service update \ 15 | --image nginx:1.13.12-alpine \ 16 | nginx 17 | ``` 18 | 19 | 以上命令使用 `--image` 选项更新了服务的镜像。当然我们也可以使用 `docker service update` 更新任意的配置。 20 | 21 | `--secret-add` 选项可以增加一个密钥 22 | 23 | `--secret-rm` 选项可以删除一个密钥 24 | 25 | 更多选项可以通过 `docker service update -h` 命令查看。 26 | 27 | ## 服务回退 28 | 29 | 现在假设我们发现 `nginx` 服务的镜像升级到 `nginx:1.13.12-alpine` 出现了一些问题,我们可以使用命令一键回退。 30 | 31 | ```bash 32 | $ docker service rollback nginx 33 | ``` 34 | 35 | 现在使用 `docker service ps` 命令查看 `nginx` 服务详情。 36 | 37 | ```bash 38 | $ docker service ps nginx 39 | 40 | ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 41 | rt677gop9d4x nginx.1 nginx:1.13.7-alpine VM-20-83-debian Running Running about a minute ago 42 | d9pw13v59d00 \_ nginx.1 nginx:1.13.12-alpine VM-20-83-debian Shutdown Shutdown 2 minutes ago 43 | i7ynkbg6ybq5 \_ nginx.1 nginx:1.13.7-alpine VM-20-83-debian Shutdown Shutdown 2 minutes ago 44 | ``` 45 | 46 | 结果的输出详细记录了服务的部署、滚动升级、回退的过程。 47 | -------------------------------------------------------------------------------- /swarm_mode/secret.md: -------------------------------------------------------------------------------- 1 | # 在 Swarm 集群中管理敏感数据 2 | 3 | 在动态的、大规模的分布式集群上,管理和分发 `密码`、`证书` 等敏感信息是极其重要的工作。传统的密钥分发方式(如密钥放入镜像中,设置环境变量,volume 动态挂载等)都存在着潜在的巨大的安全风险。 4 | 5 | Docker 目前已经提供了 `secrets` 管理功能,用户可以在 Swarm 集群中安全地管理密码、密钥证书等敏感数据,并允许在多个 Docker 容器实例之间共享访问指定的敏感数据。 6 | 7 | >注意: `secret` 也可以在 `Docker Compose` 中使用。 8 | 9 | 我们可以用 `docker secret` 命令来管理敏感信息。接下来我们在上面章节中创建好的 Swarm 集群中介绍该命令的使用。 10 | 11 | 这里我们以在 Swarm 集群中部署 `mysql` 和 `wordpress` 服务为例。 12 | 13 | ## 创建 secret 14 | 15 | 我们使用 `docker secret create` 命令以管道符的形式创建 `secret` 16 | 17 | ```bash 18 | $ openssl rand -base64 20 | docker secret create mysql_password - 19 | 20 | $ openssl rand -base64 20 | docker secret create mysql_root_password - 21 | ``` 22 | 23 | ## 查看 secret 24 | 25 | 使用 `docker secret ls` 命令来查看 `secret` 26 | 27 | ```bash 28 | $ docker secret ls 29 | 30 | ID NAME CREATED UPDATED 31 | l1vinzevzhj4goakjap5ya409 mysql_password 41 seconds ago 41 seconds ago 32 | yvsczlx9votfw3l0nz5rlidig mysql_root_password 12 seconds ago 12 seconds ago 33 | ``` 34 | 35 | ## 创建 MySQL 服务 36 | 37 | 创建服务相关命令已经在前边章节进行了介绍,这里直接列出命令。 38 | 39 | ```bash 40 | $ docker network create -d overlay mysql_private 41 | 42 | $ docker service create \ 43 | --name mysql \ 44 | --replicas 1 \ 45 | --network mysql_private \ 46 | --mount type=volume,source=mydata,destination=/var/lib/mysql \ 47 | --secret source=mysql_root_password,target=mysql_root_password \ 48 | --secret source=mysql_password,target=mysql_password \ 49 | -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \ 50 | -e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" \ 51 | -e MYSQL_USER="wordpress" \ 52 | -e MYSQL_DATABASE="wordpress" \ 53 | mysql:latest 54 | ``` 55 | 56 | 如果你没有在 `target` 中显式的指定路径时,`secret` 默认通过 `tmpfs` 文件系统挂载到容器的 `/run/secrets` 目录中。 57 | 58 | ```bash 59 | $ docker service create \ 60 | --name wordpress \ 61 | --replicas 1 \ 62 | --network mysql_private \ 63 | --publish target=30000,port=80 \ 64 | --mount type=volume,source=wpdata,destination=/var/www/html \ 65 | --secret source=mysql_password,target=wp_db_password,mode=0444 \ 66 | -e WORDPRESS_DB_USER="wordpress" \ 67 | -e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \ 68 | -e WORDPRESS_DB_HOST="mysql:3306" \ 69 | -e WORDPRESS_DB_NAME="wordpress" \ 70 | wordpress:latest 71 | ``` 72 | 73 | 查看服务 74 | 75 | ```bash 76 | $ docker service ls 77 | 78 | ID NAME MODE REPLICAS IMAGE 79 | wvnh0siktqr3 mysql replicated 1/1 mysql:latest 80 | nzt5xzae4n62 wordpress replicated 1/1 wordpress:latest 81 | ``` 82 | 83 | 现在浏览器访问 `IP:30000`,即可开始 `WordPress` 的安装与使用。 84 | 85 | 通过以上方法,我们没有像以前通过设置环境变量来设置 MySQL 密码, 而是采用 `docker secret` 来设置密码,防范了密码泄露的风险。 86 | -------------------------------------------------------------------------------- /swarm_mode/stack.md: -------------------------------------------------------------------------------- 1 | # 在 Swarm 集群中使用 compose 文件 2 | 3 | 正如之前使用 `docker-compose.yml` 来一次配置、启动多个容器,在 `Swarm` 集群中也可以使用 `compose` 文件 (`docker-compose.yml`) 来配置、启动多个服务。 4 | 5 | 上一节中,我们使用 `docker service create` 一次只能部署一个服务,使用 `docker-compose.yml` 我们可以一次启动多个关联的服务。 6 | 7 | 我们以在 `Swarm` 集群中部署 `WordPress` 为例进行说明。 8 | 9 | ```yaml 10 | version: "3" 11 | 12 | services: 13 | wordpress: 14 | image: wordpress 15 | ports: 16 | - 80:80 17 | networks: 18 | - overlay 19 | environment: 20 | WORDPRESS_DB_HOST: db:3306 21 | WORDPRESS_DB_USER: wordpress 22 | WORDPRESS_DB_PASSWORD: wordpress 23 | deploy: 24 | mode: replicated 25 | replicas: 3 26 | 27 | db: 28 | image: mysql 29 | networks: 30 | - overlay 31 | volumes: 32 | - db-data:/var/lib/mysql 33 | environment: 34 | MYSQL_ROOT_PASSWORD: somewordpress 35 | MYSQL_DATABASE: wordpress 36 | MYSQL_USER: wordpress 37 | MYSQL_PASSWORD: wordpress 38 | deploy: 39 | placement: 40 | constraints: [node.role == manager] 41 | 42 | visualizer: 43 | image: dockersamples/visualizer:stable 44 | ports: 45 | - "8080:8080" 46 | stop_grace_period: 1m30s 47 | volumes: 48 | - "/var/run/docker.sock:/var/run/docker.sock" 49 | deploy: 50 | placement: 51 | constraints: [node.role == manager] 52 | 53 | volumes: 54 | db-data: 55 | networks: 56 | overlay: 57 | ``` 58 | 59 | 在 `Swarm` 集群管理节点新建该文件,其中的 `visualizer` 服务提供一个可视化页面,我们可以从浏览器中很直观的查看集群中各个服务的运行节点。 60 | 61 | 在 `Swarm` 集群中使用 `docker-compose.yml` 我们用 `docker stack` 命令,下面我们对该命令进行详细讲解。 62 | 63 | ## 部署服务 64 | 65 | 部署服务使用 `docker stack deploy`,其中 `-c` 参数指定 compose 文件名。 66 | 67 | ```bash 68 | $ docker stack deploy -c docker-compose.yml wordpress 69 | ``` 70 | 71 | 现在我们打开浏览器输入 `任一节点IP:8080` 即可看到各节点运行状态。如下图所示: 72 | 73 | ![](image/wordpress.png) 74 | 75 | 在浏览器新的标签页输入 `任一节点IP` 即可看到 `WordPress` 安装界面,安装完成之后,输入 `任一节点IP` 即可看到 `WordPress` 页面。 76 | 77 | ## 查看服务 78 | 79 | ```bash 80 | $ docker stack ls 81 | NAME SERVICES 82 | wordpress 3 83 | ``` 84 | 85 | ## 移除服务 86 | 87 | 要移除服务,使用 `docker stack down` 88 | 89 | ```bash 90 | $ docker stack down wordpress 91 | Removing service wordpress_db 92 | Removing service wordpress_visualizer 93 | Removing service wordpress_wordpress 94 | Removing network wordpress_overlay 95 | Removing network wordpress_default 96 | ``` 97 | 98 | 该命令不会移除服务所使用的 `数据卷`,如果你想移除数据卷请使用 `docker volume rm` 99 | -------------------------------------------------------------------------------- /underly/README.md: -------------------------------------------------------------------------------- 1 | # 底层实现 2 | 3 | Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。 4 | 5 | 我们知道,传统的虚拟机通过在宿主主机中运行 hypervisor 来模拟一整套完整的硬件环境提供给虚拟机的操作系统。虚拟机系统看到的环境是可限制的,也是彼此隔离的。 6 | 这种直接的做法实现了对资源最完整的封装,但很多时候往往意味着系统资源的浪费。 7 | 例如,以宿主机和虚拟机系统都为 Linux 系统为例,虚拟机中运行的应用其实可以利用宿主机系统中的运行环境。 8 | 9 | 我们知道,在操作系统中,包括内核、文件系统、网络、PID、UID、IPC、内存、硬盘、CPU 等等,所有的资源都是应用进程直接共享的。 10 | 要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等等的相互隔离。 11 | 前者相对容易实现一些,后者则需要宿主机系统的深入支持。 12 | 13 | 随着 Linux 系统对于命名空间功能的完善实现,程序员已经可以实现上面的所有需求,让某些进程在彼此隔离的命名空间中运行。大家虽然都共用一个内核和某些运行时环境(例如一些系统命令和系统库),但是彼此却看不到,都以为系统中只有自己的存在。这种机制就是容器(Container),利用命名空间来做权限的隔离控制,利用 cgroups 来做资源分配。 14 | -------------------------------------------------------------------------------- /underly/_images/docker_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docker-practice/docker_practice/6cd1cad2affdc70642a5e77167ff7af38b422eef/underly/_images/docker_arch.png -------------------------------------------------------------------------------- /underly/arch.md: -------------------------------------------------------------------------------- 1 | # 基本架构 2 | 3 | Docker 采用了 `C/S` 架构,包括客户端和服务端。Docker 守护进程 (`Daemon`)作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。 4 | 5 | 客户端和服务端既可以运行在一个机器上,也可通过 `socket` 或者 `RESTful API` 来进行通信。 6 | 7 | ![Docker 基本架构](./_images/docker_arch.png) 8 | 9 | Docker 守护进程一般在宿主主机后台运行,等待接收来自客户端的消息。 10 | 11 | Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker 守护进程交互。 12 | -------------------------------------------------------------------------------- /underly/cgroups.md: -------------------------------------------------------------------------------- 1 | # 控制组 2 | 3 | 控制组([cgroups](https://en.wikipedia.org/wiki/Cgroups))是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。 4 | 5 | 控制组技术最早是由 Google 的程序员在 2006 年提出,Linux 内核自 2.6.24 开始支持。 6 | 7 | 控制组可以提供对容器的内存、CPU、磁盘 IO 等资源的限制和审计管理。 8 | -------------------------------------------------------------------------------- /underly/container_format.md: -------------------------------------------------------------------------------- 1 | # 容器格式 2 | 3 | 最初,Docker 采用了 `LXC` 中的容器格式。从 0.7 版本以后开始去除 LXC,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer),从 1.11 开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。 4 | -------------------------------------------------------------------------------- /underly/namespace.md: -------------------------------------------------------------------------------- 1 | # 命名空间 2 | 3 | 命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。 4 | 5 | ## pid 命名空间 6 | 不同用户的进程就是通过 pid 命名空间隔离开的,且不同命名空间中可以有相同 pid。所有的 LXC 进程在 Docker 中的父进程为 Docker 进程,每个 LXC 进程具有不同的命名空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。 7 | 8 | ## net 命名空间 9 | 有了 pid 命名空间,每个命名空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 命名空间实现的, 每个 net 命名空间有独立的 网络设备,IP 地址,路由表,/proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。 10 | 11 | ## ipc 命名空间 12 | 容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 命名空间中的进程间交互,因此需要在 IPC 资源申请时加入命名空间信息,每个 IPC 资源有一个唯一的 32 位 id。 13 | 14 | ## mnt 命名空间 15 | 类似 chroot,将一个进程放到一个特定的目录执行。mnt 命名空间允许不同命名空间的进程看到的文件结构不同,这样每个命名空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个命名空间中的容器在 /proc/mounts 的信息只包含所在命名空间的 mount point。 16 | 17 | ## uts 命名空间 18 | UTS("UNIX Time-sharing System") 命名空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。 19 | 20 | ## user 命名空间 21 | 每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。 22 | 23 | *注:更多关于 Linux 上命名空间的信息,请阅读 [这篇文章](https://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/)。 24 | -------------------------------------------------------------------------------- /underly/network.md: -------------------------------------------------------------------------------- 1 | # Docker 网络实现 2 | 3 | Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备(特别是 veth pair)。建议先熟悉了解这两部分的基本概念再阅读本章。 4 | 5 | ## 基本原理 6 | 首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。 7 | 8 | Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。 9 | Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统看来就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要快很多。 10 | 11 | Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 `veth pair`)。 12 | 13 | ## 创建网络参数 14 | Docker 创建一个容器的时候,会执行如下操作: 15 | * 创建一对虚拟接口,分别放到本地主机和新容器中; 16 | * 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9; 17 | * 容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的命名空间可见; 18 | * 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。 19 | 20 | 完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。 21 | 22 | 可以在 `docker run` 的时候通过 `--net` 参数来指定容器的网络配置,有4个可选值: 23 | * `--net=bridge` 这个是默认值,连接到默认的网桥。 24 | * `--net=host` 告诉 Docker 不要将容器网络放到隔离的命名空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用 `--privileged=true`,容器会被允许直接配置主机的网络堆栈。 25 | * `--net=container:NAME_or_ID` 让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过 `lo` 环回接口通信。 26 | * `--net=none` 让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。 27 | 28 | ## 网络配置细节 29 | 用户使用 `--net=none` 后,可以自行配置网络,让容器达到跟平常一样具有访问网络的权限。通过这个过程,可以了解 Docker 配置网络的细节。 30 | 31 | 首先,启动一个 `/bin/bash` 容器,指定 `--net=none` 参数。 32 | ```bash 33 | $ docker run -i -t --rm --net=none base /bin/bash 34 | root@63f36fc01b5f:/# 35 | ``` 36 | 在本地主机查找容器的进程 id,并为它创建网络命名空间。 37 | ```bash 38 | $ docker inspect -f '{{.State.Pid}}' 63f36fc01b5f 39 | 2778 40 | $ pid=2778 41 | $ sudo mkdir -p /var/run/netns 42 | $ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid 43 | ``` 44 | 检查桥接网卡的 IP 和子网掩码信息。 45 | ```bash 46 | $ ip addr show docker0 47 | 21: docker0: ... 48 | inet 172.17.42.1/16 scope global docker0 49 | ... 50 | ``` 51 | 创建一对 “veth pair” 接口 A 和 B,绑定 A 到网桥 `docker0`,并启用它 52 | ```bash 53 | $ sudo ip link add A type veth peer name B 54 | $ sudo brctl addif docker0 A 55 | $ sudo ip link set A up 56 | ``` 57 | 将B放到容器的网络命名空间,命名为 eth0,启动它并配置一个可用 IP(桥接网段)和默认网关。 58 | ```bash 59 | $ sudo ip link set B netns $pid 60 | $ sudo ip netns exec $pid ip link set dev B name eth0 61 | $ sudo ip netns exec $pid ip link set eth0 up 62 | $ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0 63 | $ sudo ip netns exec $pid ip route add default via 172.17.42.1 64 | ``` 65 | 以上,就是 Docker 配置网络的具体过程。 66 | 67 | 当容器结束后,Docker 会清空容器,容器内的 eth0 会随网络命名空间一起被清除,A 接口也被自动从 `docker0` 卸载。 68 | 69 | 此外,用户可以使用 `ip netns exec` 命令来在指定网络命名空间中进行配置,从而配置容器内的网络。 70 | -------------------------------------------------------------------------------- /underly/ufs.md: -------------------------------------------------------------------------------- 1 | # 联合文件系统 2 | 3 | 联合文件系统([UnionFS](https://en.wikipedia.org/wiki/UnionFS))是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。 4 | 5 | 联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。 6 | 7 | 另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。 8 | 9 | Docker 中使用的 AUFS(Advanced Multi-Layered Unification Filesystem)就是一种联合文件系统。 `AUFS` 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 `AUFS` 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。 10 | 11 | Docker 目前支持的联合文件系统包括 `OverlayFS`, `AUFS`, `Btrfs`, `VFS`, `ZFS` 和 `Device Mapper`。 12 | 13 | 各 Linux 发行版 Docker 推荐使用的存储驱动如下表。 14 | 15 | |Linux 发行版 | Docker 推荐使用的存储驱动 | 16 | | :-- | :-- | 17 | |Docker on Ubuntu | `overlay2` (16.04 +) | 18 | |Docker on Debian | `overlay2` (Debian Stretch), `aufs`, `devicemapper` | 19 | |Docker on CentOS | `overlay2` | 20 | |Docker on Fedora | `overlay2` | 21 | 22 | 在可能的情况下,[推荐](https://docs.docker.com/storage/storagedriver/select-storage-driver/) 使用 `overlay2` 存储驱动,`overlay2` 是目前 Docker 默认的存储驱动,以前则是 `aufs`。你可以通过配置来使用以上提到的其他类型的存储驱动。 23 | --------------------------------------------------------------------------------