我的应用程序依赖于许多外部二进制文件在运行时位于$PATH中(在示例中我使用curl和wget)。
我的想法是创建一个
base
docker 阶段,其中安装了所有依赖项 - 然后在其上扩展 production
和 test
阶段:
FROM alpine:latest as base
WORKDIR /app
# install runtime dependencies
RUN apk --no-cache add curl wget
FROM base as development
EXPOSE 3000
WORKDIR /app
COPY . .
RUN make dev-dependencies
CMD make dev-server
FROM development as test
WORKDIR /app
CMD make test
FROM alpine:latest as builder
WORKDIR /app
COPY . .
RUN make dev-dependencies
RUN make build-prod
FROM base as production
COPY --from builder /app/dist/app /app
CMD ./app
因为测试还需要一些服务(示例中是 mysql),所以我计划使用 docker-compose 来运行它们:
version: '3'
services:
mysql:
image: "mysql:latest"
develop:
build:
context: .
dockerfile: Dockerfile
target: development
depends_on:
- mysql
volumes:
- ./:/app
test:
profiles:
- test
build:
context: .
dockerfile: Dockerfile
target: test
depends_on:
- mysql
volumes:
- ./:/app
如果我是正确的,我将能够使用
docker-compose --profile test up
开始测试并使用 docker build -f Dockerfile -t app .
构建生产映像。两者都将使用 base
的相同依赖项。
我非常不确定这是否会按照我的计划进行,以及测试最终能否在 Gitlab CI 中运行。
我已经有一个包含生产和测试阶段的可用 Dockerfile。但由于我提到的担忧,我在创建 docker-compose 文件之前停止了。
我还考虑过在不使用 docker-compose 的情况下在单个 docker 阶段运行测试。在研究时,我发现了这个 Gitlab 问题 https://gitlab.com/gitlab-org/gitlab/-/issues/22801 所以我的结论是这会导致问题。
根据您的评论,您的方法几乎很好。您可以使用 services 而不是在 GitLab CI 作业中运行 docker-compose。服务允许您在作业容器旁边运行额外的容器(例如,MySQL 数据库)。如果服务需要相互访问,请确保使用 FF_NETWORK_PER_BUILD 功能标志。
但是,单元测试并不意味着使用外部依赖项。尽管如此,我还是建议您按照以下流程进行操作:
一个改进是您没有测试生产图像。将发送到生产环境的映像,这就是为什么针对代码进行单元测试并针对生产映像进行集成测试将是一个优点。