Symfony缓存:在构建docker容器或第一次运行它时清除



我正在docker中容器化一个symfony-3应用程序。

目前,我正在复制一个完整的parameters.yml作为构建ARG的函数,因此我可以使用3个不同的配置文件来创建3个不同版本:develpreprod

我已经知道,正确的方法是为所有环境创建一个单独的构建,因此是一个单独编译的映像二进制文件,然后在启动容器时通过ENV vars传递所有配置。但我现在需要进行配置复制。

我的Dockerfile快结束了:

ARG ENVIRONMENT
# Copy the config file.
COPY config/tighten-violet.parameters.${ENVIRONMENT}.yml /files/tighten-violet/app/config/parameters.yml
# Build the composer part
RUN 
cd /files/tighten-violet && 
composer --no-ansi --no-interaction install --no-progress  --no-autoloader --no-scripts && 
composer --no-ansi --no-interaction dump-autoload --no-dev --optimize --classmap-authoritative --no-scripts && 
composer --no-ansi --no-interaction run-script --no-dev symfony-scripts && 
php bin/console cache:clear && 
php bin/console cache:clear --env=prod && 
php bin/console assetic:dump --env=prod && 
:
EXPOSE 80
# Start apache
CMD [ "apachectl", "-D", "FOREGROUND" ]

碰巧"生成器"主机不提供与生产数据库的连接。。。我现在很惊讶,在清除缓存时,我发现数据库有"真正的连接"。我认为缓存只与"静态代码解析"有关,以编译自动加载器、编译服务容器等等…

我得到这个错误:

Updating the "app/config/parameters.yml" file
> SensioBundleDistributionBundleComposerScriptHandler::buildBootstrap
> SensioBundleDistributionBundleComposerScriptHandler::clearCache
// Clearing the cache for the dev environment with debug
// true
[OK] Cache for the "dev" environment (debug=true) was successfully cleared.
[DoctrineDBALExceptionConnectionException]
An exception occured in driver: SQLSTATE[HY000] [2002] Connection timed out
[DoctrineDBALDriverPDOException]
SQLSTATE[HY000] [2002] Connection timed out
[PDOException]
SQLSTATE[HY000] [2002] Connection timed out
cache:clear [--no-warmup] [--no-optional-warmers] [-h|--help] [-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi] [--no-ansi] [-n|--no-interaction] [-e|--env ENV] [--no-debug] [--] <command>
Script SensioBundleDistributionBundleComposerScriptHandler::clearCache handling the symfony-scripts event terminated with an exception
[...]

因此,似乎symfony-scripts运行的Sensio Bundle反过来,出于任何原因,正试图进行真正的连接。

问题

如果我想在docker中封装一个完全配置的symfony-3应用程序,我应该在构建时运行脚本吗?或者,我应该以某种方式将它们作为运行的入口点脚本的一部分来运行,首先运行脚本,然后启动apache?

解决方案是将composer部分拆分为两个单独的块:

作曲家指令第1块

下载软件包的部分。这可以在";建设者";。

作曲家指令第2块

使用下载的软件包来预热系统的部件。这可以在运行容器内运行;"就位";因此考虑到环境并能够访问适当的支持服务。

实施

Dockerfile

通过这种方式,我从更改了Dockerfile中的RUN命令

RUN 
cd /files/tighten-violet && 
composer --no-ansi --no-interaction install --no-progress  --no-autoloader --no-scripts && 
composer --no-ansi --no-interaction dump-autoload --no-dev --optimize --classmap-authoritative --no-scripts && 
composer --no-ansi --no-interaction run-script --no-dev symfony-scripts && 
php bin/console cache:clear && 
php bin/console cache:clear --env=prod && 
php bin/console assetic:dump --env=prod && 
:

进入

RUN 
cd /files/tighten-violet && 
composer --no-ansi --no-interaction install --no-progress  --no-autoloader --no-scripts && 
:

我把所有的东西都去掉了,除了";将包下载到供应商中";,作为";下载";不依赖于环境变量或配置。

到目前为止,我有一个已经填充了/vendor的可发货docker映像。

但还是少了一步。。。那些缺失的线路去哪儿了?

引导程序.sh

我所做的是一个引导脚本,所以我从更改了CMD行

CMD [ "apachectl", "-D", "FOREGROUND" ]

进入

CMD [ "/files/bootstrap.sh" ]

boostrap.sh文件也会在构建过程中被复制。。。以下是内容(简单的初始版本(:

#!/usr/bin/env bash
# Provision
composer --no-ansi --no-interaction dump-autoload --no-dev --optimize --classmap-authoritative --no-scripts && 
composer --no-ansi --no-interaction run-script --no-dev symfony-scripts
php bin/console cache:clear && 
php bin/console cache:clear --env=prod && 
php bin/console assetic:dump --env=prod
# Start the server
apachectl -D FOREGROUND

这包含";安装部件";这可能取决于环境,包括自动加载、SenioBundle脚本以及缓存和转储的转储。以防万一有ENV变量改变了我们想要缓存的行为。

这恰好适用于docker run。但是,如果您再次执行docker stopdocker start,则供应部分也会一遍又一遍地运行(停止+启动不会冻结进程状态,就像"暂停"一样,它会终止进程,然后再次重新启动,从bootstrap.sh的开头开始

因此,我可以改进boostrap脚本,使其标记是否已自动配置。这是bootstrap.sh脚本的改进(也是最终(第二个版本:

#!/usr/bin/env bash
provisionIfNeeded()
{
PROVISIONED=/tmp/provisioned
if [ ! -f ${PROVISIONED} ]; then
echo "------------------------------------------------------------------------------"
echo "Provisioning"
echo "------------------------------------------------------------------------------"
composer --no-ansi --no-interaction dump-autoload --no-dev --optimize --classmap-authoritative --no-scripts && 
composer --no-ansi --no-interaction run-script --no-dev symfony-scripts
php bin/console cache:clear && 
php bin/console cache:clear --env=prod && 
php bin/console assetic:dump --env=prod
echo "------------------------------------------------------------------------------"
echo "Ended provisioning"
echo "------------------------------------------------------------------------------"
touch ${PROVISIONED}
fi
}
startServer()
{
echo "Starting httpd."
exec apachectl -D FOREGROUND
# If you do all (including provisioning) with an
# unprivileged user, then do this:
# exec sudo --preserve-env apachectl -D FOREGROUND
}
provisionIfNeeded
startServer

因此,在docker run:

  1. 脚本启动,并在需要时尝试执行准备
  2. 它测试旗帜
  3. 由于找不到它,调用Dockerfile中缺失行的条款也没有
  4. 在配置结束时,将容器标记为已配置
  5. 然后启动apache

docker start:上

  1. 脚本启动,并在需要时尝试执行准备
  2. 已找到标志,因此未执行任何准备工作
  3. 然后启动apache

10秒的资源调配将从构建阶段转移到运行阶段。

Cons

仅第一次启动容器的时间比我们在构建阶段提供的时间长约10秒。

优点

容器是完美的";书面的";使用属于每个运行环境的缓存,同时通过Dockerfile保持构建阶段,以包含所有环境中的最大公共因子。

希望能帮忙!

最新更新