Dockerをさわってみる① (環境構築+WordPressを動かす)

11 min read読了の目安(約10500字

はじめに

今回はDockerをEC2上にインストールして、WordPressを動かしてみるところまでをやってみます。
Dockerをなんとなく知っているが触ったことがない、という方向けのハンズオンになります。

Dockerとは

https://knowledge.sakura.ad.jp/13265/

Dockerは、インフラ関係やDevOps界隈で注目されている技術の一つで、Docker社が開発している、コンテナ型の仮想環境を作成、配布、実行するためのプラットフォームです。

物理基盤、仮想化、コンテナの違い

物理基盤 仮想化 コンテナ
1つの物理基盤に1つのOSが稼働
ホストOSがシステム全体を管理
ハードウェアの性を享受できる
トランザクション処理向き
高可用性・無停止システムで利用
ハイパーバイザーが介在
仮想的なハードウェアが存在
オーバーヘッドが存在
仮想ディスクにブートローダーが必須
ゲストOSの起動・停止の管理が必要
ランタイムをパッケージ化
オーバーヘッドがほぼ0
ホストOSからプロセスとして見える
非常に軽量なアプリ環境を実現
ソフト開発の工数軽減

Dockerのメリット

  • コンテナをコードで管理するため、再利用可能となる
  • 誰でも別の環境でも同じ環境が作れる
  • コンテナをコードで管理するため、構成管理が容易になる。

ハンズオンの構成

以下が、今回ハンズオンで作成する環境となります。

  1. インターネットからSSH(22番ポート)とHTTP(8080番ポート)のアクセスを許可しているEC2インスタンスをPublicサブネットに作成します。
  2. 上記で作成したEC2インスタンスに、Dockerエンジンをインストールします。
  3. WordPressとMySQLのDockerイメージを取得し、起動します。
  4. WordPressによるブログサイトが構築できていることを確認します。

ハンズオン

環境構築

まずは、Dockerを動かすための環境をリモートサーバーに構築していきます。
AWSのEC2上に環境を構築するため、AWSのサービスでCloudFormationを使います。

CloudFormationについては以下で記事を書いていますので、こちらを参考にしてください。

https://zenn.dev/soshimiyamoto/articles/3c624728438902

まずは、以下のテンプレートでVPC, Subnet, InternetGatewayを作成します。
別のスタックでこれらの情報を利用するため、OutputsセクションでVPC、Subnetの情報を
出力しておきます。

network.yml
AWSTemplateFormatVersion: 2010-09-09

Resources: 

  # ------------------------------------------------------------#
  #  VPC
  # ------------------------------------------------------------#
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
      - Key: Name
        Value: MyVPC
  
  # ------------------------------------------------------------#
  #  Internet Gateway
  # ------------------------------------------------------------#
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: My-InternetGateway
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref InternetGateway

  # ------------------------------------------------------------#
  #  Route Table
  # ------------------------------------------------------------#
  RouteTable:
    Type: AWS::EC2::RouteTable
    DependsOn: AttachGateway
    Properties:
      VpcId: !Ref MyVPC
      Tags:
      - Key: Name
        Value: My-RouteTable
  Route:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  
  # ------------------------------------------------------------#
  #  Public Sunbet A
  # ------------------------------------------------------------#
  PublicSubnetA:
    Type: AWS::EC2::Subnet
    DependsOn: AttachGateway
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: 'true'
      VpcId: !Ref MyVPC
      Tags:
      - Key: Name
        Value: PublicSubnetA
  PublicRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref RouteTable  

Outputs:
  VPC1:
    Value: !Ref MyVPC
    Export: 
      Name: VPCName
  SubnetA:
    Value: !Ref PublicSubnetA
    Export:
      Name: SubnetName

次に、EC2インスタンスにアタッチするセキュリティグループを作成します。
インターネットからHTTP(8080ポート), SSH(22ポート)を許可するため、SecurityGroupIngressでインバウンドルールを指定します。

security.yml
AWSTemplateFormatVersion: 2010-09-09
Resources: 
  MySecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !ImportValue VPCName
      GroupDescription: Allow SSH from Internet
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 8081
          ToPort: 8080
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: WebServerSG

Outputs:
  MySecurityGroup:
    Value: !Ref MySecurityGroup
    Export: 
      Name: SecurityGroupName

最後に、以下のテンプレートでEC2インスタンスを起動します。

ec2.yml
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  KeyName:
    Description: The EC2 Key Pair
    Type: "AWS::EC2::KeyPair::KeyName"
  EC2AMIId:
    Description: AMI ID
    Type : String
    Default: ami-01748a72bed07727c

Resources: 
  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref KeyName
      ImageId: !Ref EC2AMIId
      InstanceType: t2.micro
      SubnetId: !ImportValue SubnetName
      SecurityGroupIds:
        - !ImportValue SecurityGroupName
      Tags:
        - Key: Name
          Value: WebServer

上記の3テンプレートからCloudFormationスタックを作成すると、前項で記載した構成を作成することができます。
各テンプレートの詳細な説明は割愛させていただきます。

DockerをEC2にインストールする

環境構築が完了したら、作成したEC2にDockerをインストールしていきます。
(今回は利用していませんが、docker-composeもインストールしています。)

以下のコマンドでまとめてインストールしてしまいます。

sudo yum update -y && \
sudo amazon-linux-extras install -y docker && \
sudo usermod -a -G docker ec2-user && \
sudo systemctl start docker.service && \
sudo systemctl status docker.service && \
sudo systemctl enable docker.service && \
sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose && \
sudo chmod +x /usr/local/bin/docker-compose && \
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

ここで、&&はAND演算子である。&&でコマンドをつなぐことで、コマンドが成功したら次のコマンドを実行するという動きを実現できます。

\は改行を表現しています。

  1. 以下でyumをupdateします。
sudo yum update -y
  1. 以下でdockerをインストールします。
sudo amazon-linux-extras install -y docker

Amazon Linux では、amazon-linux-extrasという独自のパッケージ管理ソフトが存在しており、これを利用することが多いです

  1. 以下でec2-userをdockerグループに追加します。これにより、dockerサービスをec2-userが実行できるようになります。
sudo usermod -a -G docker ec2-user

/etc/groupを確認すると、docker:x:992:ec2-userが追加されていることがわかります。
また、ec2-userでグループを確認すると、

$ groups
ec2-user adm wheel systemd-journal docker

のように、dockerグループに所属していることがわかります。

usermodを実行せずに、ec2-userでdockerコマンドを利用しようとすると以下のようなエラーとなるので注意してください。(docker service は起動済み)

$ docker images
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/json": dial unix /var/run/docker.sock: connect: permission denied
  1. 以下でDockerのサービスを起動し、ステータスを確認する。
sudo systemctl start docker.service
sudo systemctl status docker.service
  1. 以下のコマンドでdockerの起動設定をONにし、EC2再起動後もDockerが起動状態となる。
sudo systemctl enable docker.service
  1. 以下のコマンドでdocker-composeをインストール&権限変更を実施する。
sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose && \
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

以下参考

https://docs.docker.jp/compose/install.html#linux-compose

上記のコマンドをEC2のユーザーデータとして記述すれば、EC2インスタンスが起動すると同時にdockerのインストールも可能となる。

ec2.yml(修正後)
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  KeyName:
    Description: The EC2 Key Pair
    Type: "AWS::EC2::KeyPair::KeyName"
  EC2AMIId:
    Description: AMI ID
    Type : String
    Default: ami-01748a72bed07727c

Resources: 
  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref KeyName
      ImageId: !Ref EC2AMIId
      InstanceType: t2.micro
      SubnetId: !ImportValue SubnetName
      SecurityGroupIds:
        - !ImportValue SecurityGroupName
      Tags:
        - Key: Name
          Value: WebServer
      UserData:
        Fn::Base64: |
          #!/bin/bash
          sudo yum update -y && \
          sudo amazon-linux-extras install  -y docker && \
          sudo usermod -a -G docker ec2-user && \
          sudo systemctl start docker.service && \
          sudo systemctl status docker.service && \
          sudo systemctl enable docker.service && \
          sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose && \
          sudo chmod +x /usr/local/bin/docker-compose && \
          sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

これらのテンプレートを使いまわせば、いつでもdockerを利用できるLinux環境が手に入ります。

WordPressを動かす

上記でDockerコマンドが利用できるようになったので、手始めにdockerコマンドを試してみます。

  • dockerイメージを表示
$ docker images 
REPOSITORY   TAG     IMAGE ID   CREATED   SIZE
  • dockerコンテナを表示(-aで停止中のコンテナも含めて表示されます)
$ docker ps -a 
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

特にdockerイメージをpullしたわけでも、起動したわけでもないので、何も表示されません。

  • MySQLのDockerコンテナを起動
docker run --name mysql_db -e MYSQL_ROOT_PASSWORD=passwd -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=passwd -d mysql:5.7.21

docker runコマンドで、mysqlのコンテナを起動状態で作成します。
--nameオプションで、コンテナ名をmysql_dbに、-eオプションでMySQLの環境情報を設定しています。

MySQLのバージョンを5.7にしないとダメとのこと。

  • WordPressのDockerコンテナを起動
docker run --name wp_site --link mysql_db:mysql -p 8080:80 -e WORDPRESS_DB_HOST=mysql_db:3306 -e WORDPRESS_DB_USER=wordpress -e WORDPRESS_DB_PASSWORD=passwd -d wordpress

MySQLのコンテナと同様、docker runコマンドでWordPressコンテナを起動状態で作成します。-pオプションで、EC2上の8080ポートを、コンテナの80ポートにバインドします。--linkオプションで、WordPressのコンテナをMySQLのコンテナにリンクします。

--linkオプションは古い機能であり、利用は推奨されないようです。
https://docs.docker.jp/v17.06/engine/userguide/networking/default_network/dockerlinks.html
本来はユーザー定義のネットワークを利用することが推奨されるそうです。

  • ブラウザでhttp://{EC2インスタンスのパブリックIP}:8080にアクセスします。

  • 日本語を選択し、次へ

  • WordPressサイトの設定を行う。

  • WordPressのインストールが完了する。

  • 上記設定をもとにログイン

  • WordPressの管理画面が表示される。

  • めちゃめちゃ簡単にWordPressサイトが構築できた!

まとめ

WordPressのDockerイメージを使って簡単にWordPressサイトを構築することができました。
WordPressだけでなく、様々なDockerイメージが存在しておりますので、いろいろ試してみると面白そうです。

今回は既存のDockerイメージを利用したので、次回は自分でDockerイメージを作成して、起動するところまでをやってみたいと思います。