Go工程师体系课 015

Docker 容器化 —— Go 项目实战指南


一、Docker 核心概念

1.1 什么是 Docker

Docker 是一个开源的容器化平台,它可以将应用程序及其所有依赖项打包到一个标准化的单元(容器)中,从而实现"一次构建,到处运行"。对于 Go 开发者而言,Docker 解决了以下痛点:

  • 开发环境与生产环境不一致
  • 依赖管理复杂(数据库、缓存、消息队列等中间件)
  • 部署流程不标准化
  • 微服务架构下多服务协同困难

1.2 三大核心概念

镜像(Image)

镜像是一个只读模板,包含了运行应用所需的所有文件系统层。可以类比为"类"(Class):

  • 镜像由多层(Layer)组成,每一层代表 Dockerfile 中的一条指令
  • 层是只读的、可复用的,多个镜像可以共享底层
  • 镜像通过 tag 进行版本管理,如 golang:1.22-alpine
+---------------------------+
|   应用代码层 (COPY .)      |  <-- 最上层,变化最频繁
+---------------------------+
|   依赖安装层 (go mod)      |
+---------------------------+
|   基础工具层 (RUN apk)     |
+---------------------------+
|   基础镜像层 (alpine)      |  <-- 最底层,最稳定
+---------------------------+

容器(Container)

容器是镜像的运行实例,可以类比为"对象"(Object):

  • 容器在镜像之上添加了一个可写层
  • 每个容器都有自己独立的文件系统、网络、进程空间
  • 容器是临时的、无状态的,销毁后可写层的数据会丢失
  • 需要持久化的数据应使用数据卷(Volume)

仓库(Registry)

仓库是存储和分发镜像的服务:

  • Docker Hub:官方公共仓库,类似 GitHub
  • 私有仓库:如 Harbor、AWS ECR、阿里云 ACR
  • 镜像通过 registry/repository:tag 的格式标识,如 docker.io/library/golang:1.22

二、Dockerfile 编写(以 Go 项目为例)

2.1 基础 Dockerfile

假设我们有一个简单的 Go Web 服务:

// main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }

    http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        fmt.Fprintf(w, "OK")
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello from Go Docker Service!")
    })

    log.Printf("Server starting on port %s", port)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}

最简单但不推荐的 Dockerfile:

# 不推荐:镜像体积大,包含编译工具链
FROM golang:1.22

WORKDIR /app
COPY . .
RUN go build -o server .

EXPOSE 8080
CMD ["./server"]

这种方式生成的镜像通常超过 800MB,因为包含了完整的 Go 编译工具链。

2.2 多阶段构建(Multi-stage Build)

多阶段构建是 Go 项目 Docker 化的核心技巧,可以将镜像从 800MB+ 缩减到 10-20MB:

# ============ 第一阶段:编译 ============
FROM golang:1.22-alpine AS builder

# 设置 Go 模块代理(国内加速)
ENV GOPROXY=https://goproxy.cn,direct

WORKDIR /app

# 先复制依赖文件,利用缓存层(详见 2.3 节)
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码并编译
COPY . .

# CGO_ENABLED=0 生成静态链接的二进制文件
# -ldflags="-s -w" 去除调试信息,减小体积
RUN CGO_ENABLED=0 GOOS=linux go build \
    -ldflags="-s -w" \
    -o /app/server .

# ============ 第二阶段:运行 ============
FROM alpine:3.19

# 安装必要的 CA 证书(HTTPS 请求需要)和时区数据
RUN apk --no-cache add ca-certificates tzdata

# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app

# 从 builder 阶段复制编译好的二进制文件
COPY --from=builder /app/server .

# 复制配置文件(如果有)
# COPY --from=builder /app/config ./config

# 切换到非 root 用户
USER appuser

EXPOSE 8080

# 使用 ENTRYPOINT 而非 CMD,防止被意外覆盖
ENTRYPOINT ["./server"]

更极致的方案 -- 使用 scratch 空镜像:

# 编译阶段同上...

# 使用空镜像,最终镜像仅包含二进制文件
FROM scratch

# 从 builder 复制 CA 证书
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# 从 builder 复制时区信息
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

COPY --from=builder /app/server /server

EXPOSE 8080
ENTRYPOINT ["/server"]

镜像体积对比:

基础镜像 最终大小 适用场景
golang:1.22 ~850MB 不推荐用于生产
alpine:3.19 ~15MB 推荐,支持 shell 调试
scratch ~8MB 极致精简,无 shell
distroless ~12MB Google 推荐,安全性好

2.3 构建缓存优化

Docker 构建时,每一层都会被缓存。只要某一层的输入没有变化,就会复用缓存。关键原则是:把变化频率低的层放在前面,变化频率高的层放在后面。

# 好的做法:分离依赖下载和代码编译
COPY go.mod go.sum ./       # 依赖文件变化少,缓存命中率高
RUN go mod download          # 只有依赖变化时才重新下载
COPY . .                     # 代码频繁变化
RUN go build -o server .     # 每次代码变化都重新编译

# 坏的做法:一次性复制所有文件
COPY . .                     # 任何文件变化都导致后续所有层缓存失效
RUN go mod download
RUN go build -o server .

2.4 最佳实践总结

.dockerignore 文件

在项目根目录创建 .dockerignore,减少构建上下文大小:

# .dockerignore
.git
.gitignore
.idea
.vscode
*.md
README*
LICENSE
Makefile
docker-compose*.yml
Dockerfile*
tmp/
vendor/
bin/
*.test
*.prof

安全性最佳实践

# 1. 使用特定版本标签,避免用 latest
FROM alpine:3.19    # 好
FROM alpine:latest  # 坏 -- 不可复现

# 2. 以非 root 用户运行
RUN addgroup -S app && adduser -S app -G app
USER app

# 3. 只读文件系统(运行时指定)
# docker run --read-only --tmpfs /tmp myapp

# 4. 不要在镜像中存储密钥
# 坏的做法
ENV DB_PASSWORD=secret123
# 好的做法:运行时通过环境变量或 Secret 管理工具注入

三、docker-compose 编排

3.1 为什么需要 docker-compose

在微服务架构中,一个 Go 项目通常依赖多个外部服务。docker-compose 允许用一个 YAML 文件定义和管理多个容器的编排。

3.2 完整示例:Go 服务 + MySQL + Redis + Consul

# docker-compose.yml
version: "3.9"

services:
  # ============ Go 应用服务 ============
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - GOPROXY=https://goproxy.cn,direct
    container_name: go-app
    ports:
      - "8080:8080"    # 主机端口:容器端口
    environment:
      - PORT=8080
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_USER=root
      - DB_PASSWORD=rootpassword
      - DB_NAME=myapp
      - REDIS_ADDR=redis:6379
      - CONSUL_ADDR=consul:8500
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
      consul:
        condition: service_started
    networks:
      - app-network
    restart: unless-stopped
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 128M

  # ============ MySQL 数据库 ============
  mysql:
    image: mysql:8.0
    container_name: go-mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: myapp
      MYSQL_CHARSET: utf8mb4
    volumes:
      - mysql-data:/var/lib/mysql              # 数据持久化
      - ./deploy/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql  # 初始化脚本
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network
    restart: unless-stopped

  # ============ Redis 缓存 ============
  redis:
    image: redis:7-alpine
    container_name: go-redis
    ports:
      - "6379:6379"
    command: redis-server --requirepass redispassword --appendonly yes
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "redispassword", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network
    restart: unless-stopped

  # ============ Consul 服务注册与发现 ============
  consul:
    image: hashicorp/consul:1.17
    container_name: go-consul
    ports:
      - "8500:8500"    # HTTP API 和 Web UI
      - "8600:8600/udp" # DNS
    command: agent -server -bootstrap-expect=1 -ui -client=0.0.0.0
    volumes:
      - consul-data:/consul/data
    networks:
      - app-network
    restart: unless-stopped

# ============ 数据卷定义 ============
volumes:
  mysql-data:
    driver: local
  redis-data:
    driver: local
  consul-data:
    driver: local

# ============ 网络定义 ============
networks:
  app-network:
    driver: bridge

3.3 常用 docker-compose 命令

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

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

# 查看服务状态
docker-compose ps

# 查看某个服务的日志
docker-compose logs -f app

# 停止所有服务
docker-compose down

# 停止并删除数据卷(慎用,会丢失数据)
docker-compose down -v

# 只启动某个服务及其依赖
docker-compose up -d app

# 进入某个服务的容器
docker-compose exec app sh

# 扩展服务实例数
docker-compose up -d --scale app=3

四、常用 Docker 命令速查

4.1 镜像管理

# 构建镜像
docker build -t myapp:v1.0 .
docker build -t myapp:v1.0 -f deploy/Dockerfile .   # 指定 Dockerfile 路径

# 查看本地镜像
docker images
docker image ls

# 删除镜像
docker rmi myapp:v1.0
docker image prune           # 清理悬空镜像(dangling images)
docker image prune -a        # 清理所有未使用的镜像

# 镜像标签
docker tag myapp:v1.0 registry.example.com/myapp:v1.0

# 导入导出(离线场景)
docker save -o myapp.tar myapp:v1.0
docker load -i myapp.tar

# 查看镜像构建历史 / 层信息
docker history myapp:v1.0
docker inspect myapp:v1.0

4.2 容器管理

# 运行容器
docker run -d --name myapp -p 8080:8080 myapp:v1.0
docker run -d --name myapp \
  -p 8080:8080 \
  -e DB_HOST=localhost \
  -v /host/data:/app/data \
  --restart unless-stopped \
  myapp:v1.0

# 查看运行中的容器
docker ps
docker ps -a                 # 包含已停止的容器

# 容器生命周期
docker start myapp
docker stop myapp
docker restart myapp
docker rm myapp              # 删除已停止的容器
docker rm -f myapp           # 强制删除(包括运行中的)

# 进入容器内部
docker exec -it myapp sh     # alpine 用 sh
docker exec -it myapp bash   # 带 bash 的镜像用 bash

# 查看日志
docker logs myapp
docker logs -f myapp         # 实时跟踪
docker logs --tail 100 myapp # 最后100行

# 查看容器资源使用
docker stats
docker stats myapp

# 复制文件
docker cp myapp:/app/logs/app.log ./app.log   # 容器到主机
docker cp ./config.yaml myapp:/app/config.yaml # 主机到容器

4.3 系统清理

# 一键清理:停止的容器、悬空镜像、未使用的网络
docker system prune

# 包含未使用的数据卷(慎用)
docker system prune --volumes

# 查看 Docker 磁盘使用情况
docker system df

五、Docker 网络模式

5.1 bridge 模式(默认)

每个容器拥有独立的网络命名空间,通过虚拟网桥 docker0 进行通信:

# 创建自定义 bridge 网络
docker network create my-network

# 将容器连接到自定义网络
docker run -d --name app --network my-network myapp:v1.0
docker run -d --name db --network my-network mysql:8.0

# 同一网络内的容器可以通过容器名互相访问
# app 容器内可以用 "db:3306" 连接数据库

自定义 bridge 网络的优势:
- 容器间通过名称(DNS)互相发现
- 更好的网络隔离
- 可以动态连接/断开容器

5.2 host 模式

容器直接使用宿主机的网络,没有网络隔离:

docker run -d --network host myapp:v1.0
# 容器中监听 8080 端口 = 宿主机 8080 端口
# 不需要 -p 端口映射
  • 优点:性能最好,没有 NAT 开销
  • 缺点:端口冲突风险,安全性较低
  • 适用场景:高性能网络需求、网络调试

5.3 none 模式

容器没有网络连接,完全隔离:

docker run -d --network none myapp:v1.0
  • 适用场景:只需要进行计算、不需要网络的任务

5.4 网络模式对比

模式 隔离性 性能 使用场景
bridge 默认选择,大部分场景
host 高性能需求
none 完全 - 安全敏感的计算任务
overlay 跨主机的 Swarm/K8s

六、数据卷(Volume)与持久化

6.1 为什么需要数据卷

容器的文件系统是临时的,容器被删除后数据就会丢失。数据卷提供了持久化存储机制。

6.2 三种挂载方式

# 1. 命名卷(Named Volume)-- 推荐用于数据持久化
docker volume create mydata
docker run -v mydata:/app/data myapp:v1.0

# 2. 绑定挂载(Bind Mount)-- 适合开发时挂载源代码
docker run -v /host/path:/container/path myapp:v1.0
docker run -v $(pwd)/config:/app/config:ro myapp:v1.0   # 只读挂载

# 3. tmpfs 挂载 -- 内存中的临时文件系统
docker run --tmpfs /app/tmp myapp:v1.0

6.3 数据卷管理

# 查看所有卷
docker volume ls

# 查看卷详情
docker volume inspect mydata

# 删除卷
docker volume rm mydata

# 清理未使用的卷
docker volume prune

6.4 在 Go 项目中的典型用法

# docker-compose.yml 中的卷使用
services:
  app:
    volumes:
      - ./config:/app/config:ro    # 配置文件(只读绑定)
      - app-logs:/app/logs         # 日志目录(命名卷)
      - /app/tmp                   # 匿名卷(临时文件)

  mysql:
    volumes:
      - mysql-data:/var/lib/mysql  # 数据库数据(命名卷,最重要)

volumes:
  app-logs:
  mysql-data:

七、Docker 在微服务开发中的应用

7.1 本地开发工作流

在微服务架构下,一个 Go 服务可能依赖多个其他服务。Docker 让本地开发变得轻松:

+-----------------------------------------------+
|           docker-compose 编排                  |
|                                               |
|  +----------+  +----------+  +----------+    |
|  | 用户服务  |  | 订单服务  |  | 商品服务  |    |
|  | Go :8081 |  | Go :8082 |  | Go :8083 |    |
|  +----+-----+  +----+-----+  +----+-----+    |
|       |              |              |          |
|  +----+--------------+--------------+----+    |
|  |          app-network (bridge)         |    |
|  +----+----------+----------+-----------+    |
|       |          |          |                 |
|  +----+---+ +---+----+ +--+------+           |
|  | MySQL  | | Redis  | | Consul  |           |
|  | :3306  | | :6379  | | :8500   |           |
|  +--------+ +--------+ +---------+           |
+-----------------------------------------------+

7.2 热重载开发模式

开发时可以结合 air 等工具实现代码热重载:

# docker-compose.dev.yml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - .:/app                  # 挂载源代码
    command: air                 # 使用 air 热重载
    ports:
      - "8080:8080"
# Dockerfile.dev
FROM golang:1.22-alpine

RUN go install github.com/air-verse/air@latest

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

# 不需要 COPY . . 因为源代码通过 volume 挂载
CMD ["air"]

7.3 集成测试

使用 Docker 可以轻松搭建集成测试环境:

# 启动测试依赖
docker-compose -f docker-compose.test.yml up -d

# 运行集成测试
go test ./... -tags=integration

# 清理
docker-compose -f docker-compose.test.yml down -v

也可以在 Go 代码中使用 testcontainers-go 库动态创建测试容器:

package repository_test

import (
    "context"
    "testing"

    "github.com/testcontainers/testcontainers-go"
    "github.com/testcontainers/testcontainers-go/modules/mysql"
)

func TestUserRepository(t *testing.T) {
    ctx := context.Background()

    // 动态创建 MySQL 容器用于测试
    mysqlC, err := mysql.Run(ctx,
        "mysql:8.0",
        mysql.WithDatabase("testdb"),
        mysql.WithUsername("test"),
        mysql.WithPassword("test"),
    )
    if err != nil {
        t.Fatal(err)
    }
    defer mysqlC.Terminate(ctx)

    // 获取连接地址
    host, _ := mysqlC.Host(ctx)
    port, _ := mysqlC.MappedPort(ctx, "3306")

    // 使用真实数据库进行测试...
    t.Logf("MySQL running at %s:%s", host, port.Port())
}

八、镜像推送到 Registry

8.1 推送到 Docker Hub

# 1. 登录
docker login

# 2. 给镜像打标签(格式:用户名/仓库名:标签)
docker tag myapp:v1.0 username/myapp:v1.0
docker tag myapp:v1.0 username/myapp:latest

# 3. 推送
docker push username/myapp:v1.0
docker push username/myapp:latest

8.2 推送到私有仓库

# 以阿里云 ACR 为例
# 1. 登录私有仓库
docker login registry.cn-hangzhou.aliyuncs.com

# 2. 打标签
docker tag myapp:v1.0 registry.cn-hangzhou.aliyuncs.com/myns/myapp:v1.0

# 3. 推送
docker push registry.cn-hangzhou.aliyuncs.com/myns/myapp:v1.0

8.3 搭建本地私有仓库(Harbor)

Harbor 是企业级的 Docker 镜像仓库,支持权限管理、镜像扫描等功能:

# 使用 Docker Compose 快速部署 Harbor
# 下载离线安装包后:
./install.sh --with-chartmuseum --with-trivy

# 推送到 Harbor
docker tag myapp:v1.0 harbor.example.com/myproject/myapp:v1.0
docker push harbor.example.com/myproject/myapp:v1.0

8.4 CI/CD 中的自动构建与推送

在 GitHub Actions 中自动构建并推送镜像:

# .github/workflows/docker.yml
name: Build and Push Docker Image

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            username/myapp:${{ github.ref_name }}
            username/myapp:latest

九、Go 项目 Docker 化完整实战流程

9.1 项目结构

myapp/
├── cmd/
│   └── server/
│       └── main.go          # 入口
├── internal/
│   ├── handler/             # HTTP 处理器
│   ├── service/             # 业务逻辑
│   ├── repository/          # 数据访问
│   └── config/              # 配置管理
├── deploy/
│   ├── mysql/
│   │   └── init.sql         # 数据库初始化
│   └── nginx/
│       └── nginx.conf       # 反向代理配置
├── go.mod
├── go.sum
├── Dockerfile
├── docker-compose.yml
├── docker-compose.dev.yml
├── .dockerignore
└── Makefile

9.2 Makefile 自动化

# Makefile
APP_NAME=myapp
VERSION=$(shell git describe --tags --always --dirty)
REGISTRY=registry.example.com/myns

.PHONY: build run test docker-build docker-push deploy clean

# 本地编译
build:
    CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=$(VERSION)" \
        -o bin/$(APP_NAME) ./cmd/server

# 本地运行
run:
    go run ./cmd/server

# 运行测试
test:
    go test ./... -v -cover

# 构建 Docker 镜像
docker-build:
    docker build -t $(APP_NAME):$(VERSION) .
    docker tag $(APP_NAME):$(VERSION) $(APP_NAME):latest

# 推送镜像
docker-push: docker-build
    docker tag $(APP_NAME):$(VERSION) $(REGISTRY)/$(APP_NAME):$(VERSION)
    docker push $(REGISTRY)/$(APP_NAME):$(VERSION)

# 启动开发环境
dev:
    docker-compose -f docker-compose.dev.yml up -d --build

# 启动生产环境
deploy:
    docker-compose up -d --build

# 查看日志
logs:
    docker-compose logs -f app

# 清理
clean:
    docker-compose down -v
    docker image prune -f
    rm -rf bin/

9.3 完整的生产级 Dockerfile

# ============ 第一阶段:编译 ============
FROM golang:1.22-alpine AS builder

# 安装必要的构建工具
RUN apk add --no-cache git ca-certificates tzdata

# 设置 Go 环境
ENV GOPROXY=https://goproxy.cn,direct
ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64

WORKDIR /build

# 依赖缓存层
COPY go.mod go.sum ./
RUN go mod download && go mod verify

# 编译
COPY . .
ARG VERSION=dev
RUN go build \
    -ldflags="-s -w -X main.Version=${VERSION}" \
    -o /build/app \
    ./cmd/server

# ============ 第二阶段:运行 ============
FROM alpine:3.19

LABEL maintainer="your-email@example.com"
LABEL version="${VERSION}"
LABEL description="My Go Application"

# 安装运行时依赖
RUN apk --no-cache add ca-certificates tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

# 创建非 root 用户和必要目录
RUN addgroup -S app && adduser -S app -G app && \
    mkdir -p /app/logs /app/config && \
    chown -R app:app /app

WORKDIR /app

# 复制二进制文件
COPY --from=builder /build/app .

# 复制配置文件模板(可选)
# COPY --from=builder /build/config ./config

# 切换到非 root 用户
USER app

# 暴露端口
EXPOSE 8080

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1

# 启动
ENTRYPOINT ["./app"]

9.4 完整流程总结

# 1. 编写代码和 Dockerfile
# 2. 本地开发和测试
make dev              # 启动开发环境
make test             # 运行测试

# 3. 构建镜像
make docker-build     # 构建生产镜像

# 4. 本地验证
make deploy           # 启动完整环境
make logs             # 查看日志
curl http://localhost:8080/health  # 测试接口

# 5. 推送镜像
make docker-push      # 推送到仓库

# 6. 部署到服务器
ssh your-server
docker pull registry.example.com/myns/myapp:v1.0
docker-compose up -d

# 7. 清理
make clean

十、常见问题与排查

10.1 常见问题

问题 原因 解决方案
镜像体积过大 未使用多阶段构建 使用 multi-stage build
构建慢 缓存未命中 先 COPY go.mod,再 COPY .
容器内时区不对 缺少时区数据 安装 tzdata,设置 TZ
HTTPS 请求失败 缺少 CA 证书 apk add ca-certificates
无法连接其他容器 网络不通 确保在同一 docker network
数据丢失 未使用 volume 重要数据用 named volume

10.2 调试技巧

# 查看容器内部文件系统
docker exec -it myapp sh

# 查看容器网络配置
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp

# 查看容器环境变量
docker exec myapp env

# 临时运行一个调试容器(和目标容器共享网络)
docker run -it --rm --network container:myapp alpine sh

# 查看 Docker 构建过程(详细输出)
docker build --progress=plain -t myapp . 2>&1 | tee build.log

下一篇016 - Kubernetes 入门,学习如何将 Docker 容器部署到 K8s 集群中进行生产级编排和管理。

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6781

(0)
Walker的头像Walker
上一篇 12小时前
下一篇 2025年3月8日 12:51

相关推荐

  • Go工程师体系课 protoc-gen-validate

    protoc-gen-validate 简介与使用指南 ✅ 什么是 protoc-gen-validate protoc-gen-validate(简称 PGV)是一个 Protocol Buffers 插件,用于在生成的 Go 代码中添加结构体字段的验证逻辑。 它通过在 .proto 文件中添加 validate 规则,自动为每个字段生成验证代码,避免你手…

  • 编程基础 0013_Go企业实践案例精华

    Go 企业实践案例精华 知识来源:基于以下电子书资料整理- 《Go在百度BFE的应用 for Gopher China》- 《Go在分布式数据库中的应用》- 《Go在猎豹移动的应用》- 《Golang与高性能DSP竞价系统》- 《Go at Google: Language Design in the Service of Software Engineer…

    后端开发 20小时前
    100
  • Go资深工程师讲解(慕课) 003

    003 测试 吐槽别人家的,go语言采用表格驱动测试 测试数据和测试逻辑混在一些 出错信息不明确 一旦一个数据出错测试全部结束 表格驱动测试 test:=[]struct{ a,b,c int32 }{ {1,2,3}, {0,2,0}, {0,0,0}, {0,0,0}, {-1,1,0}, {math.MaxInt32,1,math.MinInt32},…

    后端开发 22小时前
    000
  • Go工程师体系课 002

    GOPATH 与 Go Modules 的区别 1. 概念 GOPATH 是 Go 的早期依赖管理机制。 所有的 Go 项目和依赖包必须放在 GOPATH 目录中(默认是 ~/go)。 一定要设置 GO111MODULE=off 项目路径必须按照 src/包名 的结构组织。 不支持版本控制,依赖管理需要手动处理(例如 go get)。 查找依赖包的顺序是 g…

    13小时前
    100
  • Go工程师体系课 protobuf_guide

    Protocol Buffers 入门指南 1. 简介 Protocol Buffers(简称 protobuf)是 Google 开发的一种语言无关、平台无关、可扩展的结构化数据序列化机制。与 JSON、XML 等序列化方式相比,protobuf 更小、更快、更简单。 项目主页:https://github.com/protocolbuffers/prot…

简体中文 繁体中文 English