1546053032
Install MEAN Stack Using CloudFormation
AWS CloudFormation is a service that helps you model, setup and replicate your AWS resources. It uses a template file to bring up a collection of resources together as single stack.
To create templates we use a JSON file or AWS CloudFormation Designer. For this tutorial I opted the first solution.
Note: The template is available on my Github 😎.
We start with a basic template that defines a single EC2 instance with a security group that allows SSH traffic on port 22, MongoDB traffic on port 27017, and the NodeJS app on port 3000 from anywhere, as shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | { "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "Create an EC2 instance with MEAN stack installed", "Parameters" : { "InstanceType" : { "Description" : "EC2 Instance type", "Type" : "String", "Default" : "t2.micro", "AllowedValues" : ["t1.micro",< span class="crayon-h"> "t2.micro", "t2.small", "t2.medium", "m1.small", "m1.medium", "m1.large"], "ConstraintDescription" : "Must be a valid EC2 instance type" }, "KeyName" : { "Description" : "Key pair to allow SSH access to the instance", "Type" : "AWS::EC2::KeyPair::KeyName" } }, "Resources": { "MEANInstance" : { "Type" : "AWS::EC2::Instance", "Properties" : { "ImageId" : "ami-4fffc834", "InstanceType" : { "Ref" : "InstanceType" }, "KeyName" : { "Ref" : "KeyName" }, "SecurityGroups" : { "Ref" : "MEANInstanceSecurityGroup" } ], "UserData" : { "Fn::Base64": { "Fn::Join" : [ "", [ "#!/bin/bash\n", "yum update -y\n", "rm /etc/yum.repos.d/mongodb.repo\n", "mk dir -p /data/db\n", "echo '[mongodb]' >> /etc/yum.repos.d/mongodb.repo\n", "echo 'name=MongoDB Repository' >> /etc/yum.repos.d/mongodb.repo\n", "echo 'baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/' >> /etc/yum.repos.d/mongodb.repo\n", "echo 'gpgcheck=0' >> /etc/yum.repos.d/mongodb.repo\n", "echo 'enabled=1' >> /etc/yum.repos.d/mongodb.repo\n", "echo \"/etc/yum.repos.d/mondgob.repo created\"\n", "yum inst all -y mongo-10gen mongo-10gen-server\n", "sed -i 's/bind_ip=127.0.0.1/bind_ip=0.0.0.0/' /etc/mongod.conf\n", "service mongod start\n", "echo 'Mongodb Installed'\n", "curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -\n", "yum install -y nodejs\n", "echo 'Node.JS Installed'\n", "mkdir -p /home/ec2-user/public\n", � � "cat > /home/ec2-user/public/index.html <<END\n", "<!DOCTYPE html>\n", "<html ng-app='app'>\n", " <head>\n", " <title>MEAN Stack app</title>\n", " </head>\n", " <body ng-controller='MainCtrl'>\n", � � " {{message}}\n", " </body>\n", " <script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js' charset='utf-8'></script>\n", " <script type='text/javascript'>\n", " angular.module('app',[]) \n", " .controller('MainCtrl', function(\\$scope){\n", " \\$scope.message = 'Hello from mlabouardy ^^'\n", " })\n", " </script>\n", "</html>\n", "END\n", "cat > /home/ec2-user/package.json <<END\n", "{\n 4;, " \"name\": \"simple-app\",\n", " \"authors\": \"Mohamed Labouardy\",\n", " \"dependencies\": {\n", " \ 34;express\": \"^4.15.4\",\n", " \"mongodb\": \"^2.2.31\"\n", " }\n", "}\n", "END\n", "npm install --prefix /home/ec2-user/\n", "cat > /home/ec2-user/server.js <<END\n", "var express = require('express'),\n", " app = express(),\n", " MongoClient = require(\"mongodb\").MongoClient,\n", " database = null,\n", " port = process.env.PORT || 3000;\n", "var movies = [\n", " {\n", " name: \"Spider-Man: Homecoming\"\n", " },\n", " {\n", " name: \"Dunkirk\"\n", " },\n", " {\n", " name: \"Despicable Me 3\"\n", " }\n", "]\n", "MongoClient.connect(\"mongodb://localhost/mydb\", function(error, db) {\n", " db.collection('movies').insert(movies, function(err, res) {\n", " database = db\n", " console.log('saved to database')\n", " })\n", "})\n", "app.use(express.static(__dirname + '/public'));\n", "app.use('/api', function(req, res){\n", " database.collection('movies').find().toArray(function(err, data){\n", " res.json(data)\n", " })\n", "})\n", "app.listen(port, function(){\n", " console.log('Server listening on port ', port)\n", "})\n", "END\n", "nohup node /home/ec2-user/server.js > app.out 2> app.err < /dev/null &\n" ] ] } } } }, "MEANInstanceSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable MongoDB & NodeJS server ports", "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "ToPort" : "27017", "CidrIp" : "0.0.0.0/0" }, { "IpProtocol" : "tcp", "FromPort" : "3000", "ToPort" : "3000", "CidrIp" : "0.0.0.0/0" }, { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0" } ] } } "Outputs" : { "ApplicationURL" : { "Description" : "URL for MEAN Stack application", "Value" : { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt":[ "MEANInstance", 4;PublicDnsName" ] }, ":3000" ] ] } } } } |
In addition to that, we create two input parameters that specify the instance type and a Key Pair for SSH access. Then, we use UserData property to provide a set of shell commands to install MongoDB, NodeJS and bootstrap a simple MEAN application. Finally the output section print the public URL of the MEAN application.
Now we defined our template. Go to AWS Management Console then navigate to CloudFormation Dashboard and click on "Create Stack":
Upload the JSON file and click on "Next":
Assign a name to the stack, and choose your instance type and key pair you will use to ssh to the instance. Then, click on "Next":
Left all fields unchanged and click on "Next", then "Create"
Once launched, you will get the following screen with launching process events:
After a while, you will get the CREATE_COMPLETE message in the status tab.
If you point your browser to the URL shown in the Outputs tab, you should see: a simple HTML message:
If we change the endpoint we should see a JSON response:
Congratulation ! ✨🎉 you have deployed your MEAN Stack application.
Go to EC2 Dashboard, you should see your instance there:
Verify the security group is setup as configured in the template:
To verify all packages and dependencies has been installed correctly, we can connect to the server via SSH:
To terminate the instance we can delete the stack from the CloudFormation Wizard, Deleting the stack will terminate all the instances launched by the stack:
Comments
Post a Comment