企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## docker **author: 收集整理自互联网** **last update: 2022-12-15 22:23:11** ---- [TOC=3,8] ---- ### 什么是云原生? [Pivotal](https://baijiahao.baidu.com/s?id=1642528154354438867) 公司的 Matt Stine 于2013年首次提出云原生(CloudNative)的概念;2015年,云原生刚推广时,Matt Stine 在《迁移到云原生架构》一书中定义了符合云原生架构的几个特征:12因素、微服务、自敏捷架构、基于 API 协作、扛脆弱性;到了2017年,Matt Stine 在接受 InfoQ 采访时又改了口风,将云原生架构归纳为模块化、可观察、可部署、可测试、可替换、可处理6特质;而 Pivotal 最新官网对云原生概括为4个要点:DevOps + 持续交付 + 微服务 + 容器。[什么是云原生?这回终于有人讲明白了 - 知乎](https://zhuanlan.zhihu.com/p/150190166) 2004年,谷歌开始使用容器技术。到了2006年,谷歌发布了 Cgroups ,最初叫 Process Container(进程容器)。Process Container 发布后第二年就进入了 Linux 内核主干。为避免混乱,就更名为 Control Groups,也就是 Cgroups。 9年前,Netscape 公司的创始人马克·安德森说:“软件正在吞噬世界”。6年前,OpenStack 基金会创 Jonathan Bryce 补充说:“世界的一切源于开源”。再之后,业内普遍认同“云计算已改变了天空的颜色”。但近两年云计算概念又被清晰细分,“云原生”才是那条最大的鱼。“大鱼”来了,我们能做的不是墨守成规,而是拥抱“大鱼”。让我们了解云原生,拥抱云原生,追随云原生。[到底什么是“云原生”? - 墨天轮](https://www.modb.pro/db/335891) [云原生新手入门指南 · Kubernetes 中文指南——云原生应用架构实战手册](https://jimmysong.io/kubernetes-handbook/cloud-native/quick-start.html) ---- ### 初识 docker ![](http://blog.daocloud.io/wp-content/uploads/2017/02/Containers-at-sunset-with-Docker-11.jpg) ![](https://cdn.nlark.com/yuque/0/2021/png/1613913/1625373590853-2aaaa76e-d5b5-446b-850a-f6cfa26ac70a.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_85%2Ctext_YXRndWlndS5jb20gIOWwmuehheiwtw%3D%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10) #### docker 是什么? docker 是容器化工具,是通往 云原生时代 的船票。 docker 以简练易用的使用范式,极大地降低了容器技术的使用慢门槛,由此带来了云原生技术革命,这个时代还有比它更牛逼的东西吗? 信息技术革命:Unix > Linux > TCP/IP > Web > Docker ---- #### docker 不是什么? 1. docker 不是虚拟机,不提供 宿主机虚拟化功能 2. docker 不是操作系统,它不包含操作系统内核,只包含 root 文件系统 > 如果和虚拟机作类比,那么 **docker 是半虚拟化方案(或称为轻量级虚拟化)**,而 Oracle VM VirtualBox 等产品则是全虚拟化方案。 ---- #### 为什么是 docker? 人们总想要得更多(虚拟化、隔离),但不想付出太多(虚拟机成本),而 docker 刚好迎合了 “多·快·好·省” 的需求点。 ---- #### 不用 docker 的三大理由 1. 我喜欢配一整天的环境啥事也不干,我非常享受配环境的这个过程。 2. 我追求真实,都是直接买服务器,不用虚拟的容器。 3. [云原生](https://landscape.cncf.io/)、DevOps 这些对我来说就是炒作和噱头,不符合我朴实的价值观。 4. 相较于 “一次发布、随处运行” ,我更喜欢折腾和风浪。 ---- #### docker 的好处与局限性 1. Docker 是基于 Linux 64bit 的,无法在 32bit 的 linux/Windows/unix 环境下使用 2. LXC 是基于 Cgroup 等 Linux kernel 功能的,因此 Container 的 Guest 系统只能是 Linux base 的 3. 网络限制 > 容器网络(Docker Network )让你可以方便地在同一主机下对容器进行网络连接。加上一些其他的工作,你就可以跨主机使用叠加网络功能。然而,也就到此为止了。网络配置操作是受限的,而且到目前为止可以说这些手段都是人工的。尽管容器脚本化可以规模化,因为你必须给网络定义增加预分配实例,每次提供容器时还需要额外步骤,这容易引起错误。 4. cgroup 的 cpu 和 cpuset 提供的 cpu 功能,相比 KVM 的等虚拟化方案相比难以度量(所以 dotcloud 主要是按内存收费) 5. docker 对 disk 的管理比较有限 6. container 随着用户进程的停止而销毁,container 中的 log 等用户数据不便收集 7. 库控制受限 9. 没有清晰的审计跟踪 ---- ### 最简单的,docker 可以帮我做什么? 安装一个软件环境很麻烦,如原生安装一次 pulsar 环境,好不容易成功了,下次换一台机器还要再重来一次,就算你用脚本将安装过程自动化了,但还是不能保证百分百成功并和之前的配置一模一样,这简直是噩梦! 如果有一种方式让我们只用成功安装一次,后面在其他机器上安装时能够直接复制之前的成功成果就好了,这样无论安装过程多么复杂,多么艰辛,都没有关系,只要我们成功一次,只要一次,就够了!只要成功一次,就意味着后面的无数次再也没有任何负担了。 这就是 docker 能够帮助我们做的事,我们将第一次的成功打包成一个镜像,后面的千万次只用重复运行这个镜像就行了,只用简单的重复就行了,保证和第一个毫无二致,运行镜像的过程就像启动一个进程那么简单快速,没有安装、构建过程,没有等待,一键部署,开箱即用,一次打包,到处运行,这就是 docker 带给我们的魔法。 ---- ### docker 使用 #### docker 中的概念 ##### 镜像 操作系统分为 **内核** 和 **用户空间**。内核启动后,会挂载 root 文件系统(`/` 根文件系统)为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统,比如官方镜像 `ubuntu:18.04` 就包含了完整的一套 Ubuntu 18.04 最小系统的`root`文件系统。 镜像除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。**镜像不包含任何动态数据,其内容在构建之后也不会被改变**。 镜像是容器的基础,每次执行 `docker run` 的时候都会**指定以哪个镜像作为容器运行的基础。** [Docker 镜像 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/basic_concept/image/) 镜像就是构建物,就是 环境 + 可执行程序,一次构建,多处立即运行。 ~~~ $: docker image list REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 15 months ago 13.3kB ~~~ ~~~ 镜像id 标签1 标签2 ... ~~~ [分层存储](https://vuepress.mirror.docker-practice.com/basic_concept/image/#分层存储) 镜像加速: ```shell $ vi /etc/docker/daemon.json { "registry-mirrors": [ "https://h5m24cso.mirror.aliyuncs.com", "https://hub-mirror.c.163.com", "https://mirror.baidubce.com", "https://docker.mirrors.ustc.edu.cn" ] } $: sudo systemctl daemon-reload $: sudo systemctl restart docker ``` ##### 构建缓存 [Dockerfile 最佳实践 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/appendix/best_practices/#构建缓存) ~~~ 对于 ADD 和 COPY 指令,镜像中对应文件的内容也会被检查,每个文件都会计算出一个校验和。文件的最后修改时间和最后访问时间不会纳入校验。在缓存的查找过程中,会将这些校验和和已存在镜像中的文件校验和进行对比。如果文件有任何改变,比如内容和元数据,则缓存失效。 除了 ADD 和 COPY 指令,缓存匹配过程不会查看临时容器中的文件来决定缓存是否匹配。例如,当执行完 RUN apt-get -y update 指令后,容器中一些文件被更新,但 Docker 不会检查这些文件。这种情况下,只有指令字符串本身被用来匹配缓存。 一旦缓存失效,所有后续的 Dockerfile 指令都将产生新的镜像,缓存不会被使用。 ~~~ [https://vuepress.mirror.docker-practice.com/appendix/best_practices/#run](https://vuepress.mirror.docker-practice.com/appendix/best_practices/#run) > 使用 `RUN apt-get update && apt-get install -y` 可以确保你的 `Dockerfiles` 每次安装的都是包的最新的版本,而且这个过程不需要进一步的编码或额外干预。这项技术叫作 `cache busting`。 [使用 BuildKit 构建镜像 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/buildx/buildkit/#) [Composer install in Dockerfile Without Breaking Cache | Sentinel Stand](https://www.sentinelstand.com/article/composer-install-in-dockerfile-without-breaking-cache) > The COPY instruction will copy your application's source directory to the file system of the container. These files have likely been changed and the COPY instruction will invalidate the cache, which means that all subsequent Dockerfile instructions will run on every build. > 这`COPY`指令会将应用程序的源目录复制到容器的文件系统。 这些文件可能已被更改并且`COPY`指令将使缓存失效,这意味着所有后续的 Dockerfile 指令将在每个构建上运行。 ---- ##### 仓库 镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,[Docker Registry](https://hub.docker.com) 就是这样的服务。 每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。 通常,一个仓库会包含同一个软件不同版本的镜像,而**标签就常用于对应该软件的各个版本**。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 `latest` 作为默认标签。 仓库名经常以两段式路径形式出现,比如 `jwilder/nginx-proxy` ,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。(**官方仓库可以省略用户名**) 以 [Ubuntu 镜像](https://hub.docker.com/_/ubuntu) 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,`16.04`, `18.04`。我们可以通过 `ubuntu:16.04`,或者 `ubuntu:18.04` 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 `ubuntu`,那将视为 `ubuntu:latest`。 https://hub.docker.com/_/ubuntu https://hub.docker.com/layers/library/debian/bullseye-slim/images/sha256-76cdda8fe5eb597ef5e712e4c9a9f5f1fb119e69f353daaa7bd6d0f6e66e541d?context=explore https://github.com/docker-library/php/blob/b9f17156020c3aef71df681b27684533529347a7/7.4/bullseye/cli/Dockerfile https://hub.docker.com/layers/library/php/7.4-cli-bullseye/images/sha256-e6c15481f8b9999f4f099936c59dad3477a86d9affda1f5a023b1ed527764de0?context=explore ~~~ php:7.4-cli-bullseye 158.71 MB debian:bullseye-slim 29.96 MB ~~~ [docker镜像的版本(bullseye、buster、slim、alphine)_alun550的博客-CSDN博客_docker 镜像版本](https://blog.csdn.net/alun550/article/details/123184731) [镜像加速器 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/install/mirror/#) 登录到 docker 镜像仓库: ~~~ docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: xiaobu191 Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded ~~~ ---- ##### 容器 **镜像是静态的定义,容器是镜像运行时的实体。** 容器可以被创建、启动、停止、删除、暂停等。 **容器的实质是进程**,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 [命名空间](https://en.wikipedia.org/wiki/Linux_namespaces) 。因此容器可以拥有自己的`root`文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。 容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。 https://vuepress.mirror.docker-practice.com/basic_concept/container/ ~~~ 容器 = 镜像 + 容器存储层 ~~~ > 镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层。[利用 commit 理解镜像构成 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/image/commit/) > 除了镜像依赖以外,还**需要注意的是容器对镜像的依赖。** 如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过, **容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。** 如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。[删除本地镜像 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/image/rm/#用-id、镜像名、摘要删除镜像) 首层镜像: ```shell FROM scratch ADD alpine-minirootfs-3.16.4-x86_64.tar.gz / CMD ["/bin/sh"] ``` https://github.com/alpinelinux/docker-alpine/blob/106cf8fa24b495c3c7cac2ef3564fb78aef24751/x86_64/Dockerfile https://raw.githubusercontent.com/alpinelinux/docker-alpine/106cf8fa24b495c3c7cac2ef3564fb78aef24751/x86_64/alpine-minirootfs-3.16.4-x86_64.tar.gz https://hub.docker.com/layers/library/php/7.4.33-zts-alpine3.16/images/sha256-ec9045cb4e7388d81291499ae92bfdcf194644e8f701804a4592b6a8a2c400f0?context=explore ---- ##### 数据卷 容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,**任何保存于容器存储层的信息都会随容器删除而丢失。** 按照 Docker 最佳实践的要求,**容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录**,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。 数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,**使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。** ---- ##### 使用 Dockerfile 定制镜像 一般来说,应该会**将 `Dockerfile` 置于一个空目录下,或者项目根目录下。** 如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 `.gitignore` 一样的语法写一个 `.dockerignore`,该文件是**用于剔除不需要作为上下文传递给 Docker 引擎**的。https://vuepress.mirror.docker-practice.com/image/build/#镜像构建上下文-context ---- ##### 容器不是虚拟机 Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念。 然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。 对于容器而言,其启动程序就是容器应用进程,**容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出**,其它辅助进程不是它需要关心的东西。https://vuepress.mirror.docker-practice.com/image/dockerfile/cmd/ 此外,当 Docker 容器中指定的应用终结时,容器也自动终止。https://vuepress.mirror.docker-practice.com/container/stop/ 容器内并没有除指定进程以外的其他进程,虽然在表现上很容易使人联想到虚拟机,但至少在这点上,容器很明确的体现出了它和虚拟机最大的不同,**甚至拿轻量级的虚拟机来类比也是及其错误的,容器只是一个普通进程。** ~~~ 可以看到在容器内是看不到除了主要进程以外的任何其它进程,这可以证明容器内并不是一个子系统 docker run -t -i ubuntu:18.04 /bin/bash root@584e4a8dc01e:/# ps -aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.1 0.0 18504 2032 pts/0 Ss 09:48 0:00 /bin/bash root 15 0.0 0.0 34400 1508 pts/0 R+ 09:49 0:00 ps -aux root@584e4a8dc01e:/# top top - 09:48:57 up 2:50, 0 users, load average: 0.00, 0.01, 0.05 Tasks: 2 total, 1 running, 1 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 11690800 total, 10732624 free, 406416 used, 551760 buff/cache KiB Swap: 3710972 total, 3710972 free, 0 used. 11020780 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 18504 2028 1620 S 0.0 0.0 0:00.03 bash 13 root 20 0 36616 1736 1308 R 0.0 0.0 0:00.00 top ~~~ ---- ##### Dockerfile 多阶段构建 [多阶段构建_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Kg411D78F?p=15&vd_source=8fc0f668e63ab312d59a3089f3ca7a81) > 多阶段的每一阶段都从 FROM 开始,**最终的 镜像 只会从 最后一个阶段构建,不会包含前面阶段产生的层**,因此可以减少镜像的体积。(就像预制菜可以直接由半成品加热就可以吃,而不用买菜洗菜的环节) [多阶段构建 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/image/multistage-builds/#分散到多个-dockerfile) https://github.com/khs1994-docker/laravel-demo https://github.com/khs1994-docker/lnmp-nginx-conf-demo file: app.go ```go package main import "fmt" func main(){ fmt.Printf("Hello World!"); } ``` ---- file: Dockerfile.one ```Dockerfile FROM golang:alpine RUN apk --no-cache add git ca-certificates WORKDIR /go/src/github.com/go/helloworld/ # 将(上下文目录中)源码复制到容器中 COPY app.go . RUN go get -d -v github.com/go-sql-driver/mysql \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ && cp /go/src/github.com/go/helloworld/app /root #1. 安装依赖 #2. go build app #3. app 复制到 /root WORKDIR /root/ CMD ["./app"] ``` ```shell $ docker build -t go/helloworld:1 -f Dockerfile.one . ``` ---- file: Dockerfile.build ```Dockerfile FROM golang:alpine RUN apk --no-cache add git WORKDIR /go/src/github.com/go/helloworld # 将源码复制到容器中build COPY app.go . RUN go get -d -v github.com/go-sql-driver/mysql \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . ``` file: Dockerfile.copy ```Dockerfile FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ # 将(上下文目录中)二进制构建物复制到容器中 COPY app . CMD ["./app"] ``` file: build.sh ```shell #!/bin/sh echo Building go/helloworld:build # 构建镜像(go build) docker build -t go/helloworld:build . -f Dockerfile.build # 创建容器 extract docker create --name extract go/helloworld:build # 从容器 extract 中将 二进制构建物 app 复制出来 docker cp extract:/go/src/github.com/go/helloworld/app ./app # 删除容器 extract docker rm -f extract echo Building go/helloworld:2 # 构建镜像(exec app) docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy rm ./app ``` ``` $ chmod +x build.sh $ ./build.sh ``` ~~~ $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB go/helloworld 1 f55d3e16affc 2 minutes ago 295MB ~~~ ---- ##### 编排 ---- #### docker 安装 ~~~ sudo yum install -y yum-utils sudo yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin ~~~ ~~~ sudo systemctl enable docker sudo systemctl start docker sudo systemctl status docker docker info docker run --rm hello-world ~~~ ~~~ sudo systemctl daemon-reload sudo systemctl restart docker ~~~ https://vuepress.mirror.docker-practice.com/install/ ---- #### 自定义一个 oneinstack 镜像 将自定义环境,文件,压到镜像上,做成镜像发布。 ---- #### 热数据备份 将容器内修改的文件同步出来存放到物理机的存储结构上 ---- #### docker 命令说明 ~~~ # https://wangdoc.com/bash/grammar # 命令 选项 参数 command [option ...] [argument1 ... [ argumentN ]] ~~~ ~~~ $: docker --help 用法:docker [OPTIONS] COMMAND Options: --config string 客户端配置文件的位置(默认为"/root/.docker")。 -c, --context string 用于连接守护进程的上下文的名称(覆盖 DOCKER_HOST 环境变量和用 "docker context use " 设置的默认上下文)。 -D, --debug 启用调试模式 -H, --host 列出要连接的守护进程套接字 -l, --log-level string 设置日志级别("debug"|"info"|"warning"|"error"|"fatal")(默认 "info")。 --tls 使用 TLS ;由-tlsverify暗示 --tlscacert string 只信任由该CA签署的证书(默认为"/root/.docker/ca.pem")。 --tlscert string TLS 证书文件的路径(默认为"/root/.docker/cert.pem")。 --tlskey string TLS 密钥文件的路径(默认为"/root/.docker/key.pem") --tlsverify 使用 TLS 并验证远程 -v, --version 打印版本信息并退出 Management Commands: app* Docker 应用程序(Docker公司,v0.9.1-beta3)。 builder 管理构建 buildx* Docker Buildx (Docker Inc., v0.9.1-docker) compose* Docker Compose (Docker Inc., v2.12.2) config 管理 Docker 配置 container 管理容器 context 管理语境 image 管理镜像 manifest 管理 Docker 镜像的清单和清单列表 network 管理网络 node 理 Swarm 节点 plugin 管理插件 scan* Docker Scan(Docker公司,v0.21.0)。 secret 管理 Docker 的密钥 service 管理服务 stack 管理 Docker 堆栈 swarm 管理 Swarm system 管理 Docker trust 管理 Docker 镜像的信任 volume 管理卷 Commands: attach 将本地标准输入、输出和错误流附加到正在运行的容器上 build 从 Docker 文件中建立一个镜像 commit 从一个容器的变化中创建一个新的镜像 cp 在容器和本地文件系统之间复制 文件/文件夹 create 创建一个新的容器 diff 检查容器文件系统上的文件或目录的变化 events 从服务器上获取实时的事件 exec 在一个正在运行的容器中运行一个命令 export 将一个容器的文件系统导出为一个 tar 归档文件 history 显示一个镜像的历史 images 列出镜像 import 从一个 tar 包中导入内容以创建一个文件系统镜像 info 显示整个系统的信息 inspect 返回 Docker 对象的低层次信息 kill 杀死一个或多个正在运行的容器 load 从tar档案或 STDIN 中加载一个镜像 login 登录到一个 Docker 注册中心 logout 从 Docker 注册中心注销 logs 获取一个容器的日志 pause 暂停一个或多个容器的所有进程 port 列出容器的端口映射或一个特定的映射 ps 列出容器 pull 从注册表中拉出一个镜像或一个存储库 push 将一个镜像或版本库推送到注册中心 rename 重新命名一个容器 restart 重新启动一个或多个容器 rm 移除一个或多个容器 rmi 移除一个或多个镜像 run 在一个新的容器中运行一个命令 save 保存一个或多个镜像到一个tar档案(默认流向 STDOUT )。 search 在 Docker Hub 中搜索镜像 start 启动一个或多个停止的容器 stats 显示容器资源使用情况的实时统计流 stop 停止一个或多个正在运行的容器 tag 创建一个指向 SOURCE_IMAGE 的标签 TARGET_IMAGE top 显示一个容器的运行进程 unpause 取消一个或多个容器内的所有进程的停顿 update 更新一个或多个容器的配置 version 显示 Docker 的版本信息 wait 阻塞直到一个或多个容器停止,然后打印它们的退出代码 运行 docker COMMAND --help 可以获得更多关于命令的信息。 要获得更多关于 docker 的帮助,请查看我们的指南:https://docs.docker.com/go/guides/ 通过 www.DeepL.com/Translator(免费版)翻译 ~~~ ~~~ $: docker top --help Usage: docker top CONTAINER [ps OPTIONS] Display the running processes of a container ~~~ ~~~ $: docker ps --help Usage: docker ps [OPTIONS] List containers Options: -a, --all Show all containers (default shows just running) -f, --filter filter Filter output based on conditions provided --format string Pretty-print containers using a Go template -n, --last int Show n last created containers (includes all states) (default -1) -l, --latest Show the latest created container (includes all states) --no-trunc Don't truncate output -q, --quiet Only display container IDs -s, --size Display total file sizes ~~~ ---- ### 初学者 docker 之疑问 **镜像还可以指定不同的发行版操作系统吗,那运行容器不就是在系统中又运行了一个系统?** 镜像可以指定不同的发行版操作系统,是指可以指定某个发行版操作系统的 root 文件系统,也就是系统目录结构文件等(各个发行版系统镜像本身就是只有 rootfs 部分,不包含内核),并不是可以指定不同的操作系统内核版本,容器公用同一个宿主操作系统内核,所以容器的内核都是相同的版本。 容器是运行在宿主上的一个进程,并不是完整的系统或是子系统,这是和虚拟机最大的区别。不过对于容器进程来说,它是运行在一个隔离的系统资源内,这里使用的技术是 linux 自身的命名空间、组隔离等技术(想象一下编程语言中的命名空间,作用域隔离等技术),所以在容器内看起来就像是运行在一个独立的系统中一样,这种技术得益于 linux 底层的强大与灵活和开源社区的开放性。(据说 windows NT 比 linux 先进,可是 windows 上会诞生出 Docker 这样的技术吗?) ---- **应用在 docker 中运行会有性能损耗吗?** 应用在容器内运行相较于系统原生的环境中运行会有性能损耗吗,相信对性能有要求的应用都会首先关心这个问题。 [Docker容器、虚拟机和裸机运行的性能比较 - 极术社区 - 连接开发者与智能计算生态](https://aijishu.com/a/1060000000206531) ---- **容器只能运行“单一进程”?** [为什么说容器是单进程模型_Docker_的博客-CSDN博客](https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/102028724) [Docker容器的“单进程模型”](https://baijiahao.baidu.com/s?id=1673892417155737281&wfr=spider&for=pc) [25 为什么说容器是个单进程模型-慕课专栏](https://www.imooc.com/read/84/article/2336) > 针对上面这种 **将孤儿进程的父进程置为 1 号进程进而避免僵尸进程 处理方式,容器是处理不了的。** 进而就会导致**容器中在孤儿进程这种异常场景下僵尸进程无法彻底处理**的窘境。(**将孤儿进程的父进程设置为1号进程,是为了避免出现僵尸进程,这样当孤儿进程退出后,由1号进程对其资源进行回收,防止出现对资源的永久占用**) > > 容器的单进程模型的本质其实是**容器中的 1号进程 并不具有 类 Unix 系统中 systemd 管理这些孤儿进程、多进程、多线程等复杂场景下的能力。** 单一进程,并不是指只有一个进程,而是指 一个 entrypoint 启动进程(一号进程),其他线程都是一号进程的子进程。比如 nginx 和 apache 。 ---- #### 为什么容器的主进程必须是前台进程? > 因为Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。[docker容器为啥一定要前台运行 - luzhouxiaoshuai - 博客园](https://www.cnblogs.com/kebibuluan/p/15158793.html) > Docker容器后台运行,必须有一个前台进程。容器运行的命令如果不是那些一直挂起的命令(比如运行ping,sleep),就是会自动退出的。 [docker容器中的前台程序和后台程序,为什么一定要前台运行 - 腾讯云开发者社区-腾讯云](https://cloud.tencent.com/developer/article/2137830) ---- > 不知道为什么,似乎大家都对一些核心原理讳莫如深、只字不提、避而不谈,官方口径从不提镜像的本质就是系统目录结构这个基础的事实,而软件学习和理解的难点往往就在那些基础的概念和原理上。如此简单浅显的原理,为什么要故作高深、讳莫如深呢,大家都默认皇帝穿了新装,别问,别提,问就是傻子?提就是反叛者? > 对初学者来说,不理解相关概念,靠自己的理解容易走偏。 [ubuntu18.04的docker基础镜像_dockerubuntu18.04,dockerubuntu18.04镜像-Ubuntu工具类资源-CSDN文库](https://download.csdn.net/download/yunfwe/10766980?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165214483316781435469461%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165214483316781435469461&biz_id=1&utm_medium=distribute.pc_search_result.none-task-download-2~all~first_rank_ecpm_v1~rank_v31_ecpm-5-10766980-null-null.142^v9^control,157^v4^control&utm_term=ocker%E9%95%9C%E5%83%8F%E5%BF%85%E9%A1%BB%E5%8C%85%E5%90%AB%E7%B3%BB%E7%BB%9F%E5%90%97) > 镜像大小仅26M,包含完整的ubuntu18.04.1基础系统,可以通过apt-get命令更新和安装其他软件包,使用docker load -i ubuntu\_18.04-image.tar.gz 来加载镜像 [docker容器的分层思想_dianlv8134的博客-CSDN博客](https://blog.csdn.net/dianlv8134/article/details/101369993?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-3-101369993-blog-120147021.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-3-101369993-blog-120147021.pc_relevant_default&utm_relevant_index=6) ~~~ bootfs : kernel boot rootfs : /etc /dev /bin /usr .. 容器的内核会映射到容器的rootfs,等启动到bootfs的时候,容器就会卸载掉rootfs,由系统的rootfs也就是kernel进行支持,而bootfs的目录结构就会很小,所以容器就会很小。 所有的容器无法对kernel进行升级,如果安装的环境需要其他的版本的内核,则不能安装在docker容器中,需要放在虚拟机中运行,对kernel没限制的则可以使用docker容器运行。 ~~~ [再探docker容器的镜像分层和私有仓库_咸鱼王变身的博客-CSDN博客](https://blog.csdn.net/qq_41257472/article/details/120147021?ops_request_misc=&request_id=&biz_id=102&utm_term=ocker%E9%95%9C%E5%83%8F%E5%BF%85%E9%A1%BB%E5%8C%85%E5%90%AB%E7%B3%BB%E7%BB%9F%E5%90%97&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-6-120147021.142^v9^control,157^v4^control) ~~~ ### Docker 镜像结构: ================================ contaier 容器层 读写层 ,在最顶层 ================================容器层以下都是只读 有四层结构构建而成 imageN -------------------------------- .... -------------------------------- image0 如 scratch --------------------------------kernel 躯干(文件系统) aufs AUFS是一种联合文件系统,实现了Docker镜像的分层 -------------------------------- rootfs 就是各种不同的操作系统发行版,比如Ubuntu,Centos等等 -------------------------------- bootfs 主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统 -------------------------------- ~~~ [docker镜像是否包含操作系统? - 知乎](https://www.zhihu.com/question/366527646/answer/2280261145) ~~~ 《现代操作系统》中有讨论什么是操作系统,像常见的 windows,linux 这种操作系统就是运行在内核态的软件。所谓内核态对下拥有对硬件的完全访问权,对上能够为用户提供简单统一的操作模型。 docker 主要是通过 namespace ,cgroup,aufs等 linux 内核提供的技术来完成资源的隔离,像 docker 镜像本身就是一系列 aufs 层的打包。镜像的释放就是将 aufs 层释放,系统访问时会优先访问上层的文件,使得底层的文件对系统不可见,仅此而已。 每一个 docker 容器都与 linux 宿主共享一个内核,容器里的操作还要靠速主机内核完成,很明显光有 docker 容器是不能操作硬件的。 ---- Docker镜像包含操作系统,可以看一下Dockerfile相关的内容,熟悉一下打包Docker镜像的流程。文件第一行就是“From \[system name\]”,system name替换成你想要作为基础镜像的镜像名。至于后面的应用程序,tomcat,nginx等应用程序是在该基础上添加进去的 追问一个:那FROM XXX(某发行版)中的那个XXX又是怎么来的![[为难]](https://pic1.zhimg.com/v2-132ab52908934f6c3cd9166e51b99f47.png) 其实就是一个与根文件系统类似的目录结构用tar打包直接扔给docker import进来就好了,就这么简单,甚至一个空目录经过tar再import塞进docker能得到一个0k的镜像(portainer用的那个基础镜像就是portainer官方自己打包的) ~~~ [docker镜像是否包含操作系统_赵晗老师的博客-CSDN博客_docker镜像必须包含系统吗](https://blog.csdn.net/qfzhaohan/article/details/121794034) > 你看到很多docker镜像小,不是因为它们**不是完整的os**,而是因为**docker镜像都是基于某个特定的目的精简打包而成的**,去掉了很多兼容目的的安装包、驱动、资源文件;最有名的就是alpine [Docker为何需要OS的基础镜像?_krismile__qh的博客-CSDN博客_docker os](https://blog.csdn.net/krismile__qh/article/details/99883273) > 它不是一个OS,**但为何需要OS的基础镜像?** 其实这里的**基础镜像是一个包含rootfs的镜像。Kernel启动后是需要把启动文件解压到rootfs上的,然后kernel找到init文件启动就可以得到一个Linux环境了**,Docker做的事情就是模拟这个过程,让kernel给出一个独立的隔离环境。 [docker镜像依赖于linux吗,Docker镜像是否跟操作系统相关的?还是跨平台的?_weixin_29468871的博客-CSDN博客](https://blog.csdn.net/weixin_29468871/article/details/116893187?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-2-116893187-blog-121794034.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-2-116893187-blog-121794034.pc_relevant_antiscanv2&utm_relevant_index=5) [理解Docker “容器主机”和“容器操作系统”的关系_小小鸟008的博客-CSDN博客_docker容器和宿主操作系统](https://blog.csdn.net/qq_36412715/article/details/118152467?spm=1001.2101.3001.6650.8&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-8-118152467-blog-99883273.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-8-118152467-blog-99883273.pc_relevant_aa&utm_relevant_index=15) > 也称为主机操作系统(Host OS),是Docker客户端和Docker守护进程运行的**宿主操作系统**。 > 也称为基础操作系统(Base OS)。基础操作系统是指包含操作系统(如Ubuntu、CentOS或windowsservercore)的镜像。**注意,windows容器需要基础操作系统,而Linux容器则不需要。** [并非每个容器内部都能包含一个操作系统_Spring_java_gg的博客-CSDN博客](https://blog.csdn.net/u012516914/article/details/109476058?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-109476058-blog-118152467.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-109476058-blog-118152467.pc_relevant_paycolumn_v3&utm_relevant_index=2) > 也就是说,所有的容器都依赖这一个内核了?比如我现在有一个需求,我的两个容器运行在同一台宿主机上,但是依赖的内核版本不一样,或者需要配置的内核参数不一样,怎么解决呢?**解决不了,这也是容器化技术相比于虚拟机的主要缺陷之一。** > 实linux操作系统中代码包含两部分,**一部分是文件目录和配置,另外一部分是内核**,这两部分是分开存放的,**系统只有在宿主机开机启动时才会加载内核模块。说白了,即使镜像中包含了内核也不会被加载。** 说到最后,原来**镜像只是包含了操作系统的躯干(文件系统)**,并没有包含操作系统的灵魂(内核)。 [整理了一份 Docker系统知识,从安装到熟练操作看这篇就够了|原力计划](https://baijiahao.baidu.com/s?id=1668622380573288716&wfr=spider&for=pc) > 而容器内的应用进程直接运行于宿主的内核,**容器内没有自己的内核,而且也没有进行硬件虚拟。** 因此容器要比传统虚拟机更为轻便。**每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响**,能区分计算资源。 [Docker和宿主机操作系统文件目录互相隔离的实现原理_汪子熙的博客-CSDN博客](https://jerry.blog.csdn.net/article/details/84206593?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-84206593-blog-118152467.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-84206593-blog-118152467.pc_relevant_paycolumn_v3&utm_relevant_index=1) [Docker基础知识](https://baijiahao.baidu.com/s?id=1711979845981138114&wfr=spider&for=pc) > 容器基于镜像启动和运行,镜像好比容器的源代码,保存了用于启动容器的各种条件,docker的镜像是一个层叠的只读文件系统。最底端是一个引导文件系统,即bootfs,docker用户几乎不会和引导文件系统有交互,当一个容器启动后,它将会被移动到内存中,而引导文件系统将会被卸载,**docker镜像的第二层是root文件系统rootfs(ubuntu),位于引导文件之上,root文件系统可以是一种或多种的文件系统**,docker中root文件系统只能是只读状态,并且docker利用联合加载的技术又会在root文件系统之上加载更多的只读文件系统。联合加载指的是一次加载多个文件系统,**但在外面看来只能看到一个文件系统。联合加载会将各种文件系统叠加到一起。docker将这样的文件系统称之为镜像。** [Docker镜像(image)详解](http://c.biancheng.net/view/3143.html) [docker镜像依赖于linux吗,Docker镜像是否跟操作系统相关的?还是跨平台的?_weixin_29468871的博客-CSDN博客](https://blog.csdn.net/weixin_29468871/article/details/116893187?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-2-116893187-null-null.pc_agg_new_rank&utm_term=docker%E9%95%9C%E5%83%8F%E5%8C%85%E6%8B%AC%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%90%97&spm=1000.2123.3001.4430) [并非每个容器内部都能包含一个操作系统_Spring_java_gg的博客-CSDN博客](https://blog.csdn.net/u012516914/article/details/109476058) [Docker中每个镜像都有一个系统,会不会带来极大的额外开销_慕课猿问](https://www.imooc.com/wenda/detail/425702) > docker容器的开销并不是很大,远比不上完整的操作系统。 > docker镜像是**直接跑在宿主的内核上**的。 **比如alpine镜像启动才几m而已。** > docker用的是cgroup, 镜像里运行的每个应用也是宿主的进程。 [Docker 制作基础镜像----打包操作系统_weixin_34318956的博客-CSDN博客](https://blog.csdn.net/weixin_34318956/article/details/91733368) [阿里云Docker仓库_imonkeyi的博客-CSDN博客_阿里云docker仓库](https://blog.csdn.net/imonkeyi/article/details/120557675) [容器虚拟化网络漫谈(上) - 专栏博客 / 开发者实践 - RTC开发者社区-WebRTC中文论坛|RTC实时技术论坛](https://rtcdeveloper.agora.io/t/topic/23815) > **docker 实际上是利用了多个 Linux 提供的特性来完成这一切,这也是当初 Docker 刚发布时被批评为「新瓶装旧酒」的原因**,因为实际上 Docker 只是包装了操作系统的能力并提供了一套易用的 API,并没有发明什么新东西。 (除了底层芯片,上层的任何东西都只是新包装而已,无法再凭空发明创造什么,但这样的新瓶往往能掀起一场新的革命,带来前所未有的效率革命。) ---- ### 相关资源 https://hub.docker.com/_/scratch/ [Docker — 从入门到实践 | Docker 从入门到实践](https://vuepress.mirror.docker-practice.com/) [🎉 Docker 简介和安装 - Docker 快速入门 - 易文档](https://docker.easydoc.net/doc/81170005/cCewZWoN/lTKfePfP) [微服务是什么? - 阮一峰的网络日志](https://www.ruanyifeng.com/blog/2022/04/microservice.html) [Docker 入门教程 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html) [Docker教程:Docker入门实践(精讲版)](http://c.biancheng.net/docker/) https://developer.aliyun.com/mirror/ [译见 | 谁是 Docker 公司背后的神秘推手?-DaoCloud道客博客](http://blog.daocloud.io/5003.html) > **Solomon Hykes: Docker 的使命就是为大众的创新提供工具** [云平台核心 · 语雀](https://www.yuque.com/leifengyang/oncloud/vfvmcd) [云原生实战 - kubesphere](https://kubesphere.io/zh/learn/) [Docker入门实战完成 - kubesphere](https://kubesphere.io/zh/learn/level_1/lesson_25/video/) [学习 Kubernetes 基础知识 | Kubernetes - CN](https://kubernetes.io/zh-cn/docs/tutorials/kubernetes-basics/) [在 Linux 上以 All-in-One 模式安装 KubeSphere](https://kubesphere.io/zh/docs/v3.3/quick-start/all-in-one-on-linux/) [还不了解Docker和k8s?6分钟带你快速了解! - 知乎](https://zhuanlan.zhihu.com/p/345798544) ~~~ 尽管Docker为容器化的应用程序提供了开放标准,但随着容器越来越多出现了一系列新问题: 如何协调和调度这些容器? 如何在升级应用程序时不会中断服务? 如何监视应用程序的运行状况? 如何批量重新启动容器里的程序? 解决这些问题需要容器编排技术,可以将众多机器抽象,对外呈现出一台超大机器。现在业界比较流行的有:k8s、Mesos、Docker Swarm。 在业务发展初期只有几个微服务,这时用 Docker 就足够了,但随着业务规模逐渐扩大,容器越来越多,运维人员的工作越来越复杂,这个时候就需要编排系统解救opers。 ~~~ [10分钟看懂Docker和K8S - 知乎](https://zhuanlan.zhihu.com/p/145428041) > 就在Docker容器技术被炒得热火朝天之时,大家发现,**如果想要将Docker应用于具体的业务实现,是存在困难的**——编排、管理和调度等各个方面,都不容易。于是,人们迫切需要一套管理系统,对Docker及容器进行更高级更灵活的管理。 [京东案例研究 | 库伯内斯](https://kubernetes.io/case-studies/jd-com/) > “我的建议是,首先你需要把这项技术和你自己的业务结合起来,其次你需要有明确的目标。你不能因为别人在用它就使用它。你需要考虑你自己的目标。”— 刘海峰,京东首席架构师 我的目标很简单,解决单点故障问题,并能够根据负载进行伸缩,实现“永不停机”。 [一文带你了解容器技术的前世今生](https://mp.weixin.qq.com/s?__biz=MzkzNzI1MzE2Mw==&mid=2247484578&idx=1&sn=a8ae0d1c470351a8bbcb6891bae0ca23&chksm=c29304e6f5e48df010bc7a0ceefae80d01f440ca41a40930a40bcbcb12ce74799907a7d73ef5&token=1105111533&lang=zh_CN&scene=21#wechat_redirect) > 然而令 James Bayer 没有想到的是,短短几个月 Docker 就迅速崛起了,崛起速度如此之快,快到 Cloud Foundry 以及所有的 PaaS 社区还没来得及成为它的竞争对手,就直接被宣告出局了!