一、Docker 的四大组成对象

  • 镜像(image)
  • 容器(container)
  • 网络(network)
  • 数据卷(volume)

1.1 镜像

所谓镜像,可以理解为一个只读的文件包,其中包含了虚拟环境运行最原始文件系统的内容

1.2 容器

容器就是用来隔离虚拟环境的基础设施,而在 Docker 里,它也被引申为隔离出来的虚拟环境。

Docker 的容器应该有三项内容组成

  • 一个 Docker 镜像
  • 一个程序运行环境
  • 一个指令集合

1.3 网络

在 Docker 中,实现了强大的网络功能,我们不但能够十分轻松的对每个容器的网络进行配置,还能在容器间建立虚拟网络,将数个容器包裹其中,同时与其他网络环境隔离

Docker 能够在容器中营造独立的域名解析环境,这使得我们可以在不修改代码和配置的前提下直接迁移容器,Docker 会为我们完成新环境的网络适配。对于这个功能,我们甚至能够在不同的物理服务器间实现,让处在两台物理机上的两个 Docker 所提供的容器,加入到同一个虚拟网络中,形成完全屏蔽硬件的效果

1.4 数据卷

  1. 除了网络之外,文件也是重要的进行数据交互的资源。在以往的虚拟机中,我们通常直接采用虚拟机的文件系统作为应用数据等文件的存储位置。然而这种方式其实并非完全安全的,当虚拟机或者容器出现问题导致文件系统无法使用时,虽然我们可以很快的通过镜像重置文件系统使得应用快速恢复运行,但是之前存放的数据也就消失了。
  2. 为了保证数据的独立性,我们通常会单独挂载一个文件系统来存放数据。这种操作在虚拟机中是繁琐的,因为我们不但要搞定挂载在不同宿主机中实现的方法,还要考虑挂载文件系统兼容性,虚拟操作系统配置等问题。值得庆幸的是,这些在 Docker 里都已经为我们轻松的实现了,我们只需要简单的一两个命令或参数,就能完成文件系统目录的挂载。
  3. 能够这么简单的实现挂载,主要还是得益于 Docker 底层的 Union File System 技术。在 UnionFS 的加持下,除了能够从宿主操作系统中挂载目录外,还能够建立独立的目录持久存放数据,或者在容器间共享。
  4. 在 Docker 中,通过这几种方式进行数据共享或持久化的文件或目录,我们都称为数据卷 ( Volume )…

安装

前置条件:Docker 的安装和使用有一些前提条件,主要体现在体系架构和内核的支持上。 最新docker支持情况

Docker 对于内核支持的功能,即内核的配置选项也有一定的要求(比如必须开启 Cgroup 和 Namespace 相关选项,以及其他的网络和存储驱动等)

Docker 源码中提供了一个检测脚本来检测和指导内核的配置

参考

修改源

  1. sudo vim /etc/docker/daemon.json (如果没有即可建立一个)
  2. { "data-root": "新地址" }
  3. 此文件还涉及默认源的设定,如果设定了国内源,那么实际就是在源地址下方加一行,写成:
  4. { "registry-mirrors": ["http://hub-mirror.c.163.com"], "data-root": "新地址" }
  5. sudo systemctl restart docker
  6. docker info查看是否修改成功

版本解读

  1. [root@bj-sjhl-wx-hanxu4-dev ops]# docker version
  2. Client: Docker Engine - Community
  3. Version: 20.10.14
  4. API version: 1.41
  5. Go version: go1.16.15
  6. Git commit: a224086
  7. Built: Thu Mar 24 01:49:57 2022
  8. OS/Arch: linux/amd64
  9. Context: default
  10. Experimental: true

docker 启动 (修改配置需要重启docker)

  1. service docker start

Docker 的简单运用 Hello World

  1. docker pull library/hello-world

docker pull images 是抓取 image 文件,library/hello-world 是 image 文件在仓库里面的位置,其中 library 是 image 文件所在的组,hello-world 是 image 文件的名字。

运行hello-world

  1. docker run hello-world

Docker 的核心组件包括:

  • Docker Client
  • Docker Daemon
  • Docker Image
  • Docker Registry
  • Docker Container

Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。

客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 Socket 或 REST API 与远程的服务器通信。

Docker Client ,也称 Docker 客户端。它其实就是 Docker 提供命令行界面(CLI)工具,是许多 Docker 用户与 Docker 进行交互的主要方式。

Docker Daemon 是服务器组件,以 Linux 后台服务的方式运行,是 Docker 最核心的后台进程,我们也把它称为守护进程。负责响应来自 Docker Client 的请求,然后将这些请求翻译成系统调用完成容器管理操作。

  1. systemctl status docker.service

Docker Daemon 运行在 Docker Host 上,负责创建、运行、监控容器,构建、存储镜像。

默认配置下,Docker Daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听。

编辑配置文件/etc/systemd/system/multi-user.target.wants/docker.service,在环境变量 ExecStart 后面添加 -H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。

重启 Docker Daemon:

  1. systemctl daemon-reloadsystemctl restart docker.service
  1. docker -H 服务器IP地址 info

Docker Registry

Docker Registry 是存储 Docker Image 的仓库

image.png

Docker 组件是如何协作运行容器

容器启动过程如下:

  • Docker 客户端执行 docker run 命令。
  • Docker Daemon 发现本地没有 hello-world 镜像。
  • Daemon 从 Docker Hub 下载镜像。
  • 下载完成,镜像 hello-world 被保存到本地。
  • Docker Daemon 启动容器。

namespaces

  • 查看当前bash进程所属的namespace
    • ls -l /proc/$$/ns

隔离技术
image.png

docker api

docker 本质上是一个API Server ,外层提供API,内部将请求转化为对Linux操作

1. Docker Registry API
这个是docker镜像仓库的api,通过操作这套API,你可以自由的自动化、程序化的管理你的镜像仓库。
2. Docker Hub API
Docker Hub API是用户管理操作的API,docker hub是使用校验和公共 namespaces 的方式来存储账户信息、认证账户、进行账户授权。API同时也允许操作相关的用户仓库和 library 仓库。
3. Docker Remote API
这套API用于控制主机 Docker 服务端的 API,等价于 docker命令行客户端。 有了它,你能远程操作docker容器,更重要的是你可以通过程序自动化运维docker进程。
image.png

images

命令 描述
docker search xxx
docker pull redis :latest
拉取镜像 (默认会保存在 /var/lib/docker )
指定版本
docker images 查看镜像列表 (表示镜像的仓库源,tag 镜像的标签,镜像的创建时间,镜像大小)
docker rmi 镜像id 根据镜像id删除镜像
docker image rm 会把 /var/lib/docker下的文件删除,因此进程也会没
需要先停止容器 docker rm container_id/container_name

|

container

命令 描述
docker run [option] image [command] [arg] 启动一个容器
docker ps -a 查看所有容器列表
docker ps 查看正在运行中的容器列表
docker stop containerId 关闭容器
docker start containerId 启动一个已关闭的容器
docker rm containerid 删除容器
docker rm docker ps -a -q 一次性删除所有容器
  • 创建一个container

    • docker run —name myredis -d -p63791:6379 redis (docker的二进制执行文件,run:与前面的docker组合来运行一个容器,指定镜像,如果没有就从docker hub上去获取)

  • -p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口。

  • -v $PWD/conf:/etc/mysql/conf.d:将主机当前目录下的 conf/my.cnf 挂载到容器的 /etc/mysql/my.cnf。
  • -v $PWD/logs:/logs:将主机当前目录下的 logs 目录挂载到容器的 /logs。
  • -v $PWD/data:/var/lib/mysql :将主机当前目录下的data目录挂载到容器的 /var/lib/mysql 。
  • -e MYSQL_ROOT_PASSWORD=123456:初始化 root 用户的密码。

导出

  • docker export (container id) > export.ta
  • docker load —input export.tar/ docker import -m docker export.tar exeport:latest

实际上,即可以用docker load命令来导入镜像存储文件到本地镜像库,又可以用docker import 命令来导入一个快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有历史记录和元数据信息(即保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大,此外,从容器快照文件导入时可以重新指定标签等元数据信息。

image.png

打包

docker save -o tar包的名字 镜像名 #镜像打包
docker load —input my_cuda_docker.tar #载入镜像

cgroup

需要提前安装好libcgroup、 否则无数据

centos

  1. yum install libcgroup

其他

命令 描述
docker system df 查看镜像、容器、数据卷所占用的空间

docker-compose

compose是docker api 的组合

假如 服务更新后、container 随之更新后,compose 将network 和volume的关系保留

更新一个容器时,另外一个容器默认记录的是host,如果直接删除重建,则不会更新。在compose中,一个project里的所有容器都是按照network关系排序的,所以如果有容器更新,相关容器也会对应更新配置。

对于 volume ,compose 会使用一个中间容器来暂时记下 volume ,中间容器先引用旧容器,然后删除旧容器,重新创建容器后,新建的容器就可以通过引用中间容器获得旧容器的volume内容,再删除中间容器。

启动 docker-compose up -d

如果宿主机内已经存在该应用对应的容器,docker-compose将进行行为逻辑判断,判断应用是否更新过

命令 描述
docker-compose up 创建并且启动所有容器
docker-compose up -d 创建并且后台运行方式启动所有容器
docker-compose start xx 启动服务
docker-compose stop xx 停止服务
docker-compose restart xx 重启服务
docker-compose rm xx 删除并且停止xxx容器
docker-compose down 停止并删除容器,网络,图像和挂载卷
  1. version: "3"
  2. services:
  3. mysql:
  4. image: mysql:5.7
  5. ports:
  6. - 33016:3306
  7. command:
  8. - --character-set-server=utf8mb4
  9. - --collation-server=utf8mb4_unicode_ci
  10. - --skip-character-set-client-handshake
  11. - --default-time-zone=SYSTEM
  12. - --log-timestamps=SYSTEM
  13. - --max-connections=10240
  14. environment:
  15. MYSQL_ROOT_PASSWORD: 1234567890///
  16. TZ: Asia/Shanghai
  17. volumes:
  18. - ./sql:/docker-entrypoint-initdb.d
  19. restart: always

dockerfile

Docker inspect imageid 查看docker对象的底层信息

  1. # yun
  2. docker inspect f26e21ddd20d
  3. [
  4. {
  5. "Id": "sha256:f26e21ddd20df245d88410116241f3eef1ec49ce888856c95b85081a7250183d",
  6. "RepoTags": [
  7. "mysql:5.7"
  8. ],
  9. "RepoDigests": [
  10. "mysql@sha256:1a73b6a8f507639a8f91ed01ace28965f4f74bb62a9d9b9e7378d5f07fab79dc"
  11. ],
  12. "Parent": "",
  13. "Comment": "",
  14. "Created": "2022-03-29T18:09:28.935290843Z",
  15. "Container": "e4ddfa2630a08cb042f482bcb161be50fc9a0128d186cd80a6ed435364c715f9",
  16. "ContainerConfig": {
  17. "Hostname": "e4ddfa2630a0",
  18. "Domainname": "",
  19. "User": "",
  20. "AttachStdin": false,
  21. "AttachStdout": false,
  22. "AttachStderr": false,
  23. "ExposedPorts": {
  24. "3306/tcp": {},
  25. "33060/tcp": {}
  26. },
  27. "Tty": false,
  28. "OpenStdin": false,
  29. "StdinOnce": false,
  30. "Env": [
  31. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  32. "GOSU_VERSION=1.14",
  33. "MYSQL_MAJOR=5.7",
  34. "MYSQL_VERSION=5.7.37-1debian10"
  35. ],
  36. "Cmd": [
  37. "/bin/sh",
  38. "-c",
  39. "#(nop) ",
  40. "CMD [\"mysqld\"]"
  41. ],
  42. "Image": "sha256:cfc039f055513751a726c3158898f33437a1898026c914f1b1fd90fe470d237f",
  43. "Volumes": {
  44. "/var/lib/mysql": {}
  45. },
  46. "WorkingDir": "",
  47. "Entrypoint": [
  48. "docker-entrypoint.sh"
  49. ],
  50. "OnBuild": null,
  51. "Labels": {}
  52. },
  53. "DockerVersion": "20.10.12",
  54. "Author": "",
  55. "Config": {
  56. "Hostname": "",
  57. "Domainname": "",
  58. "User": "",
  59. "AttachStdin": false,
  60. "AttachStdout": false,
  61. "AttachStderr": false,
  62. "ExposedPorts": {
  63. "3306/tcp": {},
  64. "33060/tcp": {}
  65. },
  66. "Tty": false,
  67. "OpenStdin": false,
  68. "StdinOnce": false,
  69. "Env": [
  70. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  71. "GOSU_VERSION=1.14",
  72. "MYSQL_MAJOR=5.7",
  73. "MYSQL_VERSION=5.7.37-1debian10"
  74. ],
  75. "Cmd": [
  76. "mysqld"
  77. ],
  78. "Image": "sha256:cfc039f055513751a726c3158898f33437a1898026c914f1b1fd90fe470d237f",
  79. "Volumes": {
  80. "/var/lib/mysql": {}
  81. },
  82. "WorkingDir": "",
  83. "Entrypoint": [
  84. "docker-entrypoint.sh"
  85. ],
  86. "OnBuild": null,
  87. "Labels": null
  88. },
  89. "Architecture": "amd64",
  90. "Os": "linux",
  91. "Size": 449621055,
  92. "VirtualSize": 449621055,
  93. "GraphDriver": {
  94. "Data": {
  95. "LowerDir": "/var/lib/docker/overlay2/7689b91f1de8e2d489f3abcf2b2f7dc8884df7757ba52b52ccfe7c0e07311af2/diff:/var/lib/docker/overlay2/df6a5f553487ff34aac90d9a58b00e1d8c99b10b229d316c3fbf0c7b2a5d6b6e/diff:/var/lib/docker/overlay2/b226b6e5ca38df3e697712656d0cb7ba4bb58078769a2c28fa5b6ec27f0334e3/diff:/var/lib/docker/overlay2/d0191a7cd18fb4b3e900dfec7243f77675df5312ee0232db3a5255bcfde8cc92/diff:/var/lib/docker/overlay2/2f531e3fdb3757dd7e8dfd56b7f704854015dc08f64b36bd76c3c219d862d14d/diff:/var/lib/docker/overlay2/94f1b4d4145b779e83763c9245afebfaa7ebdec2a97eb938202d515694bf502b/diff:/var/lib/docker/overlay2/c3da99e285e614c4abe0cbc0dc4cbcd44907e20df65057178ac8662e917c8a67/diff:/var/lib/docker/overlay2/8309b37f81bbb2f0a1bb6a44b2e02268df42126891070fcf70f568767e9a793d/diff:/var/lib/docker/overlay2/c23c5ebc325e3b6bbb740eaa1aa2e530d550679d23fb9f9b4c4d38e08ac0bc11/diff:/var/lib/docker/overlay2/bafc73782eb7238131935736b13b7f75bb61bd4422a8de27fd17e4ed185ce565/diff",
  96. "MergedDir": "/var/lib/docker/overlay2/b03046741e0ff2e7f63bcaf29b344387e4cbc8a5fe0a48f6bfee4f87f25745d2/merged",
  97. "UpperDir": "/var/lib/docker/overlay2/b03046741e0ff2e7f63bcaf29b344387e4cbc8a5fe0a48f6bfee4f87f25745d2/diff",
  98. "WorkDir": "/var/lib/docker/overlay2/b03046741e0ff2e7f63bcaf29b344387e4cbc8a5fe0a48f6bfee4f87f25745d2/work"
  99. },
  100. "Name": "overlay2"
  101. },
  102. "RootFS": {
  103. "Type": "layers",
  104. "Layers": [
  105. "sha256:c1065d45b8722a4385f2ee26116e1859e8083400ee00d2beff3fdd5225bfeee9",
  106. "sha256:83798bb6445214513e2589ebab004b2af82f0101658da8a41cf1131df63b150d",
  107. "sha256:726b89cb4adb8db4c0cec64a65e15a33ba6a294ccd6af27e14eadc4aefa4f994",
  108. "sha256:f8589c04a7c47e8ae26f3c7ff8b8ef74c4e97f5de9155be718d227ffac9f8e33",
  109. "sha256:a6139270daa5aab16d11ee34343e9dd2d75ae1f9bf3bb8638529dc157c6acd46",
  110. "sha256:bcdcddd1968e5e05efe31aabeff2385294ce11e49bb0a8c00d839501a90f858e",
  111. "sha256:f1ce24a3a9062c96a2cc0a2ace9b2c4313bb03ff8742d29b893143a7020ac16f",
  112. "sha256:1d7715d4a101f703f46b5f9b9167a7c174e94417b57318470cfb76e3f3de1436",
  113. "sha256:48864d05ba7cad27ba807b43755d91c5bf816472cbbfd72c9b55b0f06b06d0b6",
  114. "sha256:f13c8c3263cd1b2c1c698d279a6c2d91c4c4a260ecc7c1b659b7efe8826b8753",
  115. "sha256:30682fca5ffe48b1c9655ebec39fb1307c7965aa3760997e41eec1657dd5b1cb"
  116. ]
  117. },
  118. "Metadata": {
  119. "LastTagTime": "0001-01-01T00:00:00Z"
  120. }
  121. }
  122. ]
  • 查看container的 元数据
    • docker inspect containerId
    • 取数据 docker inspect —format=’{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’ mysql
    • 上诉简化版本 docker inspect mysql | grep IPAddress
  • 日志路径
    • docker inspect —format=’{{.LogPath}}’ mysql

与宿主机共享文件

  • docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH


*eg: 将宿主机文件copy到容器

docker cp .bashrc c3683fd8ea59:/tmp/

镜像打包/加载

  • 查看镜像 docker images |grep ubuntu
  • 打包镜像 docker save -o /tmp/ubuntu.16.04.tar ubuntu
  • 删除镜像 docker rmi ubuntu
  • 确认镜像已删除 docker images |grep ubuntu
  • 使用打包好的文件加载镜像 docker load -i /tmp/ubuntu.16.04.tar
  • 确认加载成功 docker images |grep ubuntu

dockerfile

我们可以使用dockerfile 文本方式来告诉docker如何根据我们自定义的方式来构建我们所需要的镜像

Docker 通过 读取dockerfile 文件里的指令来自动构建镜像。dockerfile 中为了要构造指定镜像需要包含所有的命令,docker镜像由只读层组成。每一层表示一个Dockerfile 命令。层是叠堆的,每个层都是上一层变化的增量。

指令 描述
FROM 初始化一个新的构建阶段并为下面的指令设置一个基础镜像,一个有效的dockerfile必须以一个FROM开头,
ENV ENV key = value,ENV 指令设置变量key的值为value,设置的变量将为接下来构建阶段的指令使用。
RUN 在当前镜像的最新一层执行指令并提交执行结果,提交的结果镜像将被用于Dockerfile中的下一步,
CMD 一个Dockerfile中只能存在一个CMD指令,如果使用了超过一个CMD命令,那么只有最后一个CMD指令会生效
COPY 该指令用于从远路径复制文件或者目录到容器中的目的的路径 COPY . /app
WORKDIR 用于配合 RUN,CMD,ENTRYPOINT 命令设置当前工作路径。设置 /app 路径 WORKDIR /app
ENTRYPOINT ENTRYPOINT 可以让你的容器表现得像一个可执行程序一样。一个 Dockerfile 中只能有一个 ENTRYPOINT,如果有多个,则最后一个生效。 将 Python 镜像变成可执行的程序
  1. FROM python:3.9
  2. MAINTAINER Rolle <i@liangyouze.com>
  3. COPY . /appWORKDIR /app
  4. RUN pip install -r requirements.txt
  5. EXPOSE 5000
  6. ENTRYPOINT ["python"]
  7. CMD ["app.py"]
  • 从 Docker Hub 上 Pull 下 Python 2.7 的基础镜像。
  • 显示维护者的信息。
  • Copy 当前目录到容器中的 /App 目录下 复制本地主机的 ( Dockerfile 所在目录的相对路径)到容器里 。
  • 指定工作路径为 /App。
  • 安装依赖包。
  • 暴露 5000 端口。
  • 启动 App。

例如:

创建一个文本文件,命名为Dockerfile

  1. FROM nginx
  2. RUN echo 'hello world' >/usr/share/nginx/html/index.html

构建镜像 > docker build -t nginx:v4 .
创建容器 docker run -p 12841:80 -d nginx:v4 (端口映射,本地的12841 映射为容器的80)
访问 http://localhost:12841