强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Perl 完全指南 / 第 22 章:Docker 中的 Perl

第 22 章:Docker 中的 Perl

“Build once, run anywhere”

Docker 是现代应用部署的标准方式。本章介绍如何将 Perl 应用容器化。


22.1 Perl Docker 镜像

官方镜像

镜像大小说明
perl:5.40~350MB完整镜像(Debian)
perl:5.40-slim~80MB精简镜像(推荐)
perl:5.40-threaded~380MB带线程支持
perl:5.40-bookworm~350MB指定 Debian 版本
# 拉取镜像
docker pull perl:5.40-slim

# 运行一次命令
docker run --rm perl:5.40-slim perl -e 'print "Hello from Docker!\n"'

# 交互式 shell
docker run -it --rm perl:5.40-slim bash

22.2 基本 Dockerfile

# Dockerfile
FROM perl:5.40-slim

# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    make \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# 安装 cpanm
RUN curl -L https://cpanmin.us | perl - App::cpanminus

# 设置工作目录
WORKDIR /app

# 先复制依赖文件(利用 Docker 缓存)
COPY cpanfile cpanfile
RUN cpanm --notest --installdeps .

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 3000

# 启动命令
CMD ["perl", "script/myapp", "daemon", "-l", "http://*:3000"]

22.3 多阶段构建

# 多阶段构建 — 减小最终镜像
# 阶段 1:构建
FROM perl:5.40 AS builder

WORKDIR /build

COPY cpanfile cpanfile
RUN cpanm --notest --installdeps .

COPY . .
RUN perl Makefile.PL && make && make test

# 阶段 2:运行
FROM perl:5.40-slim

# 复制 Perl 库
COPY --from=builder /usr/local/lib/perl5 /usr/local/lib/perl5
COPY --from=builder /usr/local/bin /usr/local/bin

WORKDIR /app
COPY . .

EXPOSE 3000
CMD ["perl", "script/myapp", "daemon", "-l", "http://*:3000"]

22.4 使用 Carton 管理依赖

FROM perl:5.40-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc make libssl-dev \
    && rm -rf /var/lib/apt/lists/*

RUN cpanm --notest Carton

WORKDIR /app

COPY cpanfile cpanfile.snapshot ./
RUN carton install --deployment --without develop

COPY . .

EXPOSE 3000
CMD ["carton", "exec", "perl", "script/myapp", "daemon", "-l", "http://*:3000"]

22.5 docker-compose 配置

# docker-compose.yml
version: "3.8"

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - MOJO_MODE=production
      - DATABASE_URL=dbi:SQLite:dbname=/data/app.db
    volumes:
      - app_data:/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  # 如果使用 PostgreSQL
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: myapp
      POSTGRES_PASSWORD: secret
    volumes:
      - pg_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  app_data:
  pg_data:

22.6 生产环境优化

.dockerignore

.git
.gitignore
t/
*.tar.gz
*.bak
public/
nytprof*
local/

安全最佳实践

# 使用非 root 用户
FROM perl:5.40-slim

RUN groupadd -r perl && useradd -r -g perl -d /app perl

RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY --chown=perl:perl . .

USER perl

EXPOSE 3000
CMD ["perl", "script/myapp", "daemon", "-l", "http://*:3000"]

资源限制

# 限制 CPU 和内存
docker run -d \
    --name myapp \
    --memory=512m \
    --cpus=1.0 \
    --restart=unless-stopped \
    -p 3000:3000 \
    myapp:latest

22.7 业务场景:完整的 Mojolicious 应用部署

项目结构

myapp/
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── cpanfile
├── cpanfile.snapshot
├── script/
│   └── myapp
├── lib/
│   └── MyApp.pm
│   └── MyApp/
├── templates/
├── public/
└── t/

Nginx 反向代理配置

# nginx.conf
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://web:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /app/public/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

完整 docker-compose

version: "3.8"

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      MOJO_MODE: production
      MOJO_SECRET: your-secret-key-here
    expose:
      - "3000"
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '1.0'

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./public:/app/public:ro
    depends_on:
      - web
    restart: unless-stopped

本章小结

要点内容
perl:5.40-slim推荐的基础镜像
多阶段构建减小最终镜像体积
CartonDocker 中管理依赖的最佳方式
.dockerignore排除不必要的文件
非 root 用户生产环境安全最佳实践
docker-compose多服务编排

练习

  1. 为你的 Perl 应用编写 Dockerfile
  2. 使用多阶段构建优化镜像大小
  3. 使用 docker-compose 编排 Perl 应用 + Nginx
  4. 配置健康检查
  5. 尝试使用 perl:5.40-slim vs perl:5.40 对比镜像大小

扩展阅读