docker学习笔记

1. docker安装

可以从以下地址下载并安装docker,Linux,Windows,MacOS均支持:

Docker 安装完成后,可以直接打开终端执行:

bash 复制代码
docker run hello-world

输出如下信息:

powershell 复制代码
Hello from Docker!
This message shows that your installation appears to be working correctly.
 
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
 
To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash
 
Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/
 
For more examples and ideas, visit:
 https://docs.docker.com/get-started/

通过上述 hello-world 镜像运行起来的容器,输出了一个容器的运行步骤:

  • Docker 客户端与 Docker 服务端建立连接,告知服务端需要使用 hello-world 镜像运行一个容器
  • Docker 服务端从 Hub 仓库拉取与当前宿主机相同架构的镜像 hello-world
  • Docker 服务端运行一个 hello-world 容器,执行容器中的 hello-world 程序
  • Docker 服务端将 hello-world 程序输出的内容打印到控制台

2. docker架构

Docker 包括三个基本概念:

  • 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  • 仓库(Repository):仓库可看成一个文件存储中心,用来保存镜像。

镜像 与 容器 的关系?

镜像(image)是一个压缩包,镜像通过 Docker Daemon 进程解压拉起(run)得到容器(container).

Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。

3. 容器和虚拟机的区别

虚拟化技术是由Hypervisor真正的创建了一个虚拟机,有以下特点:

  • 要运行真实的操作系统后才能执行应用进程,Guest OS本身就会带来资源的消耗
  • 应用进程对CPU、网络、磁盘IO的系统调用都要经过虚拟软件的拦截和处理;

容器化技术的特点:

  • 容器中的应用进程本身就是宿主机上的一个普通进程,系统调用不会带来额外的资源消耗,也不需要运行额外的Guest OS;

所以容器化技术相对于虚拟化技术的优势是敏捷和高性能。但有利就有弊,弊端在于隔离不彻底,主要表现为:

  1. 容器化的进程是共享宿主机内核,所以跨操作系统是不被支持的,例如CentoOS、Ubuntu、Windows不共融;
  2. 有些资源和对象是不能被namespace的,例如:时间,所以容器化部署的应用需要清楚哪些能做,哪些不能做。

4. 容器化技术理解

容器就是一种沙盒技术,一种把应用进程装进集装箱的技术,应用与应用之间因为有了边界而不会相互干扰,同时应用被装起来后也方便搬运和迁移 。

容器技术的核心功能,就是做到两点:

  1. 约束进程的资源边界,使用linux中的Cgroups技术;
  2. 修改进程的动态视图,使用linux中的Namespaces技术;

容器文件系统:rootfs

  • 一个操作系统的所有文件和目录,不包括内核
  • 容器化时挂载在容器根目录上,用于为进程提供隔离执行环境的文件系统。
  • chroot命令可以改变进程的根目录到指定的位置

docker与k8s的区别:

  • Docker:是一个容器运行时,拉取镜像、运行容器
  • K8s:重心在容器编排,它的观点是运行在大规模容器中的各种任务之间是有关系的,所以它从更宏观的角度,以统一的方式来定义任务之间的各种关系,而像Docker这样的容器运行时只是作为一个底层设施。

5. Namespaces

作用:从视图中隔离应用进程的可视范围,包括网络、文件、CPU、进程、用户等。

隔离进程空间要达到的效果:

  • 在宿主机中启动一个进程时,操作系统会分配一个进程编号PID(例如100),这个PID是进程的唯一标识;
  • 在Docker容器中,启动的进程只能看到当前应用一个进程,并且PID是重新计算过的,一般编号为1。

为了做到这点,就需要为应用设置一个隔离的进程空间,而namespaces就恰好能做到这点,它的原理如下:

  • 在clone函数创建进程的系统调用中添加一个参数CLONE_NEWPID,这样新创建的这个进程将会看到一个全新的进程空间,在这个进程空间中当前进程的PID=1。
cpp 复制代码
int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); 

实际上,namespaces只是对被隔离应用的进程空间做了手脚,使得这些进程只能看到重新计算过的进程编号1,而实际上在宿主机操作系统里,进程编号还是100,相当于一个碍眼法。

namespaces有很多种,除了上面提到的pid namespace外,还有下面几种:

  • Mount Namespace:用于让被隔离进程只看到当前namespace里的挂载点信息;
  • Network namespace: 用于让被隔离进程只看到当前namespace里的网络设备和配置;
  • UTS namespace: 提供主机名隔离能力;
  • IPC namespace: 提供进程间通信的隔离能力;
  • User namespace: 提供用户隔离能力。

6. Cgroups

namespaces只能隔离应用进程的可视范围,却并不能真正限制进程所能使用的资源。例如:

一个namespace中只能看到1G的内存,但它真实运行时却能占用整个宿主机的内存。

所以需要一个机制来限制进程能使用的资源上限,它就是Cgroups(全称是Linux Control Group),能限制的资源包括CPU、磁盘、内存、网络带宽等。

Cgroups 给用户暴露出来的操作接口是文件系统,位于/sys/fs/cgroup目录下,用以下命令可以展示内容:mount -t cgroup

上面截图中列出的这些子系统就是cgroup支持限制的资源种类。

下面拿CPU举例来说明如何使用(目录位于/sys/fs/cgroup/cpu):

  1. 在子系统中创建一个控制组:root@ubuntu:/sys/fs/cgroup/cpu$ mkdir user.slice, 操作系统会在新目录中自动生成对应的配置文件;
  2. 对于CPU来说主要由两个关键参数来控制:cfs_periodcfs_quota,用来限制进程在cfs_period长的时间内,最多能被分到cfs_quota的CPU时间;
  3. 在user.slice下面的tasks文件中写入进程的PID,这样container控制组的限制就只对指定的进程生效。

除CPU外,还有以下子系统分别对进程作不同的限制 :

  • blkio: 为块设备设定IO限制
  • memory: 为进程设定内存使用的限制
  • cpuset: 为进程分配单独的CPU核和内存节点

7. 镜像构建

7.1 Dockerfile

镜像一般通过Dockerfile进行构建,它是一个用来声明镜像构建过程的文件。下面是一个示例:

bash 复制代码
FROM ubuntu:20.04               # 指定基础镜像文件                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
COPY uc/sbin/ /uc/sbin/         # 拷贝应用程序文件
USER root   EXPOSE 8051 18051   # 指定用户、暴露应用进程端口
ENTRYPOINT ["./docker_start.sh"]# 指定镜像中的应用启动入口

Dockfile常用的指令有:

指令 描述
FROM 指定基础镜像,例如 FROM ubuntu:20.04
LABEL 给新镜像打标签,便于过滤,方便理解,起到备注注释的作用
RUN 在新镜像中做一些指令操作,可以理解为执行一些 shell 命令,如 mkdir, apt-get, cp 等
CMD 类似 RUN ,定义容器启动时执行的指令,或者作为参数提供给 ENTRYPOINT 指令。如果定义多个CMD,则仅最后一个有效。CMD指令可以被 docker run image param1 param2 后面的参数覆盖
ENTRYPOINT 定义容器启动指令,类似于 CMD 指令,但其不会被 docker run 的命令行参数所覆盖。可以使用 docker run image --entrypoint 选项来覆盖 ENTRYPOINT 指令指定的程序
EXPOSE 声明容器启动会使用的端口,仅仅供人查看而已。作用:帮助镜像使用者理解这个镜像使用的端口,以方便配置映射。在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口
ENV 定义环境变量,在后续的指令中,就可以使用这个环境变量(包括启动容器后)
ARG 类似ENV,但作用域不同,仅在构建镜像时有用,容器运行时不存在,可以放置在FROM前,可以被 --build-arg key=value 覆盖
COPY 复制指令,从上下文目录中复制文件或者目录到容器里指定路径,例如:COPY sayHi /uc/bin/sayHello
ADD 同COPY,比COPY多了:支持拷贝 远程url地址文件 至镜像中;压缩包会被自动解压缩。同等需求下,建议采用COPY
VOLUME 声明容器要使用的挂载点,便于使用者理解镜像的关键数据存储位置。如果没有指定则会自动挂载到匿名卷,这个匿名卷难以查找。
WORKDIR 指定工作目录,以后各层的当前目录就被改为指定的目录,可以将WORKDIR理解为 cd 命令。
USER 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

7.2 上下文

Dockerfile 所在的当前目录就是容器构建的上下文,它的作用体现在:

  • COPY 指令只能拷贝构建上下文中的文件或目录;
  • 上下文中的数据默认都会复制一份传输给 docker-daemon,所以上下文所在目录要尽可能小,以加速构建;
  • .dockerignore 可用于声明要忽略的文件,这里声明的文件不需要传输,类似于.gitignore
bash 复制代码
.git
src
*.war
*.jar

7.3 镜像分层

Docker镜像是分层构建的,Dockerfile 中每条指令可能都会新建一层。例如以下 Dockerfile:

bash 复制代码
FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py
  • 以上四条指令会创建四层,分别对应基础镜像、复制文件、编译文件以及入口文件;
  • 每层只记录本层所做的更改,而这些层都是只读层;
  • 当你启动一个容器,Docker 会在最顶部添加读写层;
  • 你在容器内做的所有更改,如写日志、修改、删除文件等,都保存到了读写层内,一般称该层为容器层。

说明:也不是每一行指令都产生新层,只有那些修改了文件系统的命令才会产生新的镜像层,例如RUN、COPY之类。

7.4 镜像构建

# 当前目录结构 tree
/tmp/test-v1
- Dockerfile
- Dockerfile2
- a.log
 
# 切换到目录
$ cd /tmp/test-v1
 
# 在当前目录下构建 test:v1 镜像
$ docker build -t test:v1 .
 
# 使用 Dockerfile2 构建镜像
$ docker build -t test:v2 -f Dockerfile2 .
 
# 添加完整的镜像路径(用于私有或第三方仓库)
$ docker build -t hub-ali.quanshi.com/repotest/test:v3 .

8. 镜像仓库

镜像仓库分为如下几类:

  1. 中央仓库:https://hub.docker.com/, 仓库上的镜像来源有

    • 官方镜像, Docker公司提供的镜像
    • 经过验证的发布者,大厂或机构
    • 开源社区,开源软件组织
    • 其他小厂或个人
  2. 第三方仓库,其他公司或者机构提供的免费或付费的仓库

    • 阿里云ACR:https://help.aliyun.com/zh/acr/
    • 腾讯云TCR:https://cloud.tencent.com/document/product/1141/39278
    • 其他
  3. 私有仓库,个人或公司自己搭建的供公司内部使用的仓库

    • registry, 官方提供的私有仓库软件
    • harbor, 基于 registry 包装的更加好用的私有仓库软件
    • 其他
  4. 本地仓库,在机器本地镜像存放的仓库

中央仓库和私有仓库在使用时有些许区别:

  • 中央仓库在拉取镜像时是不需要添加域名的,可以直接
bash 复制代码
docker pull busybox
  • 私有仓库和第三方仓库拉取镜像需要使用域名(默认只支持 https ,不需要带协议字段)
bash 复制代码
docker pull hub-ali.quanshi.com/infra/busybox

如果需要 http 或直接 ip 方式访问,需要给 docker 配置免安全校验,见下:

bash 复制代码
# 编辑 /etc/docker/daemon.json, 加入 insecure-registries 字段
{
  "insecure-registries" : ["test.hub.com", "192.168.11.11"]
}

配置镜像加速

bash 复制代码
# 编辑 /etc/docker/daemon.json, 加入registry-mirrors 字段

{
  "registry-mirrors": ["https://fv743jei.mirror.aliyuncs.com"],
}
# 更多可用镜像加速方案参照:https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6

9. 常用命令

指令 描述
docker-compose up 创建并启动容器,通过-f参数来指定yaml容器配置,例如:docker-compose -f /meetconf.yml up uniformserver -d
docker commit 通过容器创建镜像
docker cp 容器与本地目录相互拷贝文件
docker exec 在容器中执行命令,例如进入容器:docker exec -it 容器id /bin/bash
docker logs 查看容器控制台日志输出,例如:docker logs -f sqlproxy
docker ps 获取正在运行的容器,-a 获取所有容器(包含已停止的)
docker rm [容器ID] 删除已停止的容器,加上-f表示删除正在运行的容器
docker stop [容器ID] 停止正在运行的容器
docker build 通过 Dockerfile 构建镜像
docker history 查看镜像构建历史,如docker history nginx:v1
docker images 列出镜像
docker inspect [容器ID] 显示镜像或容器的详细信息
docker load 加载镜像到本地仓库
docker pull 从镜像仓库拉取镜像
docker push 推送镜像到镜像仓库
docker rmi 移除镜像
docker save 保存镜像到一个tar文件
docker tag 镜像更改标签名称

参考阅读

相关推荐
今天我又学废了16 分钟前
Scala学习记录,List
学习
幸运超级加倍~19 分钟前
软件设计师-上午题-16 算法(4-5分)
笔记·算法
王俊山IT39 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
ZHOU西口1 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
Mephisto.java1 小时前
【大数据学习 | kafka高级部分】kafka中的选举机制
大数据·学习·kafka
Yawesh_best2 小时前
思源笔记轻松连接本地Ollama大语言模型,开启AI写作新体验!
笔记·语言模型·ai写作
南宫生2 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
武子康3 小时前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
CXDNW3 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙3 小时前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型