PHP Slim 環境構築(12) 前回構築した環境をEC2上に
Introduction
前回は、DockerコンテナにNginxとPHP-FPMの両方を格納した構成をローカル環境に構築しました。
今回は、それをEC2上に構築します。
この一連のシリーズは、自分への備忘録が第一目的のため、相当不親切です。
すみません・・・
変更点
今回構築した環境では、ローカルPC上に構築したものをlocal環境、EC2上に構築したものをdevelopment環境と呼ぶことにしています。
今回は、前回作成したlocal環境をdevelopment環境にも適用するとともに、ソースを少し整理しました。
ソースツリー
今回の変更箇所です。
$(PROJECTROOT)
/aws
ec2-userdata.txt (新規)
/compose
/web_front
development.conf
/web_hoge
Dockerfile
settings.php (削除)
settings-development.yml (新規)
settings-local.yml (新規)
/src
/hoge
/lib
/Controller
DynamodbController.php
StorageController.php
MyContainerBuilder.php (新規)
/public
index.php
/test
RequestTest.php
composer.json
composer.lock
/aws/ec2-userdata.txt
EC2のユーザーデータをリポジトリに追加しました。
#!/bin/bash
cat <<'SYS_EOF' >> /etc/sysctl.conf
net.core.somaxconn=65535
SYS_EOF
sysctl -p /etc/sysctl.conf
cat > /etc/security/limits.d/20-filelimits.conf <<'FLIMIT_EOF'
* soft nofile 32768
* hard nofile 32768
FLIMIT_EOF
ulimit -n 32768
amazon-linux-extras install docker -y
systemctl enable docker
usermod -a -G docker ec2-user
service docker start
curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
yum install -yq git
cd /home/ec2-user
git clone https://github.com/dynamitecoolguy/slimtemplate.git
cd slimtemplate
git checkout chapter12
chown -R ec2-user:ec2-user .
cd compose
docker-compose -f docker-compose-common.yml -f docker-compose-development.yml up -d
/compose/web_front/development.conf
前回変更したlocal.confと同様に、nginxは単なるreverse proxyになります。
ssl_certificate /etc/certs/server.crt;
ssl_certificate_key /etc/certs/server.key;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
server {
listen 3128 default_server;
listen 8443 ssl default_server;
server_name _;
access_log /dev/stdout;
error_log /dev/stderr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://web_hoge:3128/;
}
}
/compose/web_hoge/Dockerfile
環境用設定ファイルをPHP直書きから、ymlに変更しました。
また、各環境用の設定ファイルを用意することにしました。
...(略)...
# COPY settings.php /var/www/settings.php
COPY settings-${environment}.yml /var/www/settings.yml
...(略)...
/compose/web_hoge/settings-development.yml, settings-local.yml
以前までのsettings.phpをymlに変更しました。また、ソースに直書きしていたキーなどもこのファイルに抜き出しました。
なお、settings-development.ymlとsettings-local.ymlの内容は同じです。
userdb:
host: mysql
dbname: userdb
user: scott
password: tiger
logdb:
host: postgresql
dbname: logdb
user: root
password: hogehoge
redis:
host: redis
dynamodb:
endpoint: http://dynamodb:8000
region: ap-northeast-1
key: dummy-key
secret: dummy-secret
table: hogehoge
storage:
endpoint: http://storage:9000
region: ap-northeast-1
key: minio
secret: miniminio
bucket: dummy
/src/hoge/lib/Controller/DynamodbController.php, StorageController.php
ソースコードに直接記述していたdynamoDBのテーブル名、S3のバケット名を設定ファイルを参照するようにしました。
...(略)...
$result = $dynamodb->describeTable([
//'TableName' => 'hogehoge'
'TableName' => $this->getTable()
]);
...(略)...
...('hogehoge'を変更した箇所が後3か所)...
...(略)...
private function getTable(): string
{
$setting = $this->container->get('settings')['dynamodb'];
return $setting['table'];
}
...(略)...
...(略)...
//$s3->headBucket(['Bucket' => 'dummy']);
$s3->headBucket(['Bucket' => $this->getBucket()]);
...(略)...
...('dummy'を変更した箇所が後3か所)...
...(略)...
private function getBucket(): string
{
$setting = $this->container->get('settings')['storage'];
return $setting['bucket'];
}
...(略)...
/src/hoge/lib/MyContainerBuilder.php
設定用ymlファイルを読み込み、必要な定義を組み込み済みのContainerBuilderです。
DI\ContainerBuilderを継承しています。
<?php
namespace Hoge;
use Aws\Sdk;
use PDO;
use Psr\Container\ContainerInterface;
use DI\Container;
use DI\ContainerBuilder;
use Redis;
class MyContainerBuilder extends ContainerBuilder
{
public function __construct(string $containerClass = Container::class)
{
parent::__construct($containerClass);
$this->addDefaultDefinitions();
}
private function addDefaultDefinitions(): void
{
$parsed = yaml_parse_file(__DIR__ . '/../../settings.yml');
$this->addDefinitions(['settings' => $parsed]);
$this->addDefinitions([
'userdb' => function (ContainerInterface $container)
{
$settings = $container->get('settings')['userdb'];
$dsn = 'mysql:host=' . $settings['host'] . ';dbname=' . $settings['dbname'];
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];
return new PDO($dsn, $settings['user'], $settings['password'], $options);
},
'logdb' => function (ContainerInterface $container)
{
$settings = $container->get('settings')['logdb'];
$dsn = 'pgsql:host=' . $settings['host'] . ';dbname=' . $settings['dbname'];
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
];
return new PDO($dsn, $settings['user'], $settings['password'], $options);
},
'redis' => function (ContainerInterface $container)
{
$settings = $container->get('settings')['redis'];
$redis = new Redis();
$redis->connect($settings['host']);
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_IGBINARY);
return $redis;
},
'dynamodb' => function (ContainerInterface $container)
{
$settings = $container->get('settings')['dynamodb'];
$sdk = new Sdk([
'endpoint' => $settings['endpoint'],
'region' => $settings['region'],
'version' => '2012-08-10',
'credentials' => [
'key' => $settings['key'],
'secret' => $settings['secret']
]
]);
$dynamodb = $sdk->createDynamoDb();
return $dynamodb;
},
'storage' => function (ContainerInterface $container)
{
$settings = $container->get('settings')['storage'];
$sdk = new Sdk([
'endpoint' => $settings['endpoint'],
'region' => $settings['region'],
'version' => '2006-03-01',
'credentials' => [
'key' => $settings['key'],
'secret' => $settings['secret']
],
'use_path_style_endpoint' => true
]);
$s3 = $sdk->createS3();
return $s3;
}
]);
}
}
/src/hoge/public/index.php
DI部分を上記のMyContainerBuilderに分割したので、必要ない部分を削除しました。
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Routing\RouteCollectorProxy;
use Hoge\ExampleAfterMiddleware;
use Hoge\ExampleBeforeMiddleware;
use Hoge\MyContainerBuilder;
use Hoge\Controller\PlayerController;
use Hoge\Controller\PlayerCreatedLogController;
use Hoge\Controller\RedisController;
use Hoge\Controller\DynamodbController;
use Hoge\Controller\StorageController;
/** @var Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../vendor/autoload.php';
$loader->addPsr4('Hoge\\', __DIR__ . '/../lib');
$containerBuilder = new MyContainerBuilder();
$container = $containerBuilder->build();
AppFactory::setContainer($container);
$app = AppFactory::create();
// Middleware
$contentLengthMiddleware = new \Slim\Middleware\ContentLengthMiddleware();
$app->add($contentLengthMiddleware);
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write('Hello, World!');
return $response;
})
->add(new ExampleBeforeMiddleware())
->add(new ExampleAfterMiddleware());
$app->group('/player', function (RouteCollectorProxy $group) {
$group->get('/{id}', PlayerController::class . ':get');
$group->post('', PlayerController::class . ':post');
$group->put('/{id}', PlayerController::class . ':put');
});
$app->group('/player_created', function (RouteCollectorProxy $group) {
$group->get('/{id}', PlayerCreatedLogController::class . ':get');
$group->get('', PlayerCreatedLogController::class . ':list');
});
$app->group('/redis', function (RouteCollectorProxy $group) {
$group->get('/{key}', RedisController::class . ':get');
$group->post('', RedisController::class . ':post');
$group->put('/{key}', RedisController::class . ':put');
$group->delete('/{key}', RedisController::class . ':delete');
});
$app->group('/dynamodb', function (RouteCollectorProxy $group) {
$group->get('/{key}', DynamodbController::class . ':get');
$group->post('', DynamodbController::class . ':post');
});
$app->group('/storage', function (RouteCollectorProxy $group) {
$group->get('/{filename}', StorageController::class . ':get');
$group->post('', StorageController::class . ':post');
});
$app->run();
/src/hoge/test/RequestTest.php
テスト用コードも、設定用ymlから情報を取り込むように変更しました。
(ソースコード略)。
/src/hoge/composer.json, compser.lock
yamlの使用に伴い、composer require yamlを行いました。
{
"require": {
"slim/slim": "4.2.0",
"slim/psr7": "0.5.0",
"php-di/php-di": "6.0.9",
"ext-pdo": "^7.2",
"ext-json": "^1.6",
"ext-redis": "^3.1",
"ext-curl": "*",
"ext-yaml": "*",
"aws/aws-sdk-php": "^3.112"
},
"require-dev": {
"phpunit/phpunit": "^8.4"
}
}
ここまでのソース
こちらでどうぞ。