docker入门课程

吴书松
吴书松
发布于 2026-06-07 / 13 阅读
0

docker入门课程

1、目录

  • docker基本概念入门

    • 1.1、容器是什么?

    • 1.2、容器和虚拟机的区别

    • 1.3、主流容器技术概念

    • 1.4、Docker概念:镜像、容器,仓库,各个组件等

    • 1.5、Docker安装

    • 1.6、Docker运行一个Demo

  • 容器编排技术:docker compose

  • 制作镜像DockerFile

  • 容器本地仓库搭建:registry/Harbor

  • Docker swarm 容器集群管理工具

  • k3s搭建(3主3从+内部集成ETCD)

  • k3s继承kuboard

  • k3s部署微服务,支持动态扩容节点(actuator+Prometheus)

  • k3s+springboot+本地仓库+actuator+Prometheus案例

2、容器是什么

  • 定义:容器是操作系统级别的虚拟化技术。它允许你在共享宿主机内核的同时,运行多个相互隔离的用户空间实例。

  • 运维黑话解释:

    • 是一个进程级别的“沙箱”。

    • 不是一个完整的OS,只是一个被“伪装”成独立系统的进程。

    • 类比: 容器就像公寓楼里的单间公寓(共享大楼地基和电梯,但房间内独立装修)。

一句话总结:换句话说,就是运行在宿主系统上、共享宿主系统资源的,进程级别的一个不完整的OS系统。

3、容器与常见虚拟机的区别

比如:VmWare、Proxmox VE(KVM/LXC)等

这几个都是虚拟化技术的落地,认为“都是跑应用的隔离环境”。 但从技术底层看,它们的隔离边界、资源利用率和启动逻辑截然不同。

区别就在于下面几点:

3.1、核心本质:共享内核 vs 独立内核

  • 虚拟机:模拟的是完整的硬件——CPU、内存、硬盘、网卡,甚至主板芯片组。每个虚拟机都包含一个独立的客户操作系统(Guest OS),这个 OS 拥有自己完整的内核。

    • VMware:Type-2 或 Type-1 混合模型,重点在硬件全虚拟化

    • PVE(Proxmox VE):基于 KVM(Linux 内核虚拟化模块),同样是硬件级虚拟化

  • 容器:容器没有自己独立的内核。所有容器共享宿主机的内核。每个容器只是一个进程级别的隔离环境,通过 Linux 内核的 Namespace 和 Cgroups 技术实现:

    • Namespace:让每个容器看到自己独立的进程树、网络栈、文件系统、用户 ID 等(隔离视角)

    • Cgroups:限制每个容器能使用的 CPU、内存、磁盘 IO 等物理资源(限制用量)

一句话总结:虚拟机虚拟的是硬件,容器虚拟的是操作系统接口(系统调用)。

3.2、启动速度与资源占用:秒级 vs 分钟级

特性

容器(Docker)

虚拟机(VMware/KVM)

启动时间

毫秒~秒级(本质是进程启动)

几十秒到分钟(需要引导整个 OS)

内存占用

MB 级别(共享内核 + 精简镜像)

GB 级别(每个 VM 要有完整 OS)

磁盘占用

几十 MB 到几百 MB(无 OS 内核)

数 GB 到数十 GB

实例密度

一台物理机可运行数百甚至上千容器

一般几十个 VM 已接近极限

假设你有一个 16 核 32GB 的服务器:

  • 跑 Docker:轻松跑几百个相互隔离的小服务(例如微服务架构)

  • 跑 VMware:跑 10~20 个常规 Linux 虚拟机就比较吃力了

3.3、隔离级别与安全性

虚拟机:硬件级隔离。一个虚拟机里的内核崩溃、恶意驱动、甚至蓝屏,绝对不会影响其他虚拟机或宿主机。这是银行、政务、多租户云主机首选的原因——安全边界非常清晰。

容器:进程级隔离。所有容器共享同一个宿主机内核,如果某个容器内的应用利用内核漏洞提权,理论上可以威胁到宿主机和其他容器。虽然 Docker 有 Capabilities、Seccomp、AppArmor 等加固手段,但隔离强度仍不如虚拟机

3.4、可移植性与交付方式

Docker 的优势领域:封装应用及其依赖(库、配置文件、环境变量),但不包括内核。一个 Docker 镜像可以在任何支持 Docker 的 Linux 发行版上运行(内核版本兼容即可)。开发环境、测试环境、生产环境一致性极佳。

虚拟机镜像:包含了完整 OS 和应用,体积巨大。跨平台迁移(比如从 VMware 到 KVM)通常需要格式转换(如 OVF/OVA),且可能遇到硬件驱动兼容问题。

虚拟机是“物理计算机的软件模拟”,每个虚拟机自备操作系统内核;容器是“操作系统之上的进程沙盒”,所有容器共享宿主机内核,但彼此看不见。

4、各种容器技术对比

4.1、容器和Docker关系

我们经常说到容器技术,首先想到的就是Docker,那么Docker和容器是对等的吗,他们是什么关系

  • 容器是一种虚拟化的技术,指利用Linux内核的Namespace(隔离视角)和Cgroups(限制资源)实现的进程级隔离环境。这是操作系统自带的能力,不是Docker发明的。

  • Docker是一个容器管理工具,它把底层容器技术封装成好用的镜像构建、分发、运行体验。

4.2、Docker与其他工具对比(Podman、Containerd)

特性

Docker

Podman

Containerd

定位

完整的容器平台(开发+运维)

无守护进程的Docker替代品

工业级容器运行时核心

架构

有中心守护进程(dockerd)

无守护进程,直接fork容器进程

被Docker/K8s底层使用的运行时

是否兼容Docker CLI

原生

可直接别名alias docker=podman

不支持(需要crictl或nerdctl)

是否支持Kubernetes

已弃用dockershim(需cri-dockerd)

原生支持Pod和K8s YAML

K8s默认CRI运行时

root权限要求

默认需要root

支持rootless

需配合其他组件

适用场景

开发环境、小规模生产

安全性要求高的生产环境

K8s集群节点运行时

简单总结:

  • Docker:功能最全,用户体验最好,适合开发和测试,以及中小规模部署

  • Podman:无守护进程、支持rootless,安全性更好,红帽系生产环境常见

  • Containerd:只管跑容器,不管镜像构建和网络等,Kubernetes的标配底层

用一句话记忆:Docker是瑞士军刀,Podman是安全版Docker,Containerd是K8s背后的隐形冠军。

4.3、Docker概念

Docker有很多概念:镜像、容器、Network、Volume

我们以面向对象变成的类-对象的概念,来理解镜像和容器的概念

4.3.1、镜像

可以理解成:类

镜像是一个只读的、静态的文件包,里面包含:

  • 一个精简的操作系统文件系统

  • 应用程序代码

  • 依赖的库、环境变量

  • 启动命令的默认参数

关键特性:

  • 只读,不能修改

  • 分层构建(UnionFS),多个镜像共享底层,节省空间

  • 可以存储在Registry中(如Docker Hub)

类比:镜像就像Java里的class文件,它是一个定义,不能直接运行。

4.3.2、容器

可以理解成:对象

当你执行docker run时,Docker会:

  1. 加载镜像的只读层

  2. 在最上面加一个可写层(Container Layer)

  3. 通过Namespace和Cgroups隔离成独立进程环境

这个正在运行的、带可写层的实例,就叫容器。

关键特性:

  • 顶层可写,底层镜像只读

  • 有状态(运行中、停止、退出)

  • 删除容器后,可写层数据丢失(除非用卷)

类比:容器就像new出来的对象,可以运行、修改、销毁。同一个镜像可以创建无数个容器。

4.3.3、Network

容器之间是一个封闭的简易版OS,Network是用来打破容器的网络隔离,换句话说,Network是用来给容器通网的(拥有自己的IP)

外部用户,是无法直接访问容器内部应用的,需要通过Network的不同网络模式进行访问

Network有四种网络模式

网络模式

说明

适用场景

bridge(默认)

容器通过虚拟网桥连接宿主机,端口映射对外暴露

单机运行多个容器,对外提供服务

host

容器直接使用宿主机网络栈,无隔离

对网络性能要求极高,不推荐常规使用

none

无任何网络配置,完全隔离

不需要网络的离线任务

container

共享另一个容器的网络栈

调试、代理、sidecar模式

overlay

docker network create --subnet=192.160.1.0/24 --gateway=192.160.1.1 wss-cloud-network
--driver

4.3.4、Volume(卷)

容器是一个封闭隔离的简易版OS,我们可以将各种应用,运行在这个封闭的OS上面,那么应用产生的各种数据,都会存储在这个OS中,当我们删除容器,或者容器异常的时候,数据就会丢失。

那么Volume就是用来解决容器数据丢失问题,是Docker管理的、独立于容器生命周期的数据存储区域。

  • 它可以挂载容器的某个目录(如 /var/lib/mysql

  • 容器写入这个目录的数据,实际写到了Volume里

  • Volume实际存储在宿主机的指定位置(/var/lib/docker/volume)删除容器,Volume还在;重新创建容器,挂载同一个Volume,数据恢复

三种挂载方式对比

类型

存储位置

适用场景

命令示例

Volume(推荐)

docker volumes 管理的位置

生产数据、数据库、配置

-v mydata:/data

Bind Mount

宿主机任意绝对路径

开发环境代码同步、配置文件注入

-v /host/path:/container/path

tmpfs

内存(仅Linux)

临时敏感数据

--tmpfs /tmp

docker volume create my-redis-volume

5、Docker安装

我这里采用离线安装的方式(线上大多数都是离线环境,无法直接访问外网)

https://download.docker.com/linux/static/stable/

# wget  https://download.docker.com/linux/static/stable/x86_64/docker-20.10.23.tgz
# tar zxvf docker-20.10.23.tgz 
# cp docker/* /usr/bin/
# vim /etc/systemd/system/docker.service  (创建配置文件)

配置内容如下

[Unit] 
Description=Docker Application Container Engine 
Documentation=https://docs.docker.com 
After=network-online.target firewalld.service 
Wants=network-online.target 
[Service] 
Type=notify 
ExecStart=/usr/bin/dockerd --selinux-enabled=false --insecure-registry=127.0.0.1 
ExecReload=/bin/kill -s HUP $MAINPID 
LimitNOFILE=infinity 
LimitNPROC=infinity 
LimitCORE=infinity 
TimeoutStartSec=0 
Delegate=yes 
KillMode=process 
Restart=on-failure 
StartLimitBurst=3 
StartLimitInterval=60s 
[Install] 
WantedBy=multi-user.target

继续执行如下命令:

# chmod +x /etc/systemd/system/docker.service
# systemctl daemon-reload
# systemctl start docker
# systemctl enable docker
# docker --version
Docker version 20.10.23, build 7155243

6、运行一个简单的例子

这里部署一个redis为例

docker run -d --name redis --restart unless-stopped --network my-network -p 16379:6379 -v my-redis-volume:/data --cpus=1 --memory=512m --memory-swap=512m --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 docker.1ms.run/library/redis:7.2 redis-server --requirepass 123456 --bind 0.0.0.0 --protected-mode no
docker run -d --name redis --log-opt max-size=10m --log-opt max-file=3 -m 512m --cpus=2 --restart unless-stopped -p 6379:6379 -v ~/redis/data:/data -v ~/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf:ro 08567fe300e8 redis-server /usr/local/etc/redis/redis.conf --bind 0.0.0.0 --requirepass 123456

也可以自定义配置文件

mkdir -p /opt/redis/conf
cat > /opt/redis/conf/redis.conf << 'EOF'
# 基础配置
requirepass 123456
bind 0.0.0.0
protected-mode no
port 6379

# AOF 持久化配置(你要的 aop -> AOF)
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# RDB 持久化配置(可选,作为补充备份)
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb

# 数据目录(与 volume 映射对应)
dir /data

# 内存配置(限制 400MB 给 Redis 数据,留 112MB 给系统)
maxmemory 400mb
maxmemory-policy allkeys-lru

# 日志配置
loglevel notice
logfile ""

# 性能优化
tcp-backlog 511
timeout 0
tcp-keepalive 300
databases 16
EOF
docker run -d \
  --name redis \
  --restart unless-stopped \
  --network jm-network \
  -p 16379:6379 \
  -v my-redis-volume:/data \
  -v /opt/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf:ro \
  --cpus=1 \
  --memory=512m \
  --memory-swap=512m \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  docker.1ms.run/library/redis:7.2 \
  redis-server /usr/local/etc/redis/redis.conf

:ro 只读挂载,防止容器内误修改配置 protected-mode(保护模式) 是 Redis 的一个安全机制,默认是 yes(开启)。

它的设计目的是:防止 Redis 意外暴露在公网上被未授权访问。

当以下 三个条件同时满足 时,保护模式会生效:

条件 说明

  1. protected-mode yes 保护模式开启(默认)

  2. 没有配置 bind 指令 Redis 监听所有网络接口(0.0.0.0)

  3. 没有配置密码(requirepass) 无需认证即可访问 三个条件缺一不可。 只要配置了 bind 或设置了密码,保护模式不会制造麻烦。