跳至主要內容

Docker - 2

code中间件Docker约 2115 字大约 7 分钟

Docker

Docker 本质:

Docker = 创建隔离进程 + 资源管理 + 网络/文件映射

容器就是进程

  • 容器内的应用进程直接运行在宿主机内核上
  • 容器 ID 本质上就是一组经过特殊配置的进程
  • 这些进程通过 Linux 的 namespaces 和 cgroups 实现隔离
宿主机视角:
  PID 1001: nginx 主进程  ← 这就是一个"容器"
  PID 1002: nginx worker
  ...

容器视角:
  PID 1: nginx 主进程
  PID 2: nginx worker
  ...

基本概念

Docker 包括三个基本概念

  • 镜像(Image)
  • 容器(Container)
  • 仓库(Repository)

镜像

操作系统分为 内核 和 用户空间

对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持

而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统

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

容器

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

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

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

容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机

仓库

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务

一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像

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

以 Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest

完整 Ubuntu 操作系统 = Linux 内核 + Ubuntu 用户空间

Docker 中的 ubuntu 镜像 = Ubuntu 用户空间(只有根文件系统)

因为 Linux 内核是向下兼容的:

Ubuntu 18.04 的用户空间程序可以在任何较新的 Linux 内核上运行 容器内的程序通过系统调用与宿主机内核通信 只要内核 API 兼容,就能正常运行

仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务

基本使用

容器是操作系统级别的虚拟化,不需要运行完整的操作系统,启动和运行更为高效

镜像操作

# 拉取镜像
docker pull ubuntu:20.04
docker pull nginx:latest

# 查看本地镜像
docker images

# 删除镜像
docker rmi <image_id>

# 搜索镜像
docker search nginx

容器操作

# 启动容器
docker run ubuntu:20.04
docker run -it ubuntu:20.04 /bin/bash  # 交互式终端

# 常用参数
docker run -d nginx              # 后台运行
docker run -p 8080:80 nginx      # 端口映射(宿主机 8080 -> 容器 80)
docker run -v /data:/app/data    # 挂载卷
docker run --name my-container   # 指定容器名
docker run --rm                  # 退出后自动删除

# 查看容器
docker ps                        # 运行中的容器
docker ps -a                     # 所有容器(包括已停止)

# 控制容器
docker start <container_id>
docker stop <container_id>
docker restart <container_id>
docker kill <container_id>

# 删除容器
docker rm <container_id>
docker rm -f <container_id>      # 强制删除运行中的容器

进入容器

# 进入运行中的容器
docker exec -it <container_id> /bin/bash

# 查看容器日志
docker logs <container_id>
docker logs -f <container_id>    # 实时跟踪

构建镜像

# 从 Dockerfile 构建
docker build -t my-image:1.0 .

# 从容器提交
docker commit <container_id> my-image:1.0

示例

# 运行 Nginx
docker run -d -p 80:80 --name web nginx

# 运行 MySQL
docker run -d -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=123456 \
  --name mysql mysql:8.0

# 运行 Redis
docker run -d -p 6379:6379 --name redis redis

# 查看资源使用
docker stats

清理

# 删除所有停止的容器
docker container prune

# 删除所有悬空镜像
docker image prune

# 一键清理所有未使用的资源
docker system prune

Docker Dockerfile

Dockerfile 是一个文本文件,包含了构建 Docker 镜像的所有指令。

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

通过定义一系列命令和参数,Dockerfile 指导 Docker 构建一个自定义的镜像

基本结构

# 1. 指定基础镜像
FROM ubuntu:20.04

# 2. 设置维护者信息
LABEL maintainer="your@email.com"

# 3. 设置工作目录
WORKDIR /app

# 4. 复制文件到镜像
COPY . /app

# 5. 安装依赖
RUN apt-get update && apt-get install -y python3

# 6. 设置环境变量
ENV NODE_ENV=production

# 7. 暴露端口
EXPOSE 3000

# 8. 启动命令
CMD ["node", "app.js"]
Docker面向对象
docker build类(Class) 定义
docker run根据类创建实例(Object)

构建镜像

在 Dockerfile 文件的存放目录下,执行构建动作

docker build -t my-app:1.0 .

最后的 . 代表本次执行的上下文路径

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包

运行容器

# 步骤 1:构建镜像
docker build -t my-app:1.0 .
# ↓ 镜像存储在本地

# 步骤 2:查看镜像
docker images
# REPOSITORY    TAG
# my-app        1.0

# 步骤 3:运行容器
docker run -d -p 3000:3000 my-app:1.0
# ↓ 现在应用才真正跑起来

# 步骤 4:查看运行中的容器
docker ps

Docker Compose

Docker Compose 是用来管理多个容器的工具,用 YAML 文件定义一组相关的容器,一键启动/停止

通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行 docker-compose up 命令来启动并运行整个应用程序

基本结构

# docker-compose.yml
version: '3.8'

services:
  # Web 应用
  app:
    build: .                    # 从当前目录 Dockerfile 构建
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:                 # 依赖,先启动
      - db
      - redis
    volumes:
      - ./src:/app/src          # 代码挂载,开发时自动重载
  
  # 数据库
  db:
    image: postgres:14
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
  
  # 缓存
  redis:
    image: redis:7
    ports:
      - "6379:6379"

volumes:
  pgdata:  # 命名卷,数据持久化

常用命令

# 启动所有服务(后台运行)
docker-compose up -d

# 停止所有服务
docker-compose down

# 查看运行状态
docker-compose ps

# 查看日志
docker-compose logs
docker-compose logs -f web    # 跟踪某个服务

# 重启服务
docker-compose restart web

# 进入某个服务容器
docker-compose exec web bash

# 重新构建并启动
docker-compose up -d --build

# 一键清理(删除容器、网络、镜像)
docker-compose down -v
上次编辑于: