hatem ben tayeb
Posted on December 26, 2020
In this article we will discover the devops movement step by step, we will talk about the fundamental concepts then we will make a basic pipeline with github actions to deploy an angular 6 app, so let’s go.
What is devops ?
Devops is used to remove the conflict between the developers team and the operations team to work together. This conflict is removed by adding a set of best practices, rules and tools. The devops workflow is defined with a set of setps :
Plan
This is the first step, where the team defines the product goals and phases, also defining deadlines and assigning tasks to every team member, this step is the root of the hole workflow. the team uses many methodology like scrum and agile.
Code:
After planning, there is the code when the team converts the ideas to code. every task must be coded and merged to the main app, here we use an SCM to organize the collaboration to make a clean code and have a full code history to make a rollback in case of failure.
Build:
After coding we push the code to Github or Gitlab ( SCM ) and we make the build, usually we use docker images for packaging. also we can build the code to be a Linux package like deb , rpm … or even zip files , also there is a set of tests like unit tests and integration tests. this phase is critical !
Test:
The build was succeeded, no it’s time to deploy the build artifacts to the staging server when we apply a set of manual and automated tests ( UAT ).
Release:
it’s the final step for the code work, so we make a release and announce a stable version of our code that is fully functional ! also we can tag it with a version number .
Deploy:
A pre-prod or a production server is the target now, to make our app up and running
Operate:
It’s all about infrastructure preparation and environment setup with some tools like terraform for IaaC, ansible for configuration management and security stuff configurations …
Monitor:
The performance is very important, so we install and configure some monitoring tools like ELK, nagios and datadog to get all information about the applications like CPU and memory usage …
Deploying an angular app
In this example we will deploy a simple angular app on two environments.
- On VPS ( OVH provider) as a development server.
- on heroku as a staging server.
So you must have a VPS and a heroku account to continue with me.
The application repository is here : Github repo.
- Clone the project with git clone
https://github.com/hatembentayeb/angular-devops
- run npm install && ng serve to run the app locally
Preparing the deployment for heroku
Nginx is a popular and powerful web server can be used to serve a large variety of apps based on python, angular and react …
I will go through an optimization process to produce a clean and a lightweight docker container with the best practices as much as i can.
Writing the Dockerfile
First we will prepare the Dockerfile to be deployed to the heroku cloud,so there is some tricks to make it work smoothly, make sure that you have an account and simply click new to create an app :
Make sure to give a valid name for your app, then go to your accout settings and get your API_KEY that we will use it in the pipeline file:
let’s take a look at the dockerfile of the app:
FROM trion/ng-cli as builder
WORKDIR /app
COPY package.json package.json
COPY package-lock.json package-lock.json
RUN npm ci --debug
COPY . .
RUN ng build --prod
FROM nginx:1.17.5
COPY default.conf.template /etc/nginx/conf.d/default.conf.template
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/dist/my-first-app /usr/share/nginx/html
CMD /bin/bash -c "envsubst '\$PORT' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf" && nginx -g 'daemon off;'
This Dockerfile is splitted into two stages :
Builder stage : The name of the stage is builder, it is a temporary docker container that produces an artifact which is the
dist/
folder created byng build --prod
that compiles our project to produce a single html page and some *js & *.css . The base images that is used here istrion/ng-cli
that containes all requirements to run an angular up and it’s accessible for public use in the Docker-hub, the public docker registry.
Make sure to install all app requirement packages withnpm ci
, theci
command is used often in the continues integration environments because it is faster than npm install.Final stage: The base image for this stage is
nginx:1.17.5
and simply we copy thedist/
folder from the builder stage to the/var/share/nginx/html
folder in the nginx container with the commandCOPY --from=builder
...
There is additional configurations required to run the app, we need to configure nginx, there is a file nameddefault.conf.template
that contains a basic nginx configurations so we copy it to the container under/etc/nginx/conf.d/default.conf.template
, this file have the$PORT
variable that have to be changed when building the docker image in the heroku environment.
Thedefault.conf.template
:
server {
listen $PORT default_server;
location / {
include /etc/nginx/mime.types;
root /usr/share/nginx/html/;
index index.html index.htm;
}
}
Also make sure to copy the nginx.conf under the /etc/nginx/nginx.conf
, you are free to change and modify 😃, but for now i will use the default settings.
The last command is a little bit confusing so let’s break it down :
CMD /bin/bash -c “envsubst ‘\$PORT’ < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf” && nginx -g ‘daemon off;’
→ /bin/bash -c ‘ command’ : This command will run a linux command with the bash shell.
→ envsubst : It is a program substitutes the values of environment variables, so it will replace the $PORT
from the heroku environment and replace it in the default.conf.template
file with it’s value, this variable is given by heroku and attached to your app name, then we rename the template with default.conf which is recognized by nginx.
→ nginx -g ‘daemon off;’: The daemon off;
directive tells Nginx to stay in the foreground. For containers this is useful as best practice is for one container = one process. One server (container) has only one service.
Preparing the deployment for the VPS on OVH
We will use the VPS as a development server so no need for a docker now we will use ssh for this, after all make sure to have a VPS , ssh credentials and a public IP.
I assume you have nginx installed , if not try to do it, it is simple 😙
In this tutorial i will be using the sshpass
command, it is powerful and suitable for CI environments.
You can install it with : apt-get install sshpass -y
.
lets deploy the app to our server from the local machine, navigate to the repo and run ng build --prod
, then navigate to dist/my-first-app
folder and type this command :
sshpass scp -v -p <password> -o stricthostkeychecking=no -r *.* root@<vps-ip>:/usr/share/nginx/html
If you don’t want to hardcode the password in the command line try to set the SSHPASS
variable with your password like this export SSHPASS="password"
and replace -p
with -e
to use the environment variable.
Now all things almost done ! great 😃 ! let’s prepare the pipeline in the github actions which is a fast and powerful ci system provided by github inc.
Under the project root folder create the file main.yml in the github/wokflows folder, this directory is hidden so must start with a point like this : .github/workflows/main.yml
Preparing the pipeline
let’s take a look at the pipeline steps and configurations :
name: Build an angular project
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Cache node modules
uses: actions/cache@v1
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Node ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name : push to staging server with ssh
env :
SSHPASS : ${{ secrets.SSHPASS }}
SERVER : ${{ secrets.SERVER}}
run : |
sudo apt-get update
sudo apt-get install sshpass -y
npm install -g @angular/cli@6.2
npm ci --debug
ng build --prod
cd dist/my-first-app/
sudo sshpass -p ${SSHPASS} -v ssh -o StrictHostKeyChecking=no root@${SERVER} 'rm -rf /usr/share/nginx/html/*'
sudo sshpass -p ${SSHPASS} scp -v -o stricthostkeychecking=no -r *.* root@${SERVER}:/usr/share/nginx/html
- name: push to heroku
env :
HEROKU_REGISTRY_URL: registry.heroku.com
HEROKU_TOKEN : ${{ secrets.HEROKU_TOKEN }}
run : |
docker login --username=_ --password $HEROKU_TOKEN $HEROKU_REGISTRY_URL
export HEROKU_API_KEY=$HEROKU_TOKEN
heroku container:login
heroku container:push web --app angulardevops
heroku container:release web --app angulardevops
heroku ps:scale web=1 --app angulardevops
- Block 1: In this block we define the the workflow name and the actions that must be performed to start the build , test and the deployment. and of course you have to specify the branch of your repo (by default master ).
-
Block 2 : The
jobs
keyword has to sub keywordsbuild
andsteps
, the build define the base os for the continues integration environment, in this case we will useubuntu-latest
, also we define thenode-version
as a matrix that allow us to use multiple node versions in the list, in this case we need only12.x
. The steps allow us to define the wokflow steps and configurations ( build,test,deploy...). -
Block 3 :
actions/checkout@v1
is used to clone the app code in the ci env. this action is provided by github. Lets define a cache action with the namecache node modules
, the name is up to you 😃, then we use a predefined actioncalled actions/cache@v1
and specify the folders that we want to cache. -
Block 4 : Installing and configuring the node run-time with an action called
actions/node-setup@v1
and pass to it the desired node version that we already defined. -
Block 5 : The show will begin now ! let’s configure the build and the deployment to the VPS. Create two environment variables
SSHPASS
for the sshpass command and define theserver
address , make sure to define these values on the github secrets under setting on the top of your repo files. Underrun
keyword put your deployment logic. so we need the sshpass command and and the angular cli to be installed, then install all required packages and build the app with the production mode--prod
, next, navigate to thedist/my-first-app
folder and run the sshpass command with a set of arguments to remove older app in the server and deploy the new code. -
Block 6 : Now heroku is our target, so define also two env. variables, the heroku registry url and the API KEY to gain access to the registry using docker , next we need to define a special variable
HEROKU_API_KEY
that is used by heroku cli, next, we login to the heroku container and build the docker image then we pushed to the registry. we need to specify the target app in my case i named itangulardevops
. After deploying the docker image we need to release it and tell the heroku dynos to run our app on a heroku server, using 1 serverweb=1
, note thatweb
is the name of the docker image that we already pushed.
We are almost done! now try to make a change in the app code and push it to GitHub , the workflow will start automatically 🎉 🎉 😄 !
You can view the app here: https://angulardevops.herokuapp.com/
Finally, this tutorial is aimed to help developers and DevOps engineers to deploy an Angular app, I hope it is helpful 😍. for any feedback please contact me!
If this post was helpful click the clap button as much as possible 😃.
Thank you 😃
Posted on December 26, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.