Docker部署的PHP(Symfony)应用连接AWS RDS(MariaDB)失败
场景与配置
在EC2实例上通过Docker运行PHP(Symfony)应用,对应的Docker Compose配置如下:
version: "3.7" services: traefik: image: traefik:1.7 container_name: so-traefik command: --docker --docker.exposedbydefault=false ports: - "80:80" volumes: - /var/run/docker.sock:/var/run/docker.sock app: image: thecodingmachine/php:7.2-v4-apache container_name: so-app labels: - traefik.enable=true - traefik.backend=app - traefik.frontend.rule=Host:so.localhost environment: APACHE_DOCUMENT_ROOT: web PHP_INI_MEMORY_LIMIT: 1G PHP_INI_ERROR_REPORTING: E_ALL PHP_INI_UPLOAD_MAX_FILESIZE: 512M PHP_INI_POST_MAX_SIZE: 512M PHP_INI_MAX_INPUT_VARS: 4096 PHP_INI_MAX_EXECUTION_TIME: 500 PHP_EXTENSION_GD: 1 PHP_EXTENSION_IMAGICK: 1 PHP_EXTENSION_INTL: 1 PHP_EXTENSION_XDEBUG: 0 PHP_EXTENSION_BCMATH: 1 PHP_INI_XDEBUG__REMOTE_AUTOSTART: 0 PHP_INI_XDEBUG__MAX_NESTING_LEVEL: 5000 SYMFONY_ENV: prod working_dir: /var/www/html volumes: - "./website:/var/www/html" - "./website/vendor:/var/www/html/vendor:cached"
问题现象
可以通过Docker CLI执行mysql -h ${HOST} -P 3306 -u ${USER} -D ${DB} -p(其中HOST为AWS RDS端点)成功连接数据库,说明容器能正常解析主机名。但执行任何访问数据库的Symfony命令时,都会出现连接错误:
docker@724cef2e8b7a:/var/www/html$ php bin/console doctrine:query:sql 'SELECT * FROM product;' 11:27:30 ERROR [console] Error thrown while running command "doctrine:query:sql 'SELECT * FROM product;'" Message: "An exception occured in driver: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known" ["exception" => Doctrine\DBAL\Exception\ConnectionException { …},"command" => "doctrine:query:sql 'SELECT * FROM product;'","message" => "An exception occured in driver: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known"] In AbstractMySQLDriver.php line 103: An exception occured in driver: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known In PDOConnection.php line 47: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known In PDOConnection.php line 43: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known In PDOConnection.php line 43: PDO::__construct(): php_network_getaddresses: getaddrinfo failed: Name or service not known
参数配置
parameters.dist文件已配置正确的数据库主机名及相关参数:
# This file is auto-generated during the composer install parameters: database_host: ${DB_HOST} database_port: 3306 database_name: ${DB_NAME} database_user: ${DB_USER} database_password: ${DB_PASS} mailer_transport: smtp mailer_host: 127.0.0.1 mailer_user: null mailer_password: null secret: ThisTokenIsNotSoSecretChangeIt mail_from_email: null mail_from_name: null portal_url: null portal_asset_url: null wkhtmltopdf_binary: /usr/local/bin/wkhtmltopdf.sh sendgrid_api_key: ${SENDGRID_KEY}
解决方案
确保环境变量传入容器:
parameters.dist中使用的${DB_HOST}等环境变量需要在app容器中存在。可以在docker-compose.yml的app服务的environment字段中添加这些变量:environment: # 原有环境变量... DB_HOST: "你的RDS端点地址" DB_NAME: "目标数据库名" DB_USER: "数据库用户名" DB_PASS: "数据库密码" SENDGRID_KEY: "你的SendGrid密钥"也可以在docker-compose所在目录创建
.env文件,写入这些变量,docker-compose会自动加载该文件的环境变量。验证Symfony加载的参数是否正确:进入app容器执行以下命令,查看实际加载的数据库主机配置:
php bin/console debug:container --parameter=database_host如果返回的不是正确的RDS端点,说明参数未正确替换。需要执行
composer install生成parameters.yml文件,或者执行php bin/console cache:clear --env=prod清除生产环境缓存,确保参数被正确加载。测试PHP环境的DNS解析能力:虽然mysql命令行能解析RDS域名,但PHP的DNS解析可能存在问题。在容器中创建测试脚本
test_dns.php:<?php $host = getenv('DB_HOST'); var_dump(gethostbyname($host)); ?>执行
php test_dns.php,如果返回错误,说明PHP环境的DNS配置异常。可以在app服务的docker-compose配置中添加DNS服务器:dns: - 8.8.8.8 - 1.1.1.1确认RDS安全组规则:检查RDS实例的安全组入站规则,是否允许容器的出口IP访问3306端口。可以在容器中执行
curl ifconfig.me获取公网IP,然后将该IP添加到RDS安全组的入站规则中。
内容的提问来源于stack exchange,提问作者sakisk

