如何不(几乎)重复“生产”和“开发”环境中的“Dockerfile”?

如何不(几乎)重复“生产”和“开发”环境中的“Dockerfile”?

我有一个 dockerised 的服务器应用程序,但似乎无法按要求将变量从docker-compse.yaml任何服务传递给它。Dockerfile

因此我找不到任何其他解决方案,只能按照以下方法...

我有两个几乎相同的Dockerfiles,每个服务器环境一个

# ./docker/production-server/Dockerfile
FROM rust:latest
WORKDIR /usr/src/rust-scrape-yt

ENV BUILD_FLAGS="--release"
ENV TEST_DOCKER="true"
ENV PRODUCTION="true"

COPY dummy.rs src/main.rs
COPY Cargo.toml .
COPY Cargo.lock .

RUN echo "Dummy build for deps, with flags: $BUILD_FLAGS"
RUN cargo build $BUILD_FLAGS

COPY . .

RUN cargo build $BUILD_FLAGS

对于开发容器:

# ./docker/development-server/Dockerfile
FROM rust:latest
WORKDIR /usr/src/rust-scrape-yt

ENV BUILD_FLAGS=""
ENV TEST_DOCKER="true"
ENV PRODUCTION="false"

COPY dummy.rs src/main.rs
COPY Cargo.toml .
COPY Cargo.lock .

RUN echo "Dummy build for deps, with flags: $BUILD_FLAGS"
RUN cargo build $BUILD_FLAGS

COPY . .

RUN cargo build $BUILD_FLAGS

唯一的区别是生产 Dockerfile 有

ENV BUILD_FLAGS="--release"

虽然开发服务器镜像已经

ENV BUILD_FLAGS=""

COPY dummy.rs src/main.rs
COPY Cargo.toml .
COPY Cargo.lock .

RUN echo "Dummy build for deps, with flags: $BUILD_FLAGS"
RUN cargo build $BUILD_FLAGS

COPY . .

RUN cargo build $BUILD_FLAGS

docker-compose.yaml的如下

version: "3.9"

services:

  production-db:
    image: postgres
    restart: always
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: thisisjustSommmePasWorttLaliloo
      POSTGRES_DB: rust-yt-scraper
    ports:
      - 15878:5432
    volumes:
      - production-rust-yt-scraper:/var/lib/postgresql/data

  development-db:
    image: postgres
    restart: always
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: thisisjustSommmePasWorttLalilooForDev
      POSTGRES_DB: rust-yt-scraper
    ports:
      - 15879:5432
    volumes:
      - development-rust-yt-scraper:/var/lib/postgresql/data

  production-server:
    depends_on:
      - production-db
    build:
      context: .
      dockerfile: docker/production-server/Dockerfile
    image: djfm/rust-yt-scraper-prod:latest
    restart: always
    environment:
      PRODUCTION: "true"
    
    ports:
      - "19850:8080"
    command: cargo run --release --bin server

  development-server:
    depends_on:
      - development-db
    build:
      context: .
      dockerfile: docker/development-server/Dockerfile
    image: djfm/rust-yt-scraper-dev:latest
    restart: always
    ports:
      - "19851:8080"
    command: cargo run --bin server
    environment:
      PRODUCTION: "false"

  server-tests:
    image: djfm/rust-yt-scraper:latest
    restart: never
    depends_on:
      - development-server
    environment:
      - PRODUCTION:false
      - BUILD_FLAGS:""
    command: cargo test

  adminer:
    image: adminer
    restart: always
    ports:
      - "9280:8080"

volumes:

  production-rust-yt-scraper:
    driver: local

  development-rust-yt-scraper:
    driver: local

我试过

service:
  blah:
    build:
      context: .
      dockerfiles: ./conf/server.Dockerfile
      args:
        PRODUCTION:true

这没希望了吗?我需要维护单独的 Dockerfile 吗?

答案1

嗨。

在安装不同的软件包之前,请仅使用一个 Dockerfile 来构建映像。
或者更好的是,我认为,在这个用例中是多阶段构建,因为你使用的是 rust,并且你不会将源代码与映像一起发送。

对于 ENV 变量,您做对了,但输入有误。下面将进行解释。

只需定义您想要在运行时映像中拥有的 ENV 变量,并用默认值填充它们(如果需要)。
对于 BUILD_FLAGS,我建议使用 ARG

信息:
ENV 随后会保留在图像中,因为环境变量
ARG 仅在图像构建期间可用,并且不会保留在图像中

为了便于阅读,我将跳过一些步骤...

尝试使用多阶段更新你的 Dockerfile:

ARG BUILD_FLAGS="[YOUR DEFAULT FLAGS]"
FROM rust:latest as buildimage
ARG BUILD_FLAGS
ENV CARGO_TARGET_DIR=target
COPY dummy.rs src/main.rs
RUN cargo build $BUILD_FLAGS

在同一个 Dockerfile 中继续:

FROM rust:latest
ARG BUILD_FLAGS
ENV PRODUCTION="false"
COPY --from=buildimage target/ /app/

所以发生了什么事:

  • 第一个镜像用于编译你的应用程序,名为 buildimage
  • 第二幅图像只会将 buildimage 的结果复制到不包含 main.rs 的新图像中
  • 最终图像没有 ENV 变量 BUILD_FLAGS 因为我们将其声明为 ARG
  • 最终图像仅设置了 PRODUCTION 环境变量,其默认字符串为“false”
  • FROM 之前的 ARG 是全局的,FROM 之后的 ARG 仅在当前构建中本地。要接管默认值,请重新定义它们
  • DryRun:我将 CARGO_TARGET_DIR 设置为仅“target”,以摆脱 target/release 和 target/debug 文件夹

注意:
由于我不是 Rust 开发人员,我只能猜测编译后的主文件位于何处。
这是一个完整的试运行,但应该可以解决您的问题。

结合您的撰写文件,您将获得两幅图像。
一幅图像包含可用于生产的内容,
另一幅图像包含调试符号等。

在 Compose 文件中配置你的环境变量。
你可以通过两种方式定义环境变量:
方式一:

    environment:
      VAR_1: "value_1"
      VAR_2: "value_2"

方法二:

    environment:
      - VAR_1="value_1"
      - VAR_2="value_2"

我更喜欢第一种保留完整语法的方式

因此你的撰写文件看起来应该是这样的:

version: "3.9"
services:
  production-db:
  [...]

  development-db:
  [...]

  production-server:
    depends_on:
      - production-db
    build:
      context: .
      dockerfile: docker/Dockerfile
      args:
        BUILD_FLAGS: "--release"
    image: djfm/rust-yt-scraper:latest
    restart: always
    environment:
      PRODUCTION: "true"
    ports:
      - "19850:8080"
    command: cargo run --release --bin server

  development-server:
    depends_on:
      - development-db
    build:
      context: .
      dockerfile: docker/Dockerfile
      args:
        BUILD_FLAGS: ""
    image: djfm/rust-yt-scraper-dev:latest
    restart: always
    environment:
      PRODUCTION: "false"
    ports:
      - "19851:8080"
    command: cargo run --bin server

  server-tests:
    image: djfm/rust-yt-scraper:latest
    restart: never
    depends_on:
      - development-server
    environment:
      PRODUCTION: "false"
    command: cargo test

  adminer:
    image: adminer
    restart: always
    ports:
      - "9280:8080"

volumes:

  production-rust-yt-scraper:
    driver: local

  development-rust-yt-scraper:
    driver: local

高血压

相关内容