Deploy an Angular4 App & Parse Server in the same Docker Container with Dokku
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
- Install Oracle Virtual Box. You can get it from here. We shall need a virtual environment to run dokku.
- Install Homebrew if you are on a mac, and you don’t have it installed yet.
- Install
git
if you don’t yet have it installed on your machine. You can follow instructions here. - Set up SSH. You’ll need it to deploy to dokku. You can follow the instructions here.
- Clone the Newsroom dashboard repo from here. It is our test project for this tutorial.
- 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
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
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
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:
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: