windowsのDcokerで構築したlaravelをAWSのEC2にデプロイする方法

AWS NO IMAGE

windowsのDcokerで構築したlaravelをAWSのEC2にデプロイします。

LEMP(Linux、Nginx、Mysql、Php)環境で構築を行います。

仕様ツール

・AWS Systems Manager
・AWS CloudFormation
・AWS EC2
・AWS RDS

手順

1.AWS EC2 インスタンス作成とssh接続

参考サイト:

https://zenn.dev/mai_mizz/articles/4a6b9e16dca99c
https://qiita.com/tsukamoto/items/1e0f3c8ecf4cba5cf485
https://www.softbank.jp/biz/blog/cloud-technology/articles/202309/cloudformation/

CloudFormationを利用したインスタンスの作成を行います。

CloudFormationとは、プロビジョニング(必要なものを準備すること、ITインフラの調達や設定など)およびサーバー設定のエリアにおける自動化および構成管理のためのサービスです。

分かりやすく言うと、管理画面から行うサーバーの設定を、コード化することができます。

そのコードがあれば、同じ環境を構築するのもとても簡単にできます。

AWS Systems Managerを始める

「Get Started with Systems Manager」ボタンを押します。

設定は以上です。

サーバー設定のテンプレートファイルの作成

「larablog」とEc2ImageIdとEc2KeyNameのdefaultを変更してください。

AWSTemplateFormatVersion: "2010-09-09"

Description: "template on EC2"

Parameters:
  ProjectName:
    Type: String
    Default: larablog

  VpcCidrBlock:
    Type: String
    Default: "10.0.0.0/16"
  PublicSubnetCidrBlock1:
    Type: String
    Default: "10.0.1.0/24"
  PublicSubnetCidrBlock2:
    Type: String
    Default: "10.0.2.0/24"
  PrivateSubnetCidrBlock1:
    Type: String
    Default: "10.0.3.0/24"
  PrivateSubnetCidrBlock2:
    Type: String
    Default: "10.0.4.0/24"

  Ec2ImageId:
    Type: String
    Default: ami-0d7bfdca2fa8d3cc4

Resources:
  # VPC
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidrBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-VPC"
  # サブネット
  MyPublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref PublicSubnetCidrBlock1
      AvailabilityZone: "ap-northeast-3a"
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-PublicSubnet1"
  MyPublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref PublicSubnetCidrBlock2
      AvailabilityZone: "ap-northeast-3c"
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-PublicSubnet2"
  MyPrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref PrivateSubnetCidrBlock1
      AvailabilityZone: "ap-northeast-3a"
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-PrivateSubnet1"
  MyPrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: !Ref PrivateSubnetCidrBlock2
      AvailabilityZone: "ap-northeast-3c"
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-PrivateSubnet2"

  # IGW設定
  MyInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-IGW"
  MyVPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref MyInternetGateway

  # ネットワーク設定/Public
  MyPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-PublicRouteTable"
  MyPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: MyInternetGateway
    Properties:
      RouteTableId: !Ref MyPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref MyInternetGateway
  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref MyPublicSubnet1
      RouteTableId: !Ref MyPublicRouteTable
  
  MySecurityGroupEC2:
    Type: AWS::EC2::SecurityGroup
    DependsOn: MyVPC
    Properties:
      GroupName: MySecurityGroup2
      GroupDescription: For EC2
      VpcId: !Ref MyVPC
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-SecurityGroup-ec2"
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0

        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
  
  # EC2定義
  NewKeyPair:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: !Sub "${ProjectName}-key"
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref Ec2ImageId
      KeyName: !Ref NewKeyPair
      InstanceType: t2.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          SubnetId: !Ref MyPublicSubnet1
          GroupSet:
            - !Ref MySecurityGroupEC2
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-EC2"

CloudFormationで構築

上記で作成した「ec2.yml」ファイルをアップロードします。

ファイルをアップロードして、次へのボタンをクリック

スタック名を記入して、あとは特に変更せずに、進めていきます。

作成を実行して、上の様な画面になれば成功です。

EC2のインスタンス一覧を見ると、問題なく実行されています。

ペアキーの確認

最近になって、CloudFormationでsshに必要なキーペアの追加もできるようになりました。

本来であれば、インスタンス作成時一回のみキーペアをダウロードすることができます。

CloudFormationで構築したときには、キーペアがダウンロードされることはありません。

パラメータストアから取得可能です。

赤い枠をクリックして、秘密鍵を取得します。

それを「~.pem」として、sshディレクトリに保存します。

SSHで接続

sshのキーを所定のディレクトリに移動して、権限の変更を行い、SSH接続を行います。

# sshのディレクトリにキーの移動
# sshの保存先に移動
cd C:\Users\user\.ssh
# AWSで権限の変更を下記コマンド実行を促されます。
chmod 400 sample-key.pem
# しかしwindows環境ではchmodは使用できないので、
$path = ".\sample-key.pem"
# 対象ファイルの既存の権限をリセットする
icacls.exe $path /reset
# 操作ユーザに読み取り権限(chmod 400)を付与
icacls.exe $path /GRANT:R "$($env:USERNAME):(R)"

# AWSに接続
ssh -i "sample-key.pem" ec2-user@ec0000-000-000-000.ap-northeast-1.compute.amazonaws.com

# 下記の画面になれば接続成功です。

   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-00-00-000~]$

上記の情はインスタンスの接続から確認できます。

2.EC2にdockerの構築

Docker Engineをインストールとdockerコマンドの実行

# yumパッケージのアップデート
sudo yum update -y
# Docker Engineをインストール
sudo dnf install -y docker
# システム起動時のDocker自動起動を有効化+起動
sudo systemctl enable --now docker
# Dockerサービスの状態を確認
systemctl status docker
# 下記が表示されれ場成功です。
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: disabled)
     Active: active (running) since Wed 2023-11-15 07:59:52 UTC; 6s ago
TriggeredBy: ● docker.socket
# 確認の停止
Ctrl + Z

# ec2-userでroot権限なしでdockerコマンドを操作できるようにする
sudo usermod -aG docker ec2-user
sudo su ec2-user
# バージョンの確認
docker -v
> Docker version 24.0.5, build ced0996

Docker Composeをインストール

DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
sudo mkdir -p $DOCKER_CONFIG/cli-plugins
# ここはDocker公式ドキュメント記載の最新バージョンに置き換える
# https://docs.docker.com/compose/install/linux/#install-using-the-repository
sudo curl -SL https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
#docker-composeの実行権限を適用
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
# Docker Composeのバージョンの確認
docker compose version
> Docker Compose version v2.20.3

Gitとプロジェクトのインストール

# Gitのインストール
sudo dnf install -y git
# プロジェクトのクローン
git clone git@github.com:XXXXX/XXXXXX.git
# プロジェクトに移動
cd laravel_project
# Dockerの起動
docker compose up -d
# 起動状況の確認
docker ps

3.Laravelの設定

# phpイメージに接続
# phpは環境によって変更してください
docker exec -it php bash
# 接続が成功すると下記になり、lsでファイルの確認
root@000000000:/src# ls
aws  docker  docker-compose.yml  laravel
# laravelに移動
cd laravel
# composerとnpmのインストールと実行
composer install
npm install
npm run build
# .envファイルの作成して、データベースの設定変更
cp .env.example .env
sudo dnf install -y vim-gnome
# シンボリックリンクの設置
chmod -R 777 storage
php artisan storage:link
# マイグレーションとキーの生成
php artisan migrate:fresh --seed
php artisan key:generate

上記を実行して、一度以下の赤枠からアクセスしてみます。

このときhttpsにアクセスしますが、httpに変更してください。

以下の画面が表示されれば成功です。

インストールが進まないとき

サーバーのレベルが低いと「npm install」実行時に、動かなくなる時があります。

そんな時は一度、ターミナルやpowershellを終了してください。

「npm install」をもう一度やり直します。

また、sshログインすらできなくなってしまった場合は、以下の紫枠でインスタンスの再起動をします。

再起動を行った場合は、sshの接続情報が変わりますので、接続上の確認をします。

4.RDS(データベース)の作成と接続

既にDockerでデータベースの構築が完了していますので、この設定は必要な場合に行って下さい。

参考サイト:
https://qiita.com/yyy752/items/601646d3683869521f9b

RDSの作成は割愛いたします。

RDSを作り終えた状況からの解説になります。

ターミナルでデータベースの確認

# キーの場所に移動
cd C:\Users\user\.ssh
# AWSに接続
ssh -i "sample-key.pem" ec2-user@ec0000-000-000-000.ap-northeast-1.compute.amazonaws.com
# パッケージのアップデート
sudo yum update -y
# MySQLをインストール
sudo yum -y install mysql
# 上記コマンドで下記コマンドが表示された場合
No match for argument: mysql
Error: Unable to find a match: mysql
# 下記コマンドでMySQLをインストール
sudo dnf -y localinstall https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm
sudo dnf -y install mysql mysql-community-client
sudo yum install mysql -y
# MySQLのバージョン確認
mysql --version
# MySQLに接続
mysql -h database.000000000.ap-northeast-3.rds.amazonaws.com -P 3306 -u admin -p
# パスワードの入力(RDSで設定したマスターパスワード)
Enter password:
# 下記が表示されれば、接続成功です。
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 177
Server version: 8.0.33 Source distribution
# データベースの確認
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| laravel_blog       |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.02 sec)

EC2とRDSの接続が確認できれば、Laravelの.envファイルのデータベースの設定を変更します。

DB_CONNECTION=mysql
DB_HOST=database-1.000000000.0000000.rds.amazonaws.com
DB_PORT=3306
DB_DATABASE=larablog-test
DB_USERNAME=admin
DB_PASSWORD=testtest