docker 学习笔记(一)

docker 学习笔记(一

Posted by ZW on July 7, 2021

什么是docker

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器

docker 的好处

  1. 占用空间小,系统开销小
  2. 启动快
  3. 提供一致的运行环境
  4. 持续交付和部署
  5. 更轻松的迁移
  6. 更轻松的维护和扩展

基本概念

镜像(image)

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。

分层存储 : 镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

仓库(Repository)

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。

安装

实操

使用镜像

获取镜像

```shell script docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

例如: docker pull ubuntu:18.04


## 启动容器
```shell script
docker run -it --rm ubuntu:18.04 bash

  • -it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
  • –rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 –rm 可以避免浪费空间。
  • ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash。

本地镜像列表

```shell script $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE redis latest 5f515359c7f8 5 days ago 183 MB nginx latest 05a60462f8ba 5 days ago 181 MB mongo 3.2 fe9198c04d62 5 days ago 342 MB

00285df0df87 5 days ago 342 MB ubuntu 18.04 329ed837d508 3 days ago 63.3MB ubuntu bionic 329ed837d508 3 days ago 63.3MB ``` * CREATED 为 镜像owner 运行的最新docker build的日期 * docker inspect -f '' hello-world 查看本地镜像创建时间 * SIZE 不是实际占用磁盘空间,因为docker 文件分层,底层文件可以服用 ## 删除镜像 ```shell script $ docker image rm [选项] <镜像1> [<镜像2> ...] 例如 docker image rm 501 ``` ## docker commit ```shell script docker diff webserver docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]] docker history nginx:v2 ``` docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 docker commit 定制镜像,定制镜像应该使用 Dockerfile 来完成 使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。 ## 定制镜像 Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。 ### 实操 指令 * FROM : FROM 就是指定 基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令 * RUN : 是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一. > 使用 && 将各个所需命令串联起来.简化为了 1 层. 镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。 * COPY: 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。 * ADD: 和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。可以增加URL,tar文件。 * CMD :格式和 RUN 相似。容器中的程序应该以前台的方式执行。 * ENTRYPOINT:格式和 RUN 指令格式一样.当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令. * ENV :设置环境变量. * ARG:和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。 VOLUME : 定义匿名卷 EXPOSE :暴露端口.要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。 WORKDIR :指定工作目录.每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。 因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令 USER :和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。 HEALTHCHECK : 健康检查 ONBUILD :它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。 ### 生成镜像 docker build -t nginx:v3 . . 不是指当前目录,指实际上是在指定上下文的目录,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。 一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。 ### manifest 当用户获取一个镜像时,Docker 引擎会首先查找该镜像是否有 manifest 列表,如果有的话 Docker 引擎会按照 Docker 运行环境(系统及架构)查找出对应镜像(例如 golang:alpine)。如果没有的话会直接获取镜像(例如上例中我们构建的 username/test)