GuoXin Li's Blog

Docker notes

字数统计: 3k阅读时长: 11 min
2021/03/21 Share

Docker

基本概念

镜像

操作系统分为 内核用户空降。Linux 系统内核启动后,会挂载 root 文件系统为其提供用户空间支持。

Docker 镜像相当于一个 root 文件系统,如 官方镜像 ubuntu:18:04 就包含了完整的一套 ubuntu18.04最小系统 root 文件系统。

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

镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说是由多层文件系统联合组成。

容器

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

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

容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,自己的用户 ID 空间。

容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。

每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层

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

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

  • 数据卷:

    • 数据卷可以在容器之间共享和重用
    • 对数据卷的修改会立马生效
    • 对数据卷的更新,不会影响镜像
    • 数据卷默认会一直存在,即使容器被删除

    数据卷的使用,类似于 Linux 下对目录或文件进行 mount,镜像中被置顶为挂载点的目录中的文件会复制到数据卷中(仅数据卷为空时会被复制)。

    • 创建数据卷
      docker volume create my-vol

      查看所有 数据卷

      docker volume ls

      在主机里使用一下命令可以查看指定的 数据卷 的信息

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      $ docker volume inspect my-vol
      [
      {
      "Driver": "local",
      "Labels": {},
      "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
      "Name": "my-vol",
      "Options": {},
      "Scope": "local"
      }
      ]
*   启动一个挂载数据卷的容器

    在用 `docker run` 命令时,使用 `--mount ` 标记来将 数据卷挂载到容器里,在一次 `docker run` 中可以挂载多个 数据卷。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

仓库

Docker Registry 就是一个集中的存储、分发镜像的服务。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的 官方镜像。除此以外,还有 Red Hat 的 Quay.io;Google 的 Google Container RegistryKubernetes 的镜像使用的就是这个服务;代码托管平台 GitHub 推出的 ghcr.io

国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为 加速器。常见的有 阿里云加速器DaoCloud 加速器 等。使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从 Docker Hub 下载速度会提高很多。

除此之外,Docker 还提供搭建私有仓库。

安装 Docker

Ubuntu

首先卸载旧版本

1
2
3
$ sudo apt-get remove docker \
docker-engine \
docker.io

可以使用 APT 安装,整个过程由 apt 使用 https 确保下载过程中不被篡改。

当然最便捷的方法是使用 Docker 官方提供的脚本进行安装简化流程。

1
2
3
4
# $ curl -fsSL test.docker.com -o get-docker.sh
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh --mirror Aliyun
# $ sudo sh get-docker.sh --mirror AzureChinaCloud

启动 Docker

$ sudo systemctl enable docker $ sudo systemctl start docker

建立 Docker 用户组

默认情况下,docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。

建立 docker 用户组

$ sudo groupadd docker

将当前用户加入 docker 组

$ sudo usermod -aG docker $USER

Mac

  • 使用 Homebrew
1
brew install --cask docker
  • 手动下载 package 进行安装,下载链接

检查 Docker 版本

docker --version

安装 Nginx 测试 Docker 服务

$ docker run -d -p 80:80 --name webserver nginx

之后访问 http://localhost 即可进入到 nginx

停止 Nginx 并删除命令

$ docker stop webserver

$ docker rm webserver

获取镜像

获取镜像命令 docker pull

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

Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub(docker.io)。

仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ docker run -it --rm ubuntu:18.04 bash

root@e7009c6ce357:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

运行容器

docker run 来创建容器时,docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定镜像,不存在就从 registry 下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中
  • 从地址池分配一个 IP地址给容器
  • 执行用户指定应用程序
  • 执行完毕容器终止

启动已经终止容器

利用 docker container start 命令,直接将一个已经终止 exited 的容器启动运行。

可以在容器中使用 ps 命令查看进程信息。

守护态运行

可以使用 -d 参数来实现 Docker 应用后台运行,而不是将执行命令的结果输出在当前的宿主机下。

再次通过 docker container logs [container ID or NAMES] 来进行查看输出信息。

终止容器

使用 docker container stop [container ID or NAMES] 终止运行中的容器。

使用 docker container ls -a 查看被终止的容器。

进入容器

attach 容器名字,可以进入,但是exit后会导致容器停止。

-i -t 参数可以看到熟悉的 Linux 命令提示符。

导出容器

使用 docker export

1
2
3
4
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7691a814370e ubuntu:18.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test
$ docker export 7691a814370e > ubuntu.tar

导入容器快照

使用 docker import

1
2
3
4
$ cat ubuntu.tar | docker import - test/ubuntu:v1.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB

通过指定 URL 或者某个目录来导入

1
$ docker import http://example.com/exampleimage.tgz example/imagerepo

列出镜像

1
2
docker ps
docker image ls

docker image ls 列表中的镜像提及总和并非是所有镜像时机硬盘消耗,由于docker的多层存储结构,并可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像从而拥有共同的层。因此实际硬盘空间可能要比列表镜像大小总和小很多。

docker system df 可以便捷的查看镜像、容器、数据卷所占用的空间

Screen Shot 2021-04-15 at 23.22.28

虚悬镜像

当进行 docker pull xxx 更新某个镜像的时候,或者docker build 会导致更新的镜像使用原有的名字,老的镜像被取消名称,这就是 dangling image 虚悬镜像,可以用 docker image prune 来进行删除,虚悬镜像失去存在的价值了。

删除镜像

docker image ls

然后使用

docker image rm **

操作容器

docker run -it ubuntu:18.04 /bin/sh

-t 让dock儿分配一个伪终端,并绑定到容器的标准输入上,-i 则让容器的标准输入保持打开。

docker run 创建容器时,Docker 后台运行操作包括:

  • 检查本地是否存在指定镜像,如果不存在就从 registry 上下载

访问仓库

Docker Hub 是官方维护的一个公共仓库,可以用来下载镜像。

docker search 用来查找官方仓库中的镜像,docker pull 来将镜像下载到本地。

推送镜像

用户登陆后可以通过 docker push 命令将自己的镜像推送到 Docker Hub

1
2
3
4
5
6
7
$docker tag ubuntu:18.04 username/ubuntu:18.04

$docker image ls

$docker push username/ubuntu:18.04

$docker search username

Docker 私有仓库

docker-registry 是官方提供的工具,可以用于构建私有的镜像仓库。

安装 Docker-registry

使用官方的 registry 镜像运行:

1
$ docker run -d -p 5000:5000 --restart=always --name registry registry

默认仓库会被创建在容器的 /var/lib/registry 目录下。可以使用 -v 参数来修改指定路径。

私有仓库上传、搜索、下载镜像

使用 docker tagubuntu:latest镜像标记为 127.0.0.1:5000/ubuntu:latest

1
2
$ docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest
$ docker image ls

使用 docker push 上传标记的镜像

1
$ docker push 127.0.0.1:5000/ubuntu:latest

外部访问容器

容器中可以运行网络应用,如果想要外部可以访问这些应用,可以通过 -p 参数来指定端口映射。

当使用 -P 标记时,Docker 会随机映射一个端口到内部容器开放的网络端口。

使用 docker container ls可以看到某一容器的端口号与本地主机之间的映射关系,前面是本地主机后面是容器的端口号。访问本机的端口即可访问容器的页面。

映射到指定地址的指定端口

1
docker run -d -p 127.0.0.1:80:80 nginx:alpine

查看端口访问记录

1
docker logs fa

查看映射端口的配置

1
docker port fa 80

可以用来查看当前映射的端口配置,查看绑定的地址。

CATALOG
  1. 1. Docker
    1. 1.1. 基本概念
      1. 1.1.1. 镜像
      2. 1.1.2. 容器
      3. 1.1.3. 仓库
    2. 1.2. 安装 Docker
      1. 1.2.1. Ubuntu
        1. 1.2.1.1. 启动 Docker
        2. 1.2.1.2. 建立 Docker 用户组
      2. 1.2.2. Mac
    3. 1.3. 获取镜像
      1. 1.3.0.1. 运行
  2. 1.4. 运行容器
    1. 1.4.1. 启动已经终止容器
    2. 1.4.2. 守护态运行
    3. 1.4.3. 终止容器
    4. 1.4.4. 进入容器
    5. 1.4.5. 导出容器
    6. 1.4.6. 导入容器快照
    7. 1.4.7. 列出镜像
    8. 1.4.8. 虚悬镜像
    9. 1.4.9. 删除镜像
    10. 1.4.10. 操作容器
  3. 1.5. 访问仓库
    1. 1.5.1. 推送镜像
    2. 1.5.2. Docker 私有仓库
    3. 1.5.3. 私有仓库上传、搜索、下载镜像
  4. 1.6. 外部访问容器
    1. 1.6.1. 映射到指定地址的指定端口
    2. 1.6.2. 查看端口访问记录
    3. 1.6.3. 查看映射端口的配置