Continuous Deployment of Meteor to Amazon ECS using Docker and Codeship
In the previous article, we looked at what it takes to deploy a meteor app to Amazon EC2 Container Service (ECS). One issue with that deployment process is that the application source code is baked into the docker image. Changes to the application would require creating a new docker image, publishing that image and then stopping running containers and starting new containers pointing to the new image. We'll improve upon that and develop a continuous integration/deployment process using Codeship. Once everything is configured, you will simply commit to your master branch to update your app in production.
There are a lot of pieces involved. This article will not cover everything in detail so you should be already familiar with:
To get everything working you will need to:
curl -o meteor_install_script.sh https://install.meteor.com/
chmod +x meteor_install_script.sh
sed -i "s/type sudo >\/dev\/null 2>&1/\ false /g" meteor_install_script.sh
./meteor_install_script.sh
export PATH=$PATH:~/.meteor/
meteor --version
That script basically installs meteor (with a workaround since we're not running with root access on Codeship). Credit to @david_sykora for that script. In the Configure Test Pipelines enter:
meteor run --test
This is a good point to see if the test pipeline is working. Commit to your repo and Codeship will start running the test scripts. If the tests pass you are ready to move on. Note that things run much slower on cloud servers so if your test suite is passing all tests on your local system but not on Codeship that could be the issue. You may need to explicitly wait for DOM elements to appear at certain points in your test scripts.
On your local machine, create an app bundle by running
meteor build --architecture=os.linux.x86_64
Upload the tar file to the S3 folder. Refer to the previous article on how to set up Meteor/Docker on ECS. In the task definition, use the BUNDLE_URL variable like this:
Run the task to verify it is configured correctly. After you confirm the task will run, set up a service to run the task. With the ECS service set up, go back to Codeship and set up deployment.
AWS_DEFAULT_REGION
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Go to Deployment Settings, under "Add a deployment to your pipeline" there are several options; choose Custom Script. For the custom script enter:
mkdir ~/build
meteor build --architecture=os.linux.x86_64 ~/build/
aws s3 cp ~/build/your-app.tar.gz s3://your-bucket/meteor-bundles/your-app.tar.gz
aws ecs update-service --service web-service --task-definition your-app --desired-count 0
sleep 30
aws ecs update-service --service web-service --task-definition your-app --desired-count 1
The script uses the meteor build command to create a tar file of the application. Then it copies the tar file to S3. It stops the ECS web service by setting the desired-count to 0, waits a bit then starts the service (with a new container that pulls in the latest code).
Make a commit to your repo and you should see Codeship running through the test and deployment steps; open a browser and find the latest version of your app in production!
There are a lot of pieces involved. This article will not cover everything in detail so you should be already familiar with:
- using a test framework like Velocity for testing your app
- using Docker with Meteor using MeteorD
- deploying Meteor on Amazon ECS
To get everything working you will need to:
- configure Codeship to test your app
- configure ECS to use an app bundle with BUNDLE_URL
- configure Codeship to deploy your app
Configure Codeship to test our app
Sign into Codeship and create your project by pointing to your project git repository. Go to Project Settings, then Test Settings. Choose "I want to create my own custom commands". In the Setup Commands enter:curl -o meteor_install_script.sh https://install.meteor.com/
chmod +x meteor_install_script.sh
sed -i "s/type sudo >\/dev\/null 2>&1/\ false /g" meteor_install_script.sh
./meteor_install_script.sh
export PATH=$PATH:~/.meteor/
meteor --version
That script basically installs meteor (with a workaround since we're not running with root access on Codeship). Credit to @david_sykora for that script. In the Configure Test Pipelines enter:
meteor run --test
This is a good point to see if the test pipeline is working. Commit to your repo and Codeship will start running the test scripts. If the tests pass you are ready to move on. Note that things run much slower on cloud servers so if your test suite is passing all tests on your local system but not on Codeship that could be the issue. You may need to explicitly wait for DOM elements to appear at certain points in your test scripts.
Configure ECS to use an app bundle with BUNDLE_URL
As mentioned, we don't want to include our app code within the docker container. We'll use the BUNDLE_URL feature of the meteorhacks/meteord image. This allows the image to pull an app bundle from from a url. We'll use S3 to host the app bundle as discussed in this article. Create a bucket in S3 and create a folder for the app bundle. Add a bucket policy to S3 that grants read permissions to all for anything in that folder otherwise the container will fail to start because it can't download the app bundle. Let's get this working manually without Codeship.On your local machine, create an app bundle by running
meteor build --architecture=os.linux.x86_64
Upload the tar file to the S3 folder. Refer to the previous article on how to set up Meteor/Docker on ECS. In the task definition, use the BUNDLE_URL variable like this:
{
"family": "your-app",
"containerDefinitions": [
{
"name": "your-app-container",
"image": "meteorhacks/meteord:base",
"cpu": 300,
"memory": 300,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "ROOT_URL",
"value": "http://yourapp.com"
},
{
"name": "BUNDLE_URL",
"value": "http://yourbucket.s3.amazonaws.com/some-folder/your-app.tar.gz"
}
]
}
]
}
Run the task to verify it is configured correctly. After you confirm the task will run, set up a service to run the task. With the ECS service set up, go back to Codeship and set up deployment.
Configure Codeship to deploy our app
We need to configure Codeship with the AWS credentials that can access S3. Go to Project Settings, then Environment and enter variables for:AWS_DEFAULT_REGION
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Go to Deployment Settings, under "Add a deployment to your pipeline" there are several options; choose Custom Script. For the custom script enter:
mkdir ~/build
meteor build --architecture=os.linux.x86_64 ~/build/
aws s3 cp ~/build/your-app.tar.gz s3://your-bucket/meteor-bundles/your-app.tar.gz
aws ecs update-service --service web-service --task-definition your-app --desired-count 0
sleep 30
aws ecs update-service --service web-service --task-definition your-app --desired-count 1
The script uses the meteor build command to create a tar file of the application. Then it copies the tar file to S3. It stops the ECS web service by setting the desired-count to 0, waits a bit then starts the service (with a new container that pulls in the latest code).
Make a commit to your repo and you should see Codeship running through the test and deployment steps; open a browser and find the latest version of your app in production!
<< Home