Docker 进阶教程

同步更新至个人站点:Docker 进阶指南 - 容器管理与多服务编排实战 | CellStack

在上一篇文章Docker 入门教程里,我们用 docker builddocker run 命令,成功地将一个应用放进了容器里并运行起来。这感觉很棒,就像 hello world 一样。

但是,hello world 之后,我们总会好奇背后的秘密。而且,只靠这两个命令,还远远无法应对真实的工作场景。你可能马上就会遇到一连串新的问题:

  • 容器在后台运行,我怎么知道它里面发生了什么?如何查看日志?
  • 如果应用卡死了,或者我想暂时关闭它,该怎么操作?
  • 我的应用不是孤立的,它需要连接数据库。数据库也放在容器里吗?两个容器如何"对话"?
  • 每次启动应用都要敲一长串 docker run 命令,参数又多又难记,有没有更简单的方法?

这些问题,才是我们日常工作的核心。今天,我们就来逐一攻克它们,让 Docker 从一个"有趣的玩具"变成我们手中"可靠的工具"。

掌控容器:生命周期管理

首先,我们要学会如何管理一个正在运行的容器。

假设我们用上一篇的命令启动了一个 Go 服务器: $ docker run -d -p 8080:8080 --name go-server go-hello-server:1.0

  1. 查看正在运行的容器 docker ps 命令会列出所有正在运行的容器,就像任务管理器一样。

    bash 复制代码
    $ docker ps
    CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                    NAMES
    f8b3a0c4a4e1   go-hello-server:1.0   "/app/main"              2 minutes ago    Up 2 minutes    0.0.0.0:8080->8080/tcp   go-server

    这里包含了容器 ID、所用镜像、运行状态、端口映射等关键信息。

  2. 查看容器日志 应用在容器里运行,fmt.Printlnconsole.log 的输出会去哪里?答案是 Docker 日志。

    bash 复制代码
    # docker logs [容器名或容器ID]
    $ docker logs go-server
    Server starting on port 8080...
    
    # 加上 -f 参数,可以像 tail -f 一样持续跟踪日志
    $ docker logs -f go-server
  3. 停止、启动和重启容器 这就像操作服务一样简单。

    bash 复制代码
    $ docker stop go-server   # 停止
    $ docker start go-server  # 再次启动
    $ docker restart go-server # 重启

    停止后,docker ps 就看不到它了,但容器并没有被删除。使用 docker ps -a 可以看到包括已停止在内的所有容器。

  4. 进入容器内部 有时我们需要进入容器内部进行调试,比如查看文件、检查环境。docker exec 命令可以做到。

    bash 复制代码
    # -it 参数让你可以在容器里进行交互式操作
    # /bin/sh 是我们想在容器里执行的命令,这里是启动一个 shell
    $ docker exec -it go-server /bin/sh
    
    # 进入容器后,你就得到了一个 shell 提示符
    /app # ls
    main
    /app # exit
  5. 删除容器 如果一个容器你不再需要了,可以用 docker rm 删除它。注意,必须先停止容器才能删除。

    bash 复制代码
    $ docker stop go-server
    $ docker rm go-server

现在,你已经掌握了容器的"生老病死"全过程管理,这是进行下一步的基础。

连接容器:网络与数据

真实的应用很少是孤立的。一个 Go 后端服务,通常需要一个数据库(如 PostgreSQL),一个前端应用可能需要调用这个后端服务。

1. 容器间的通信

默认情况下,Docker 会创建一个名为 bridge 的虚拟网络。所有通过 docker run 启动的容器都会连接到这个网络上。在同一个网络内,容器之间可以通过容器名直接通信。

让我们来验证一下。首先,我们启动一个 PostgreSQL 数据库容器:

bash 复制代码
$ docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=mysecretpassword \
  postgres:13
  • -e 参数用来设置环境变量,这里是设置数据库的密码。

现在,PostgreSQL 数据库正在名为 my-postgres 的容器中运行。你的 Go 应用如何连接它?

在你的 Go 代码里,数据库的连接地址不再是 localhost ,而应该是数据库容器的名称 my-postgres

go 复制代码
// 数据库连接字符串
// host=localhost:5432  =>  host=my-postgres:5432
const connStr = "host=my-postgres user=postgres password=mysecretpassword dbname=postgres sslmode=disable"

Docker 内置了 DNS 服务,它会自动把容器名 my-postgres 解析成该容器的内部 IP 地址。这是 Docker 网络一个非常优雅的设计。

2. 数据的持久化:数据卷 (Volume)

我们刚刚启动的数据库容器,数据是保存在哪里的?答案是保存在容器内部的文件系统中。

这是一个巨大的隐患:如果容器被删除,数据就永远丢失了。

为了解决这个问题,Docker 提供了数据卷(Volume)。你可以把数据卷想象成一个外接的 U 盘。我们将这个"U 盘"插到容器上,让应用把数据写到"U 盘"里。这样,即便容器这个"读卡器"坏了、被扔掉了,数据还在"U 盘"上,安然无恙。

使用数据卷非常简单,只需要在 run 命令里加一个 -v 参数。

bash 复制代码
# 完整地启动一个带数据卷的 postgres 容器
$ docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -v pgdata:/var/lib/postgresql/data \
  postgres:13
  • -v pgdata:/var/lib/postgresql/data 的意思是:
    • 创建一个名为 pgdata 的数据卷(如果它不存在的话)。
    • 将这个数据卷"挂载"到容器内部的 /var/lib/postgresql/data 目录上(这是 PostgreSQL 默认的数据存储路径)。

现在,所有数据库文件都会被写入 pgdata 这个数据卷里。你可以通过 docker volume ls 查看已有的数据卷。即使你删除了 my-postgres 容器,数据卷 pgdata 和里面的数据依然存在。

Docker Compose

现在,我们有了 Go 应用和 PostgreSQL 数据库。每次启动它们,需要执行两条长长的 docker run 命令,还要注意启动顺序。如果服务更多,比如加上 Redis、Nginx,手动管理将成为一场噩梦。

Docker Compose 就是来解决这个问题的。它是一个用于定义和运行多容器 Docker 应用程序的工具。你只需要在一个 YAML 文件中(默认为 docker-compose.yml),描述清楚你的应用由哪些服务构成,然后用一条命令就能同时启动或关闭所有服务。

在你的项目根目录下,创建一个 docker-compose.yml 文件:

yaml 复制代码
# docker-compose.yml

# 版本号
version: "3.8"

# 定义一系列服务
services:
  # 这是我们的 Go 后端服务
  backend:
    build: . # 使用当前目录的 Dockerfile 来构建镜像
    ports:
      - "8080:8080" # 端口映射
    depends_on:
      - db # 表明 backend 服务依赖于 db 服务,Compose 会先启动 db

  # 这是我们的数据库服务
  db:
    image: postgres:13 # 直接使用官方镜像
    environment:
      POSTGRES_PASSWORD: mysecretpassword
    volumes:
      - pgdata:/var/lib/postgresql/data # 使用数据卷

# 定义数据卷
volumes:
  pgdata:

这个文件清晰地定义了 backenddb 两个服务,以及它们之间的关系和配置。现在,管理整个应用只需要两条命令:

  • 启动所有服务:

    bash 复制代码
    # -d 表示在后台运行
    $ docker-compose up -d

    Compose 会自动构建镜像、创建网络、创建数据卷,并按依赖顺序启动所有容器。

  • 关闭并删除所有服务:

    bash 复制代码
    $ docker-compose down

    它会帮你停止并删除所有相关的容器、网络。默认情况下,数据卷会被保留。

有了 Docker Compose,复杂的应用环境变得前所未有地简单和清晰。

总结

至此,你掌握的 Docker 知识已经足以应对绝大部分的日常开发和测试工作。你会发现,无论是搭建开发环境、进行集成测试,还是确保团队成员环境一致,Docker 都将成为你的得力助手。

Docker 的世界依然广阔,下一步你可以去了解 Dockerfile 的最佳实践(比如多阶段构建),或者探索容器的终极舞台------Kubernetes。但无论走多远,今天所学的这些核心概念,都将是你坚实的基础。

相关推荐
我好饿13 小时前
Linux入门教程 第十五章 Linux 系统调优工具
linux·运维·网络
萌虎爱分享3 小时前
Linux 防火墙 (firewalld) 管理完整指南
linux·运维·防火墙·firewalld
mCell7 小时前
Docker 入门教程
运维·docker·操作系统
祈祷苍天赐我java之术7 小时前
Linux 进阶之性能调优,文件管理,网络安全
java·linux·运维
深耕云原生8 小时前
Kubernetes 深入浅出系列 | 容器剖析之容器安全
安全·容器·kubernetes
王火火(DDoS CC防护)8 小时前
服务器网络带宽不足要怎么处理?
运维·服务器
潇凝子潇8 小时前
获取服务器指标的信息
linux·运维·服务器
FreeBuf_8 小时前
Chrome高危零日漏洞PoC公开,已被用于野外攻击
linux·运维·服务器·安全·web安全
初学者_xuan11 小时前
Linux程序与进程和进程程序基础以及程序管理(零基础掌握版)
运维·计算机网络·网络安全·零基础·学习方法·linux程序管理