背景:最近和人讨论问题发现一个现象,当讨论的双方对某个主题的认识并不处在同一水平时, 讨论产出的价值是极其有限的;尤其是当一方对主题或客体几乎没有多少认知时。

简单来说,先花时间把基础的东西都看熟悉,了解透,再来讨论更节约时间成本。

顺便,101 这个数字在美国大学体系里往往是某专业入门课的课程号

之前在流利说看到一个非常好的习惯,在团队的知识中针对引入的技术,会写这样一篇用于 入门指南的文档,不求内容精,旨在帮助不熟悉的人能够快速对某个主题有一个感性认识,并 指引去获取更深层次的知识。学之。

推荐阅读

什么是 Docker https://www.redhat.com/zh/topics/containers/what-is-docker

https://www.redhat.com/zh/topics/containers/what-is-docker

什么是容器

https://www.redhat.com/zh/topics/containers/whats-a-linux-container

https://www.docker.com/resources/what-container

Docker 文档

https://docs.docker.com/

Linux 容器原理

https://coolshell.cn/articles/17010.html

https://coolshell.cn/articles/17029.html

https://coolshell.cn/articles/17049.html

https://coolshell.cn/articles/17061.html

安装

根据使用的操作系统环境,推荐阅读 https://docs.docker.com/install/ 文档寻找安装方式

关于在 macOS 下的实现 https://docs.docker.com/docker-for-mac/docker-toolbox/

由于本质上 Docker 应用的是 Linux 容器 (GNU/Linux 操作系统内核提供的 namespace 与 cgroup 的功能) 。所以对于 macOS 来说需要先有一个 Linux 内核环境。 Docker Toolbox for Mac 在安装命令的同时也安装了 VirtualBox ,所以实际上是在虚拟机里跑的。

Docker Desktop for Mac uses HyperKit instead of Virtual Box. Hyperkit is a lightweight macOS virtualization solution built on top of Hypervisor.framework in macOS 10.10 Yosemite and higher.

所以, Docker Desktop For Mac 其实是使用另外一种虚拟化技术,同样也是跑了一台虚拟机实现的。

Docker 如何工作

https://docs.docker.com/engine/docker-overview/

也是与 Linux 容器最大的不同, Docker 围绕在 Linux 容器周围建立起一套方便的工具链环境,让软件的分发、交付更为快捷,自动化。

https://docs.docker.com/engine/images/architecture.svg

我们从 Linux 容器的原理上已经知道,容器是利用内核的 namespace 与 cgroup 为容器里的一组进程创造资源,权限,功能隔离的独立空间。但仅仅是这样还不够方便。

有多不方便(某种程度来说是自由)?体验一下 lxc 的使用就知道了,https://linuxcontainers.org/lxc/introduction/

Docker 在这个基础上还实现了几个具有特点的功能,做到开箱即用。

运行进程而不是 init

推荐先阅读 https://en.wikipedia.org/wiki/Init 了解 Unix/Linux 系统的 init 进程,当操作系统内核启动后,用户要与内核交互完成工作,还需要有进程来负责维护、管理其他程序。

这是传统上一个操作系统的运行模型,而 Linux 容器本来使用时也并无区别,这也是为什么 Linux 容器在 Linux 环境下在用户感官上与虚拟机几乎相同的原因。

但 Docker 采取的做法不同,容器启动后并不运行 init 进程,改而直接运行目标程序,这样做相当于将一个容器打包变成一个软件的交付单元,非常轻量,

甚至网上有大量 docker 交付的软件运行起来只占用数MiB空间,数MiB内存。并且启动关闭快速,比起传统的虚拟机要更轻量。

此外,Docker 的思想是容器启动的进程退出,容器即关闭,但文件系统内容等保留,直到删除。

文件系统快照

传统的虚拟机,虚拟化系统本身使用起来与传统服务器主机并无区别。Docker 在文件系统上选用 Overlay2 文件系统 (早期,18.09版本以前,内核 3.13 前使用 AUFS ),实现文件系统的快照与恢复。

让文件系统内容也像 Git 版本管理一样,能够层层叠进。不仅仅有利于本地文件系统的版本管理,又有利于网络的传输(想想看,只需要比较一下镜像的文件系统版本,就可以知道哪些已经存在,只需要传输哪些更新的内容)。

镜像的共享、交付

传统上软件的分发,一般是共享出源代码,仅仅对开发者友好。想要让更多人使用,需要编译成二进制分发到各地,对于 Unix/Linux 操作系统有包管理器。对于其他设备,有应用商店。

当然对于虚拟机,也有不同的应用,但在行业内一般仅限于某个具体的虚拟化服务厂商。

Docker 建立起 Docker Registry ,并让 docker 具有网络共享镜像的能力,让全世界的社区都来贡献自己制作的镜像,上传到 Docker Hub (Docker公司自己运营的 Registry ),供人搜索,下载使用。

可以预见未来的软件交付,可能会演变为打包为 Docker 镜像,让用户直接本地 pull 一下。

使用

更多细节请参考 docker 文档

    # 下载镜像
    $ docker pull busybox

    # 运行镜像,交互式命令行
    # --rm 表示容器关闭后自动删除  -t -i 分别表示分配 tty 控制台以及交互式 shell ,最后是要运行的命令
    $ docker run --rm -ti --name busybox busybox sh

    # 运行软件,映射网络端口
    # -d 表示容器启动后 daemon 化, -p 表示映射端口 {host}:{container}
    # -v 表示目录映射 {host}:{container}
    $ docker pull nginx
    $ docker run -d -p 8080:80 -v `pwd`:/var/www/html --name nginx nginx

    # 将运行中的 docker 文件系统提交,保存为新版本的镜像
    # 当然这种手工操作现在显得很繁琐,建议使用 docker build
    $ docker commit ${name} [${image}]

    # 将 Docker 镜像推送到远程 Docker 仓库中
    $ docker push ${image}

    # 删除容器的相关文件
    $ docker rm ${name}

    # 根据当前路径下 Dockerfile 规则,以当前路径为工作目录,打包镜像
    # 更多请参考 Dockerfile 与镜像打包文档
    $ docker build -t ${image} .

    # 镜像相关操作
    $ docker images
    $ docker rmi ${image}
    # 清理不与运行中容器,镜像有关的文件层,清理空间
    $ docker image prune

    # 查看容器状态
    $ docker ps [-a]
    $ docker inspect ${container}
    $ docker stats ${container}

    # 在运行中的容器内执行命令
    $ docker exec ${container} ${command...}

    # 进入容器的交互式命令行
    $ docker exec -ti ${container} sh
    $ docker exec -ti ${container} bash

其他的一些情况,例如图形界面软件,可以通过映射文件系统,让容器内的软件读取到外部 X11 环境实现,也可以通过远程桌面实现。

Docker 打包镜像参考: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

使用上的难题

使用非 HTTPS 的 registry

参考: https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file

在 dockerd 配置文件 docker-daemon.json 中加入以下内容

    {
      "insecure-registries": ["http://192.168.1.100:5000/"]
    }

Windows 下配置文件位于 %programdata%\docker\config\daemon.json

Linux 下配置文件位于 /etc/docker/daemon.json

macOS 用户请使用界面配置

科学上网

有些镜像在国外,可能无法直接访问,需要配置科学上网

Windows 用户参考 https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/configure-docker-daemon

macOS 用户请使用界面配置

Linux 用户在 Docker 启动文件中加入 HTTP\_PROXY 与 HTTPS\_PROXY 环境变量

init 的使用 /etc/init.d/docker

systemd 用户修改 /lib/systemd/system/docker.service ,在 Service 下添加 Environment=HTTP\_PROXY=… 与 Environment=HTTPS\_PROXY=…

拓展工具应用

  • docker compose https://docs.docker.com/compose/ 用来组织多个容器间协作构建环境的工具,通过写 docker-compose.yaml 文件,方便的利用 docker-compose up 与 docker-compose down 命令开关多个 Docker 容器

拓展阅读