我快疯了。
我一直在为我的项目处理一个Dockerfile
和docker-compose.yml
文件。我最近更新了项目的依赖项。当我使用composer install
在容器外部构建项目时,它会使用正确的依赖项进行构建。但是,当我在 docker 容器中构建项目时,它会下载并安装最新的依赖项,但随后以某种方式使用过时的依赖项运行应用程序!
首先,这是我Dockerfile
的样子:
FROM composer
# Set the working directory within the docker container
WORKDIR /app
# Copy in the app, then install dependencies.
COPY . /app
RUN composer install
我已经排除了composer.lock
文件和vendor
目录 在我的.dockerignore
:
vendor
composer.lock
这是我的docker-compose.yml
:
version: "3"
services:
app:
build: .
volumes:
- app:/app
webserver:
image: richarvey/nginx-php-fpm
volumes:
- app:/var/www/html
volumes:
app:
请注意,生成过程发生在app
卷内。我认为这不应该是问题的一部分,因为我每次都运行docker system prune
来清除所有现有卷。
这就是我运行容器的方式。在故障排除时,我一直在运行以下命令以在启动容器之前消除任何缓存文件:
$ docker system prune
$ docker-compose build --no-cache
$ docker-compose up --force-recreate
当我观察依赖项的安装和下载时,我可以看到它正在下载和安装正确的版本!因此,在过程中的某个时刻,它必须具有正确的composer.json
文件。
然而,不知何故,一旦构建完成并且应用程序启动,我会收到关于过时依赖项的相同旧警告,果然,容器内的composer.json
已经过时了!
所以我的问题是:
- 容器中的
composer.json
文件如何过时?它从哪里获取过时的文件,因为它不再存在于任何图像或缓存中? - TF 如何设法使用这个过时的 composer.json 文件安装最新的依赖项,但随后不使用它们,实际上恢复了 composer.json 文件和依赖项?
我认为问题是,您将本地文件复制到应用程序容器中并在此副本上运行composer install
。由于这不会影响您的主机系统,因此实际为您的项目提供服务的 Web 服务器仍将使用过时的本地版本,而不是来自其他映像的副本。
您可以尝试使用多阶段构建或类似的东西:
COPY FROM app:latest /app /var/www/html
这会将工件从您的"构建容器"(即在应用程序中安装了依赖项的项目)复制到运行代码的实际容器中,即 Web 服务器。不幸的是,我认为这不适用于您的设置(很好),您将卷安装到该位置。
好吧,我终于解决了这个问题,尽管我原始问题的某些部分仍然让我感到困惑。
以下是我学到的:
docker-compose up
过程按以下顺序进行:
- 如果映像已存在,请使用它,即使 Dockerfile(或其使用的文件)已更改。(这可以通过
docker-compose up --build
避免)。 - 如果没有现有映像,请从 Dockerfile 生成映像。
- 挂载 docker 撰写文件中指定的卷。
我的问题的很大一部分是我认为卷是在构建过程之前挂载的,并且由于这些命令,我的应用程序将安装到此卷中:
COPY . /app
RUN composer install
但是,当卷装载到容器内的同一位置时,这些文件后来被覆盖(/app
)。
现在,由于我没有挂载主机目录,只是一个临时的命名卷,因此/app
目录应该是空的。我仍然不明白为什么不是,考虑到我在每次构建之前都用docker system prune
清除了现有的 Docker 卷。无论什么。
最后,我使用了@dbrumann的解决方案。这更简单,不需要使用任何 Docker 卷,并且避免在构建过程完成后使用实时composer
容器(这对生产不利)。我的Dockerfile
现在看起来像这样:
Dockerfile
:
# Install dependencies using the composer image
FROM composer AS composer
# Set the working directory within the docker container
WORKDIR /app
# Copy in the app, then install dependencies.
COPY . .
RUN composer install
# Start the nginx server
FROM richarvey/nginx-php-fpm
# Copy over files from the composer image, which is then discarded automatically
WORKDIR /var/www/html
COPY --from=composer /app .
而新docker-compose.yml
:
version: "3.7"
services:
webserver:
build: .
tty: true
ports:
- "80:80"
- "443:443"