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/6762

(0)
Walker的头像Walker
上一篇 2小时前
下一篇 4小时前

相关推荐

  • Go工程师体系课 004

    需求分析 后台管理系统 商品管理 商品列表 商品分类 品牌管理 品牌分类 订单管理 订单列表 用户信息管理 用户列表 用户地址 用户留言 轮播图管理 电商系统 登录页面 首页 商品搜索 商品分类导航 轮播图展示 推荐商品展示 商品详情页 商品图片展示 商品描述 商品规格选择 加入购物车 购物车 商品列表 数量调整 删除商品 结算功能 用户中心 订单中心 我的…

    14小时前
    400
  • Go工程师体系课 002

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

    1天前
    400
  • Go工程师体系课 009

    其它一些功能 个人中心 收藏 管理收货地址(增删改查) 留言 拷贝inventory_srv--> userop_srv 查询替换所有的inventory Elasticsearch 深度解析文档 1. 什么是Elasticsearch Elasticsearch是一个基于Apache Lucene构建的分布式、RESTful搜索和分析引擎,能够快速地…

    后端开发 9小时前
    400
  • Go工程师体系课 018

    API 网关与持续部署入门(Kong & Jenkins) 对应资料目录《第 2 章 Jenkins 入门》《第 3 章 通过 Jenkins 部署服务》,整理 Kong 与 Jenkins 在企业级持续交付中的实战路径。即便零基础,也能顺着步骤搭建出自己的网关 + 持续部署流水线。 课前导览:什么是 API 网关 API 网关位于客户端与后端微服务…

    后端开发 30分钟前
    000
  • Go工程师体系课 006

    项目结构说明:user-web 模块 user-web 是 joyshop_api 工程中的用户服务 Web 层模块,负责处理用户相关的 HTTP 请求、参数校验、业务路由以及调用后端接口等功能。以下是目录结构说明: user-web/ ├── api/ # 控制器层,定义业务接口处理逻辑 ├── config/ # 配置模块,包含系统配置结构体及读取逻辑 …

简体中文 繁体中文 English