Based on what I've done in previous week9, open a new gitpod workspace and do the following steps (in the end, changes are committed to the branch of week-10 and then merged to the main branch):
- Preparation
- Template and Config
- Command
- Static Website Hosting for Frontend
- Settings for DB
- Clean Up
Update gitpod.yml
to install cfn-lint, cfn-guard, cfn-toml, etc.
Create two S3 buckets cfn-artifacts-beici
and codepipeline-cruddur-artifacts-beici
by:
aws s3 mb s3://cfn-artifacts-beici
export CFN_BUCKET="cfn-artifacts-beici"
gp env CFN_BUCKET="cfn-artifacts-beici"
aws s3 mb s3://codepipeline-cruddur-artifacts-beici
Create a new folder aws/cfn
to save template and config (change to your own parameters) for each CloudFormation stack, including:
- Base networking components:
networking/template.yaml
andnetworking/config.toml
- Networking and cluster configuration to support Fargate containers:
cluster/template.yaml
(change to your own namespace) andcluster/config.toml
- RDS database for the application:
db/template.yaml
anddb/config.toml
- Fargate backend service:
service/template.yaml
(change to your own namespace, role and policy names) andservice/config.toml
- CICD for the backend servie:
cicd/nested/codebuild.yaml
,cicd/template.yaml
,cicd/config.toml
- Frontend:
frontend/template.yaml
andfrontend/config.toml
- Sync changes for the frontend:
sync/template.yaml
andsync/config.toml
- Dedicated user role for CFN:
machine-user/template.yaml
andmachine-user/config.toml
Create and run command scripts for the above CFN, then we can execute the change set and check the output on AWS CloudFormation.
- Run
./bin/cfn/networking
to createCrdNet
stack. - Run
./bin/cfn/cluster
to createCrdCluster
stack. - Edit Route53 type A records for
api.beici-demo.xyz
to point to theCrdClusterALB
. - Export
DB_PASSWORD
and run./bin/cfn/db
to createCrdDb
stack. - It will take some time to create the RDS database
cruddur-instance
. When it's done, get its endpoint, and update theCONNECTION_URL
in AWS System Manager's Parameter Store. - Run
./bin/cfn/service
to createCrdSrvBackendFlask
stack. - Use SAM to run
./ddb/build
(to create.aws-sam
), then./ddb/package
, and finally./ddb/deploy
, in order to createCrdDdb
stack. - Use the created DDB table from above step as the value for
DDBMessageTable
to updateaws/cfn/service/template.yaml
andaws/cfn/service/config.toml
, then run again./bin/cfn/service
. - Run
./bin/cfn/frontend
to createCrdFrontend
stack. At this stage, no frontend code is deployed to it, so we need to setup static building and syncing in the following sections. - Edit Route53 type A records for
beici-demo.xyz
andwww.beici-demo.xyz
to point to the CloudFront created byCrdFrontend
. - Delete the old AWS codepipeline and codebuild and run
./bin/cfn/cicd
to createCrdCicd
stack and a nested one. - Run
./bin/cfn/machineuser
to createCrdMachineUser
stack. In IAM > Users > cruddur_machine_user > create access key, then update the generated key in Parameter Store.
To successfully pass the health check in the backend service, worth checking the following settings:
- Parameter Store set to correct
CONNECTION_URL
,AWD_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
. - RDS database created by
CrdDb
is running. - Security group
CrdDbRDSSG
has a inbound rule that sets to port 5432 and sourcesCrdClusterServSG
. - Security group
CrdClusterServSG
has a inbound rule that sets to port 4567 and sourceCrdClusterALBSG
. - Security group
CrdClusterALBSG
has inbound rules to allow all HTTP and HTTPS traffics. - Edit health check settings for the target group of
CrdClu-Backe-XXX
, in advanced settings, set the health check port to override port 4567. - Make sure Route53's type A records are using the correct routes.
Now if we merge this week-10 branch to the prod branch, it will trigger CICD. In AWS, Developer Tools > Connections > CrdCicd-connection, update pending connection. If successful, https://api.beici-demo.xyz/api/health-check
will return {"success":true,"ver":1}
. A screenshot of succeeded pipeline is attached below.
We use a Ruby-based tool to sync a folder from local development to S3 bucket, and then invalidate the CloudFront cache.
Create the following scripts:
./bin/frontend/static-build
and./bin/frontend/sync
./erb/sync.env.erb
(change to your ownSYNC_S3_BUCKET
andSYNC_CLOUDFRONT_DISTRIBUTION_ID
)./tmp/.keep
as a placeholderGemfile
Rakefile
./bin/cfn/sync
Also update ./bin/frontend/generate-env
and frontend components as mainly seen in this commit.
Now we initialize the static hosting by uploading the frontend to S3 bucket:
- run
./bin/frontend/static-build
cd frontend-react-js
thenzip -r build.zip build/
- download and decompress the zip, and upload everything inside the build folder to s3://beici-demo.xyz
For syncing:
- Install by
gem install aws_s3_website_sync dotenv
- Run
./bin/frontend/generate-env
to generatesync.env
- Run
./bin/frontend/sync
to sync - Run
./bin/cfn/sync
to create stackCrdSyncRole
, add the permissions by creating an inline policyS3AccessForSync
for the createdCrdSyncRole
with S3 service, actions of GetObject, PutObject, ListBucket and DeleteObject, resources specific to bucketbeici-demo.xyz
, and resource with the same bucket and any object.
Later if frontend is changed, we can sync by running ./bin/frontend/static-build
and then ./bin/frontend/sync
.
In order to do some DB migration from gitpod, we firstly need to edit inbound rules for CrdDbRDSSG
to allow gitpod IP. Then update the following env according to our CFN:
export GITPOD_IP=$(curl ifconfig.me)
export DB_SG_ID="your_security_group_id_of_CrdDbRDSSG"
gp env DB_SG_ID="your_security_group_id_of_CrdDbRDSSG"
export DB_SG_RULE_ID="corresponding_sgr_for_gitpod"
gp env DB_SG_RULE_ID="corresponding_sgr_for_gitpod"
export PROD_CONNECTION_URL='postgresql://cruddurroot:<your_password>@<endpoint_of_cruddur-instance>:5432/cruddur'
gp env PROD_CONNECTION_URL='postgresql://cruddurroot:<your_password>@<endpoint_of_cruddur-instance>:5432/cruddur'
./bin/rds/update-sg-rule
./bin/db/schema-load prod
Since we need to add other columns to the RDS DB, run ./bin/generate/migration reply_to_activity_uuid_to_string
to generate backend-flask/db/migrations/xxxxx_reply_to_activity_uuid_to_string.py
, edit this python file and then run CONNECTION_URL=$PROD_CONNECTION_URL ./bin/db/migrate
. Column bio
will be added to the users
table, and reply_to_activity_uuid
added to the activities
table.
Plus, in cruddur-post-confirmation
Lambda, change CONNECTION_URL
, VPC (change to the ones created by CFN, create a new CognitoLambdaSG
with the CrdNet
VPC), edit inbound rules of CrdDbRDSSG
to allow CognitoLambdaSG
.
Up to this point, we have created CloudFormation stacks as seen in the screenshot below.
As mainly seen in this commit, clean up backend and frontend to:
- refactor to use JWT Decorator, app.py, and routes
- implement replies for posts
- improve error handling
Since the backend is updated, we can trigger CICD by merging this branch to the prod branch. Since the frontend is also updated, we can sync by running ./bin/frontend/static-build
and then ./bin/frontend/sync
.
Following screenshots present https://beici-demo.xyz/ is working:
-
Existing user
@beiciliang
can do crudClean up!
in the homepage, and reply to this crud with messageTry a reply.
. -
# a new user
@altliang
who can also crudHi everybody, this is Alt Liang :)
, and reply to@beiciliang
's crud with messageYes we can reply :)
. -
User
@altliang
can send@beiciliang
a direct messageHey this is Alt Liang!
using urlhttps://beici-demo.xyz/messages/new/beiciliang
.
Now the homepage looks like follows:
Here are some other changes to make profile editing work in production:
- In
bin/frontend/static-build
, add env variableREACT_APP_API_GATEWAY_ENDPOINT_URL
in order to be stored in production. - In
backend-flask/routes/users.py
, route for/api/profile/update
include method ofPUT
. - In S3 bucket saving the uploaded avatars (in my case
beici-cruddur-uploaded-avatars
), edit the CORS configuration, including settingAllowedOrigins
as your cruddur domain andAllowedMethods
asPOST,PUT
. - In Lambda
CruddurAvatarUpload
, editfunction.rb
by settingAccess-Control-Allow-Origin
as your cruddur domain andAccess-Control-Allow-Methods
asOPTIONS,GET,POST,PUT
.
After editing the bio and uploading an avatar, my profile page looks like follows: