[PYTHON] Build a WardPress environment on AWS with pulumi

Introduction

Last time, I built the basic configuration (ec2 + rds environment) for running web applications on pulumi on AWS previous article.

This time, we will build the ALB + ec2 dynamic website configuration with pulumi. In addition, WordPress (docker container) is operated in the AWS environment built with pulumi.

Diagram

スクリーンショット 2020-07-28 0.38.26.png

Actual code

Whole code

This is the pulumi code created this time.

__main__.py


import pulumi
import pulumi_aws as aws

#Creating a VPC
vpc = aws.ec2.Vpc(
    "pulumi-vpc",
    cidr_block="10.0.0.0/16",
    tags={
        "Name": "pulumi-vpc",
    })

#Creating a Subnet
public_subnet_a = aws.ec2.Subnet(
    "pulumi-public-subnet-a",
    cidr_block="10.0.1.0/24",
    availability_zone="ap-northeast-1a",
    tags={
        "Name": "pulumi-public-subnet-a",
    },
    vpc_id=vpc.id)

public_subnet_c = aws.ec2.Subnet(
    "pulumi-public-subnet-c",
    cidr_block="10.0.2.0/24",
    availability_zone="ap-northeast-1c",
    tags={
        "Name": "pulumi-public-subnet-c",
    },
    vpc_id=vpc.id)

private_subnet_a = aws.ec2.Subnet(
    "pulumi-private-subnet-a",
    cidr_block="10.0.3.0/24",
    availability_zone="ap-northeast-1a",
    tags={
        "Name": "pulumi-private-subnet-a",
    },
    vpc_id=vpc.id)

private_subnet_c = aws.ec2.Subnet(
    "pulumi-private-subnet-c",
    cidr_block="10.0.4.0/24",
    availability_zone="ap-northeast-1c",
    tags={
        "Name": "pulumi-private-subnet-c",
    },
    vpc_id=vpc.id)

#Creating an Internet Gateway
igw = aws.ec2.InternetGateway(
    "pulumi-igw",
    tags={
        "Name": "pulumi-igw",
    },
    vpc_id=vpc.id)

#Creating an EIP
ngw_eip_a = aws.ec2.Eip("pulumi-ngw-eip-a")

ngw_eip_c = aws.ec2.Eip("pulumi-ngw-eip-c")

#Creating Nat Gateway
ngw_a = aws.ec2.NatGateway(
    "pulumi-ngw-a",
    allocation_id=ngw_eip_a.id,
    subnet_id=public_subnet_a.id)

#Creating Nat Gateway
ngw_c = aws.ec2.NatGateway(
    "pulumi-ngw-c",
    allocation_id=ngw_eip_c.id,
    subnet_id=public_subnet_c.id)

#Creating a RouteTable
public_route_table_a = aws.ec2.RouteTable(
    "pulumi-public-route-table-a",
    routes=[
        {
            "cidr_block": "0.0.0.0/0",
            "gateway_id": igw.id,
        },
    ],
    tags={
        "Name": "pulumi-public-route-table-a",
    },
    vpc_id=vpc.id)

public_route_table_c = aws.ec2.RouteTable(
    "pulumi-public-route-table-c",
    routes=[
        {
            "cidr_block": "0.0.0.0/0",
            "gateway_id": igw.id,
        },
    ],
    tags={
        "Name": "pulumi-public-route-table-c",
    },
    vpc_id=vpc.id)

private_route_table_a = aws.ec2.RouteTable(
    "pulumi-private-route-table-a",
    routes=[
        {
            "cidr_block": "0.0.0.0/0",
            "nat_gateway_id": ngw_a.id,
        },
    ],
    tags={
        "Name": "pulumi-private-route-table-a",
    },
    vpc_id=vpc.id)

private_route_table_c = aws.ec2.RouteTable(
    "pulumi-private-route-table-c",
    routes=[
        {
            "cidr_block": "0.0.0.0/0",
            "nat_gateway_id": ngw_c.id,
        },
    ],
    tags={
        "Name": "pulumi-private-route-table-c",
    },
    vpc_id=vpc.id)

#Creating a RouteTableAssociation
route_table_association_public_a = aws.ec2.RouteTableAssociation(
    "pulumi-route-table-association-public-a",
    subnet_id=public_subnet_a.id,
    route_table_id=public_route_table_a.id)

route_table_association_public_c = aws.ec2.RouteTableAssociation(
    "pulumi-route-table-association-public-c",
    subnet_id=public_subnet_c.id,
    route_table_id=public_route_table_c.id)

route_table_association_private_a = aws.ec2.RouteTableAssociation(
    "pulumi-route-table-association-private-a",
    subnet_id=private_subnet_a.id,
    route_table_id=private_route_table_a.id)

route_table_association_private_c = aws.ec2.RouteTableAssociation(
    "pulumi-route-table-association-private-c",
    subnet_id=private_subnet_c.id,
    route_table_id=private_route_table_c.id)

#Creating a Security Group
alb_sg = aws.ec2.SecurityGroup(
    "pulumi-alb-sg",
    ingress=[
        {
            "from_port": 80,
            "protocol": "TCP",
            "to_port": 80,
            "cidr_blocks": ["0.0.0.0/0"]
        },
    ],
    egress=[
        {
            "from_port": 0,
            "protocol": "TCP",
            "to_port": 65535,
            "cidr_blocks": ["0.0.0.0/0"]
        },
    ],
    tags={
        "Name": "pulumi-alb-sg",
    },
    vpc_id=vpc.id)

ec2_sg = aws.ec2.SecurityGroup(
    "pulumi-ec2-sg",
    ingress=[
        {
            "from_port": 80,
            "protocol": "TCP",
            "to_port": 80,
            "security_groups": [alb_sg.id]
        },
    ],
    egress=[
        {
            "from_port": 0,
            "protocol": "TCP",
            "to_port": 65535,
            "cidr_blocks": ["0.0.0.0/0"]
        },
    ],
    tags={
        "Name": "pulumi-ec2-sg",
    },
    vpc_id=vpc.id)

rds_sg = aws.ec2.SecurityGroup(
    "pulumi-rds-sg",
    ingress=[
        {
            "from_port": 3306,
            "protocol": "TCP",
            "to_port": 3306,
            "security_groups": [ec2_sg.id]
        },
    ],
    egress=[
        {
            "from_port": 0,
            "protocol": "TCP",
            "to_port": 65535,
            "cidr_blocks": ["0.0.0.0/0"]
        },
    ],
    tags={
        "Name": "pulumi-rds-sg",
    },
    vpc_id=vpc.id)

#Creating a Key Pair
key_pair = aws.ec2.KeyPair(
    "pulumi-keypair",
    public_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 [email protected]",
    tags={
        "Name": "pulumi-keypair",
    })

#Creating a TargetGroup
target_group = aws.alb.TargetGroup(
    "pulumi-target-group",
    health_check={
        "healthyThreshold": 5,
        "interval": 30,
        "matcher": "200,302",
        "path": "/",
        "protocol": "HTTP",
        "timeout": 5,
        "unhealthyThreshold": 2
    },
    name="pulumi-target-group",
    port=80,
    protocol="HTTP",
    tags={
        "Name": "pulumi-target-group",
    },
    target_type="instance",
    vpc_id=vpc.id)

#Reading user data
file = open("./user-data")
user_data = file.read()

#Creating a Launch Configuration
launch_conf = aws.ec2.LaunchConfiguration(
    "pulumi-launch-conf",
    image_id="ami-0ee1410f0644c1cac",
    instance_type="t2.micro",
    associate_public_ip_address=True,
    key_name=key_pair.key_name,
    security_groups=[ec2_sg.id],
    user_data=user_data)

file.close()

#Creating an Auto Scaling Group
autoscaling_group = aws.autoscaling.Group(
    "pulumi-autoscaling-group",
    availability_zones=["ap-northeast-1a", "ap-northeast-1c"],
    health_check_type="ELB",
    desired_capacity=1,
    launch_configuration=launch_conf.name,
    max_size=1,
    min_size=1,
    target_group_arns=[target_group.arn],
    vpc_zone_identifiers=[
        private_subnet_a.id,
        private_subnet_c.id
    ])

#Creating a Load Balancer
alb = aws.alb.LoadBalancer(
    "pulumi-alb",
    load_balancer_type="application",
    name="pulumi-alb",
    security_groups=[alb_sg.id],
    subnets=[
        public_subnet_a.id,
        public_subnet_c.id
    ],
    tags={
        "Name": "pulumi-alb",
    })

#Creating a Listener
alb_listener = aws.alb.Listener(
    "pulumi-alb-listener",
    default_actions=[{
        "target_group_arn": target_group.arn,
        "type": "forward",
    }],
    load_balancer_arn=alb.arn,
    port="80",
    protocol="HTTP")

#Creating an RDS Subnet Group
rds_subnet = aws.rds.SubnetGroup(
    "pulumi-rds-subnet",
    subnet_ids=[
        private_subnet_a.id,
        private_subnet_c.id,
    ],
    tags={
        "Name": "pulumi-rds-subnet",
    })

#Create an RDS instance
rds = aws.rds.Instance(
    "pulumi-rds",
    allocated_storage=20,
    db_subnet_group_name=rds_subnet.name,
    engine="mysql",
    engine_version="5.7",
    identifier="pulumi-rds",
    instance_class="db.t2.micro",
    name="pulumi",
    parameter_group_name="default.mysql5.7",
    password="password",
    skip_final_snapshot=True,
    storage_type="gp2",
    tags={
        "Name": "pulumi-rds",
    },
    username="admin",
    vpc_security_group_ids=[rds_sg.id])

user-data


#!/bin/bash

yum install docker -y

service docker start

docker pull wordpress

docker run -p 80:80 -d wordpress

NAT Gateway, Route Table (for private subnet)

This time, launch EC2, which hosts the application, with a private subnet. Created NAT Gateway and Route Table for it so that EC2 can get out to the Internet

#Creating an EIP to be linked to NAT Gateway
ngw_eip_a = aws.ec2.Eip("pulumi-ngw-eip-a")

ngw_eip_c = aws.ec2.Eip("pulumi-ngw-eip-c")

#Creating Nat Gateway
ngw_a = aws.ec2.NatGateway(
    "pulumi-ngw-a",
    allocation_id=ngw_eip_a.id,
    subnet_id=public_subnet_a.id)

#Creating Nat Gateway
ngw_c = aws.ec2.NatGateway(
    "pulumi-ngw-c",
    allocation_id=ngw_eip_c.id,
    subnet_id=public_subnet_c.id)

#Creating a RouteTable for a private subnet
#Adding a route for NAT Gateway
private_route_table_a = aws.ec2.RouteTable(
    "pulumi-private-route-table-a",
    routes=[
        {
            "cidr_block": "0.0.0.0/0",
            "nat_gateway_id": ngw_a.id,
        },
    ],
    tags={
        "Name": "pulumi-private-route-table-a",
    },
    vpc_id=vpc.id)

private_route_table_c = aws.ec2.RouteTable(
    "pulumi-private-route-table-c",
    routes=[
        {
            "cidr_block": "0.0.0.0/0",
            "nat_gateway_id": ngw_c.id,
        },
    ],
    tags={
        "Name": "pulumi-private-route-table-c",
    },
    vpc_id=vpc.id)

#Linking RouteTable and subnet
route_table_association_private_a = aws.ec2.RouteTableAssociation(
    "pulumi-route-table-association-private-a",
    subnet_id=private_subnet_a.id,
    route_table_id=private_route_table_a.id)

route_table_association_private_c = aws.ec2.RouteTableAssociation(
    "pulumi-route-table-association-private-c",
    subnet_id=private_subnet_c.id,
    route_table_id=private_route_table_c.id)

LaunchConfiguration、AutoScalingGroup、TargetGroup Create Launch Configuration and Auto Scaling Group Also, create a TargetGroup to link ALB and AutoScalingGroup.

#Creating a TargetGroup
target_group = aws.alb.TargetGroup(
    "pulumi-target-group",
    health_check={
        "healthyThreshold": 5,
        "interval": 30,
        "matcher": "200,302",
        "path": "/",
        "protocol": "HTTP",
        "timeout": 5,
        "unhealthyThreshold": 2
    },
    name="pulumi-target-group",
    port=80,
    protocol="HTTP",
    tags={
        "Name": "pulumi-target-group",
    },
    target_type="instance",
    vpc_id=vpc.id)

#Reading user data
file = open("./user-data")
user_data = file.read()

#Creating a Launch Configuration
launch_conf = aws.ec2.LaunchConfiguration(
    "pulumi-launch-conf",
    image_id="ami-0ee1410f0644c1cac",
    instance_type="t2.micro",
    associate_public_ip_address=True,
    key_name=key_pair.key_name,
    security_groups=[ec2_sg.id],
    user_data=user_data)

file.close()

#Creating an Auto Scaling Group
autoscaling_group = aws.autoscaling.Group(
    "pulumi-autoscaling-group",
    availability_zones=["ap-northeast-1a", "ap-northeast-1c"],
    health_check_type="ELB",
    desired_capacity=1,
    launch_configuration=launch_conf.name,
    max_size=1,
    min_size=1,
    target_group_arns=[target_group.arn],
    vpc_zone_identifiers=[
        private_subnet_a.id,
        private_subnet_c.id
    ])

About the setting of health_check of TargetGroup Since it is redirected when accessing / of WordPress, the status code (302) of redirect is also added to the setting value of matcher.

About user_data of LaunchConfiguration, it is read from another file The contents of user_data will be described later.

ALB Create ALB and Listener.

#Creating a Load Balancer
alb = aws.alb.LoadBalancer(
    "pulumi-alb",
    load_balancer_type="application",
    name="pulumi-alb",
    security_groups=[alb_sg.id],
    subnets=[
        public_subnet_a.id,
        public_subnet_c.id
    ],
    tags={
        "Name": "pulumi-alb",
    })

#Create Listener (HTTP)
alb_listener = aws.alb.Listener(
    "pulumi-alb-listener",
    default_actions=[{
        "target_group_arn": target_group.arn,
        "type": "forward",
    }],
    load_balancer_arn=alb.arn,
    port="80",
    protocol="HTTP")

This time, I created a Listener with HTTP, but when creating an HTTPS Listener, it is also necessary to set the certificate etc. as follows.

#Create Listener (HTTPS)
alb_listener = aws.alb.Listener(
    "pulumi-alb-listener",
    certificate_arn="arn:aws:iam::187416307283:server-certificate/test_cert_rab3wuqwgja25ct3n4jdj2tzu4",
    default_actions=[{
        "target_group_arn": target_group.arn,
        "type": "forward",
    }],
    load_balancer_arn=alb.arn,
    port="443",
    protocol="HTTPS",
    ssl_policy="ELBSecurityPolicy-2016-08")

User data

This time, start the WordPress image registered in Docker hub Install and start docker and start WordPress container with user data

user-data


#!/bin/bash

#install docker
yum install docker -y

#Start docker daemon
service docker start

#Pull WordPress image
docker pull wordpress

#Launch a WordPress container
docker run -p 80:80 -d wordpress

Summary

This time, I created a typical AWS configuration for running a dynamic website with pulumi and started the WordPress docker container.

The AWS resources created in the previous article are not explained in detail this time, so please refer to Previous article if you like.

bonus

Actually access

Language setting スクリーンショット 2020-07-28 1.46.46.png

Database information settings Here, enter the RDS settings you created earlier. スクリーンショット 2020-07-28 1.47.05.png

User information settings スクリーンショット 2020-07-28 1.48.27.png

Screen after WordPress login スクリーンショット 2020-07-28 1.49.46.png

Recommended Posts

Build a WardPress environment on AWS with pulumi
Build a python environment with ansible on centos6
# 2 Build a Python environment on AWS EC2 instance (ubuntu18.04)
Build a python3 environment on CentOS7
Easily build a development environment with Laragon
Build a python environment on MacOS (Catallina)
Build a Tensorflow environment with Raspberry Pi [2020]
Build a Fast API environment with docker-compose
Build Python environment with Anaconda on Mac
[Linux] Build a jenkins environment with Docker
Build a python virtual environment with pyenv
Build a Python + OpenCV environment on Cloud9
Build a modern Python environment with Neovim
[Linux] Build a Docker environment with Amazon Linux 2
Build a 64-bit Python 2.7 environment with TDM-GCC and MinGW-w64 on Windows 7
Build a Flask / Bottle-like web application on AWS Lambda with Chalice
Build a Python environment on your Mac with Anaconda and PyCharm
# 3 Build a Python (Django) environment on AWS EC2 instance (ubuntu18.04) part2
Build a LAMP environment on your local Docker
Build a C language development environment with a container
Procedure for building a kube environment on amazon linux2 (aws) ~ (with bonus)
Try Tensorflow with a GPU instance on AWS
Build python environment with pyenv on EC2 (ubuntu)
Simply build a Python 3 execution environment on Windows
Build a Python + bottle + MySQL environment with Docker on RaspberryPi3! [Easy construction]
Build a Django environment on Raspberry Pi (MySQL)
Build a Python environment on Mac (Mountain Lion)
[Python] Build a Django development environment with Docker
Create a python3 build environment with Sublime Text3
Build a cheap summarization system with AWS components
Build a Django environment with Vagrant in 5 minutes
Build a Python development environment on your Mac
[Memo] Build a virtual environment with Pyenv + anaconda
Build a virtual environment with pyenv and venv
Build a Django development environment with Doker Toolbox
Build a Kubernetes environment for development on Ubuntu
Build a Python environment with OSX El capitan
Quickly build a Python Django environment with IntelliJ
Build a Python machine learning environment with a container
Build a Python development environment on Raspberry Pi
Build a python execution environment with VS Code
Build a Python + bottle + MySQL environment with Docker on RaspberryPi3! [Trial and error]
Build a TensorFlow development environment on Amazon EC2 with command copy and paste
Easily build HPC on AWS with genuine AWS Cfn Cluster
Build a GVim-based Python development environment on Windows 10 (3) GVim8.0 & Python3.6
Build a Django development environment using pyenv-virtualenv on Mac
Build a python virtual environment with virtualenv and virtualenvwrapper
Build a local development environment for Laravel6.X on Mac
Build a machine learning Python environment on Mac OS
Build a python environment for each directory with pyenv-virtualenv
I made a Python3 environment on Ubuntu with direnv.
Build a GVim-based Python development environment on Windows 10 (1) Installation
How to build a Django (python) environment on docker
Build a Python development environment on Mac OS X
Build a Python environment on your Mac using pyenv
Build a machine learning application development environment with Python
Build a python virtual environment with virtualenv and virtualenvwrapper
Build a Python development environment using pyenv on MacOS
Notes on creating a virtual environment with Anaconda Navigator
Build a development environment with Poetry Django Docker Pycharm
How to build a Python environment on amazon linux 2