我正在docker中容器化一个symfony-3应用程序。
目前,我正在复制一个完整的parameters.yml
作为构建ARG
的函数,因此我可以使用3个不同的配置文件来创建3个不同版本:devel
、pre
和prod
。
我已经知道,正确的方法是为所有环境创建一个单独的构建,因此是一个单独编译的映像二进制文件,然后在启动容器时通过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 stop
和docker 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
:
- 脚本启动,并在需要时尝试执行准备
- 它测试旗帜
- 由于找不到它,调用Dockerfile中缺失行的条款也没有
- 在配置结束时,将容器标记为已配置
- 然后启动apache
在docker start
:上
- 脚本启动,并在需要时尝试执行准备
- 已找到标志,因此未执行任何准备工作
- 然后启动apache
10秒的资源调配将从构建阶段转移到运行阶段。
Cons
仅第一次启动容器的时间比我们在构建阶段提供的时间长约10秒。
优点
容器是完美的";书面的";使用属于每个运行环境的缓存,同时通过Dockerfile保持构建阶段,以包含所有环境中的最大公共因子。
希望能帮忙!