Deploy an Angular4 App & Parse Server in the same Docker Container with Dokku

Seremba John Paul
The Andela Way
Published in
10 min readNov 14, 2017

From the dokku website, dokku is introduced as an extensible, open source Platform as a Service that runs on a single server of your choice. Dokku, therefore provides us with a flexible deployment process, and it is quite simple to use. Dokku abstracts most of the deployment configurations for you, as you sit back, relax and push your code.

Dokku provides a number of deployment options for you. For this tutorial, we have embarked on the Dockerfile deployment option. This is a transparent process that lets you control how your app is built and deployed in production from a high level point of view.

Introduction

As a case study, we are going to use an open source Citizen Reporter Newsroom Dashboard application built on top of Angular4 and Parse Server. The problem we are going to solve in the tutorial below is deploying the two applications; i.e. Angular4 newsroom dashboard and the Parse Server in the same docker container, but different urls, running on a single dokku instance.

Pre-requisites

  1. Install Oracle Virtual Box. You can get it from here. We shall need a virtual environment to run dokku.
  2. Install Homebrew if you are on a mac, and you don’t have it installed yet.
  3. Install git if you don’t yet have it installed on your machine. You can follow instructions here.
  4. Set up SSH. You’ll need it to deploy to dokku. You can follow the instructions here.
  5. Clone the Newsroom dashboard repo from here. It is our test project for this tutorial.
  6. Clone the Parse Server from here. The App is dependent on it.

Setup Dokku with Vagrant

Since I’m running a mac, and dokku doesn’t explicitly run on a mac, I have to install vagrant to manage virtual machines for me. However, you may not need to set this up if you are running a fresh installation of Ubuntu, on a machine dedicated as a server.

Vagrant is a command line utility for managing the lifecycle of virtual machines.

Step 1:
Open a fresh terminal window and run the command below.

$ brew cask install vagrant

installing vagrant dependencies

Step 2:
You also need to install the vagrant manger. This comes in handy when you want to perform some sophisticated tasks in future. Run the command below in your terminal.
$ brew cask install vagrant-manager

installing vagrant manager

Step 3:
Clone the dokku repo from the official dokku repository.
$ git clone git@github.com:dokku/dokku.git

When the cloning is done, switch to the cloned dokku repo as the new working directory. Run the command below in your terminal.
$ cd dokku
When you run ls you’ll be able to view the current directory contents.

Step 4:
This dokku repo has a Vagrantfile which provides us with an option of starting dokku with vagrant. Therefore, run $ vagrant up to start the dokku in a virtual machine. This process takes about 10 minutes, basing on the speed of your internet connection.

Step 5:
Set up virtual hosts: This shall enable us to point a domain name to the dokku instance. On a Mac the virtual hosts file is found in /private/etc/hosts

Edit the hosts file with this command;
$ sudo nano /private/etc/hosts
Nano is one of the text editors on a mac. But you can still edit the file with your favorite text editor such as vim.

You’ll be prompted for your System password, enter it and edit the file as follows;
Add a host: 10.0.0.2 dokku.me to the hosts in the above file. Press Ctrl + X to save your changes and close the file.

Step 6:
Go to a browser of your choice and enter the address dokku.me
Set the public key (a copy of the SSH key that you created previously. Sometimes, this is automatically loaded). If the public key is not automatically loaded, you may need to copy it from ~/.ssh/id_rsa.pub

Set the hostname as dokku.me, as shown in the picture below. Check the option Use virtualhost naming for apps, and afterwards click Finsh Setup. This ensures that the app runs from the host name that we specified.

Step 7:
SSH into the dokku instance. You’ll be prompted for the passphrase for your public key.
$ ssh root@dokku.me

creating the dokku host

We shall refer that new terminal that prefixes root@dokku: as the dokku host.

Step 8:
From the dokku host to above, create an app that is going to be hosted. Lets name it creporter-dashboard.
$ dokku apps:create creporter-dashboard

Run the command $ dokku apps:list You should be able to view your newly created app.

Step 9: Our app shall be using Parse Server, which depends on MongoDB, so we need to install the mongo image.

From the dokku host, run the command
$ dokku plugin:install https://github.com/dokku/dokku-mongo.git

The process may take about 2 mins, depending on your internet connection.

Create a database for the app.
The sytanx is $ dokku mongo:create <database_name>
Create the database with: $ dokku mongo:create parsedb

Step 10:
Link the database to the app we created:
The sytnax is $dokku mongo: link <database_name> <app_name>
Run$ dokku mongo:link parsedb creporter-dashboard
The above command creates a MONGO_URL variable by default. Copy the value of MONGO_URL for we shall need it in the next steps.

Step 11:
Set the Environment variables.
The syntax for setting environment variables is
$ dokku config:set <app_name> <VARIABLE_NAME>=<VALUE>

Use the MONGO_URL value that you copied in the previous step to set the DATABASE_URI. It is in the format mongodb://parsedb: ... /parsedb
$ dokku config:set creporter-dashboard DATABASE_URI=<MONGO_URL>
$ dokku config:set creporter-dashboard APP_ID=<YOUR_APP_ID>
$ dokku config:set creporter-dashboard APP_SECRET=<YOUR_APP_SECRET>
$ dokku config:set creporter-dashboard MASTER_KEY=<YOUR_MASTER_KEY>
$ dokku config:set creporter-dashboard PASSWORD=<YOUR_PASSWORD>
$ dokku config:set creporter-dashboard APP_NAME=<APP_NAME>

Remember to replace the values in < > with your custom values.
That’s all we need to do from the docker host. How its time to configure our 2 apps for deployment.
Create a second terminal window for the next steps. You may leave the dokku host terminal open.

Prepare the applications

We have two applications that we cloned at the start of this tutorial, i.e; Our Angular4 application (Citizen Reporter Newsroom Dashboard) and the Parse Server.

Step 1:
Create an app directory $ mkdir creporter; Then $ cd creporter. Ensure that from this step onwards you are in the creporter directory.

Step 2:
Move the Parse Server directory into the creporter directory.

If you haven’t yet cloned the repo you can run this command
$git clone git@github.com:parse-community/parse-server-example.git

Rename the parse-server-example directory to parseServer

Step 3:
Move your Angular4 (Newsroom dashboard) project into a folder called dashboard You can however name it anything you want. But to follow along closely you can go ahead and name it dashboard.
Your directory structure now looks like so:

+-creporter
| +-dashboard
| +-parseServer

Move the following files from the Angular app (dashboard) into the root folder (creporter)

> .angular-cli.json
> .gitignore
> tsconfig.json
> package.json
> package-lock.json
> tsconfig.json
> tslint.json
> README.md

Move your node_modules folder to the root too. But, you may choose to delete this folder for it shall be re-created when we run npm install in the future.

Move the following files from the parseServer directory;

> app.json
> jsconfig.json

Delete the node_modules from the parseServer directory. We plan to have a single node_modules folder. You can also delete the package.json and package-lock.json files. Their contents are going to be merged into a single package.json file in the root.

The package.json file in the parseServer directory looks similar to this:

The package.json file in the parseServer directory

Copy the repository and the dependencies objects from the parseServer package.json file and merge them into the root package.json file.

Your directory structure should now be similar to this;

+-creporter
|+-dashboard
| +-e2e
| +-src
| +-karma.conf.js
| +-protractor.conf.js
|+-parseServer
| +-cloud
| +-public
| +-README.md
|-.angular-cli.json
|-.gitignore
|-app.json
|-jsconfig.json
|-package-lock.json
|-package.json
|-README.md
|-tsconfig.json
|-tslint.json

Step 4.
Update the package.json file
Inside the package.json file, update the scripts object’s start attribute to "start": "node server.js" We shall create the server.js file in future.
So, your scripts section should look like this:

Move the following angular-cli dependencies from devDependencies to dependencies. We need them to be installed in our production environment, so that our app can be built and deployed at the same time.

"@angular/cli": "1.3.0",
"@angular/compiler": "^4.2.4",
"@angular/compiler-cli": "^4.2.4",

The above versions may defer basing on the version of the cli that you are running.

Add an engines section at the bottom of the file, which shall define the node and npm versions that we are using. You can update the node and npm versions according to what you feel comfortable with.

The package.json file should look similar to this:

With that done, we need to update our .angular-cli file to inform it about the location of the Angular Project, and where to serve it.

Update the following in the app section of the .angular-cli file.

"root": "dashboard/src",
"outDir": "dashboard/dist",

Update the styles object to point to the correct bootstrap css file in the node modules folder as so;

"styles": [
"./../../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
]

Update the location of the protractor.config.js file and karma.conf.js file.

"e2e": {
"protractor": {
"config": "dashboard/protractor.conf.js"
}
},
.
.
.
"test": {
"karma": {
"config": "dashboard/karma.conf.js"
}
},

Your .angular-cli should now look similar to this

Step 5:
Create a server.js file. This is an express script that defines the way our app is run. It shall also help us define the urls from which to run the dashboard and the parseServer

First, you’ll need to install express, if you haven’t already done so.
$ npm install --save express

The comments in the file below are sufficient and self explanatory. There are two main sections, Serving the parse server and serving the newsroom dashboard.
Your server.js file should look like this;

Step 5:
Create a DockerFile. A docker file tells docker how to build the docker image. Dokku has a provision that supports docker container deployment.

What that file does is; First (on line 1)we need to define the image we want to build from. We therefore use the latest long term support version boron of node. Its well tested, stable and available from the Docker Hub.

On line 3, we create a directory /opt/app where our project files shall be stored for smooth running in the container. We set our working directory to /opt/app on line 4. This gives our app a place to call home.

On lines 7, 8, and 10 we copy the package.json and package-lock.json files to the container, and then install the dependencies into our container. We explicitly state that we only want to install production dependencies.

On lines 12 and 13 we copy the .angular-cli.json together with the rest of the files that are not in the .dockerignore into the container.

Line 15 builds our app in production mode.
Lines 17, 18, and 19 enable you to set your environment variables if you need to do so.

Line 21 specifies the port from which the app shall run in the container.

Finally on line 23 we define a script that shall start the application. Here we specify npm start which looks for the start script in the package.json file which in turn executes our server.js script that tells our application how to run and serve the different assets.

Step 6: Add another file .dockerignore to prevent addition of certain folders in the docker container. We ignore node_modules and the npm-debug.log file.

Step 7:
In this step, we update the environment variables that define the parse server URL and other app dependencies.

For our case project, the parse config file is found in dashboard/src/environments/. There are two files in the environments directory, i.e; environment.prod.ts and environment.ts which we update with the relevant values.

Update the ServerURL to point to
http://creporter-dashboard.dokku.me:1337/parse or what you set as the server URL.

Update the APP_ID and MASTER_KEY values with the master key values you created earlier.

Step 8:
That is all we need to do to configure both projects. Its now time to deploy to dokku.

You need to initialize git if you haven’t yet initialized it on the repo creporter.

Run $ git init in the root folder creporter

You may add the remote origin to your github repository if you created one.

Then, you’ll need to add the dokku remote to your repository. The syntax is git remote add dokku dokku@dokku.me:<app_name>

We therefore run;
git remote add dokku dokku@dokku.me:creporter-dashboard

After adding the remotes, push to dokku. Dokku deploys from the master branch. However this configuration can be changed if you read up from the docker documentation.

We hence run;
$ git push dokku master

If you want to deploy a different branch from master, you can run
$ git push dokku <branch_bame>:master

The push command triggers the build process, and the docker container is created.

The build process takes some time to complete. As you see from the above picture, there is a message “Application deployed” that has the application urls. Navigate to http://creporter-dashboard.dokku.me:1337 and view your freshly deployed app.

Test the Parse Server to see whether it was successfully deployed by navigating to http://creporter-dashboard.dokku.me:1337/parse

Test the Parse Dashboard also by navigating to http://creporter-dashboard.dokku.me:1337/dashboard

Bravo. You are now good to go. You have successfully deployed two apps in a single container, but different urls, on dokku.

You can also go a head and deploy the Docker image with Docker.

References:

  1. https://nodejs.org/en/docs/guides/nodejs-docker-webapp/
  2. https://docs.docker.com/get-started/
  3. http://dokku.viewdocs.io/dokku/getting-started/installation/

--

--