Collection of Dockerfiles, docker-compose files and shell scripts for automating web app deployment on remote VPS hosts.
The main packages are:
- A local mongodb, mongo-express and node-js development stack
- A remote nexus repository hosted in a VPS running with java.
- A remote nexus repository hosted in a VPS running as a docker container.
- local docker and docker compose setup
- remote docker and docker compose setup
- collection of shell scripts to automatically setup and run docker containers on remote hosts.
-
Pull SCM
Pull the repository locally by running
git clone https://github.com/hangrybear666/07-devops-bootcamp__docker.git
-
Create Remote Linux VPS and configure
Generate local ssh key and add to remote VPS's
authorized_keys
file. -
Install additional dependencies on remote
Some Linux distros ship without the
netstat
command we use. In that case runapt install net-tools
ordnf install net-tools
on fedora et cetera. -
Create environment file in node-app/ folder and add secrets Add an
.env
file in your repository'snode-app/
directory and add the following key value-pairs:MONGO_DB_USERNAME=admin MONGO_DB_PWD=xxx MONGO_INITDB_ROOT_USERNAME=admin MONGO_INITDB_ROOT_PASSWORD=xxx ME_CONFIG_MONGODB_ADMINUSERNAME=admin ME_CONFIG_MONGODB_ADMINPASSWORD=xxx ME_CONFIG_MONGODB_SERVER=mongodb ME_CONFIG_MONGODB_URL=mongodb://mongodb:27017
Add an
.env
file in your repository's root directory and add:AWS_ECR_URL="010928217051.dkr.ecr.eu-north-1.amazonaws.com/node-app"
-
Add your remote VPS configuration parameters to
config/remote.properties
REMOTE_ADDRESS=167.99.128.206 ROOT_USER="root" SERVICE_USER="docker-runner" REMOTE_ADDRESS_2=104.248.37.28 SERVICE_USER_2="nexus-docker-runner"
-
Install docker locally.
Make sure to install docker and docker-compose (typically built-in) for local development. See https://docs.docker.com/engine/install/
-
Install docker on remote.
Ensure docker is installed on your remote VPS intended to run the node-app with mongo-db. See https://docs.docker.com/engine/install/
-
Dont forget to open ports in your remote firewall.
The port 3000 for express server, 8081 for mongo-express and 27017 for mongodb and 22 for ssh.
-
To run a node-js app, mongodb and mongo-express together in local development with manually configured docker containers
Execute the following commands in order within the
node-app/
folder.# create a bridge network docker network create node-mongo-bridge # pull and run mongo db docker run -d -p 27017:27017 --env-file app/.env --network node-mongo-bridge --name mongodb -v $(pwd)/seed-mongodb.js:/docker-entrypoint-initdb.d/seed-mongodb.js mongo:latest # pull and run mongo express docker run -d -p 8081:8081 --env-file app/.env --network node-mongo-bridge --name mongo-express mongo-express # build and run app from node-app folder docker build -f Dockerfile -t node-app:latest . docker run --rm -d --network node-mongo-bridge -p:3000:3000 --env-file app/.env --name node-server node-app
-
To run a node-js app, mongodb and mongo-express together in local development with a simple docker-compose script
To run these 3 images in the same network, with the desired node-app version simply run in the
node_app/
folder:export VERSION_TAG=1.0 docker compose -f docker-compose.yaml up
P.S.Mongodb is being initialized with a seed script to create a database and collection via
seed-mongodb.js
automatically, so interaction with mongo-express is not required. -
To push a docker image to a private AWS Elastic Container Registry, follow these steps
a. Make sure you create a user without root privileges in AWS IAM.
b. Then create an access key for this user and store the key value pair securely.
c. install aws cli on your local machine and run
aws configure
to setup your account. When prompted, provide the access key from step b, choose regioneu-central-1
andjson
as output format.d. Navigate to your AWS ECR Console and get the docker push commands from there.
In our case, the docker push commands for our private ECR instance are (change version for each image):
cd node-app aws ecr get-login-password --region eu-north-1 | docker login --username AWS --password-stdin 010928217051.dkr.ecr.eu-north-1.amazonaws.com # remember to change the version each time docker build -f Dockerfile -t node-app:1.0 . docker tag node-app:1.0 010928217051.dkr.ecr.eu-north-1.amazonaws.com/node-app:1.0 docker push 010928217051.dkr.ecr.eu-north-1.amazonaws.com/node-app:1.0
-
To pull docker image from AWS ECR and execute it with docker-compose on a remote VPS hosted in the cloud, follow these steps
a. First, you have to add the IP address of your remote machine and the root user to
config/remote.properties
file.b. Navigate to
scripts/
folder and install docker on your remote by executing./remote-install-docker.sh
(THIS SCRIPT IS FOR FEDORA 40 distribution using dnf package manager).c. Add the ECR repository url to your
.env
file in theAWS_ECR_URL
key.d. Then run
./remote-login-to-docker-registry.sh
. This will login to your docker ECR registry so subsequent docker compose and docker run/pull commands are setup correctly.e. you will be asked to provide the service user password defined in step b - you will also be queried for the node-app tag you want to use, as this is dynamically set as an ENV variable for docker-compose.
-
To run docker containers with volumes attached, specifically mongodb for persistence, we can use anonymous (named) volumes that are managed by docker, making it easier to deal with file permissions and such.
To attach a persistent volume on your local file system to a the docker container setup, navigate to
node-app/
directory and run:export VERSION_TAG=1.0 docker compose -f docker-compose-with-volumes.yaml up
Then: a. head to localhost:8081 with
admin
andpass
credentials for mongo-express and add the collection users in the database user-account.b. head to localhost:3000 and make updates to the user profile.
c. stop the docker containers with
docker compose -f docker-compose-with-volumes.yaml down
d. the containers were destroyed, now you can run
docker compose -f docker-compose-with-volumes.yaml up
once again and see that the updates from stepb. were persisted.
-
To use the existing nexus repository running on a remote VPS server from demo project 6, adding a docker-registry to it and pushing images to that registry from localhost, follow these steps
Get the remote url from demo project 6, in my case https://github.com/hangrybear666/06-devops-bootcamp__nexus_artifact_repo/blob/main/config/remote.properties Nexus repository is accessible at
REMOTE_ADDRESS:8081
and the credentials are stored in the.env
file of your project 6 repo.a. Login to the existing nexus repository as an admin user.
b. Create a new role named
nx-docker
and apply the privilegenx-repository-view-docker-docker-hosted-*
to it. (NOTE: you might have to create a docker-hosted repo first)c. Create a new local user named
docker-creds
d. Add
Docker Bearer Token Realm
under Realms.e. Create a blob store of type File named
docker-hosted-blob
f. Store the relevant credential information in this repository's
.env
file.NEXUS_ADMIN_PASSWORD=xxx NEXUS_USER_1_ID=docker-creds NEXUS_USER_1_PWD=xxx
g. Create a new Repository of type
docker-hosted
, assign the blob store from step e. and enable the HTTP flag with port 8082 to allow insecure connections without having to configure HTTPS in nexus.h. In your local linux distro with docker installed, edit the
/etc/docker/daemon.json
file and add:{ "insecure-registries" : [ "REMOTE_ADDRESS:8082" ] }
If the file doesn't exist, create it
sudo vim /etc/docker/daemon.json
sudo systemctl daemon-reload sudo systemctl restart docker docker info
Now docker info should print your nexus repository under insecure registries.
i. Now login to the nexus docker-hosted repository via: AND DON'T FORGET TO ALLOW PORT 8082 IN YOUR REMOTE VPS FIREWALL
docker login REMOTE_ADDRESS:8082
When prompted, provide the credentials defined in your
env
file in step f. namelyNEXUS_USER_1_ID
andNEXUS_USER_1_PWD
j. Now simply build your desired image, tag it and push it to the repository url you logged in to.
cd node-app docker build -f Dockerfile -t node-app:0.1 . docker tag node-app:0.1 104.248.37.28:8082/node-app:0.1 docker push 104.248.37.28:8082/node-app:0.1
k. Now you can pull the image via a simple docker pull command, or use the nexus API to fetch the hosted versions and fetch the newest via extraction of the downloadUrl via the jq tool, as demonstrated in https://github.com/hangrybear666/06-devops-bootcamp__nexus_artifact_repo
-
To setup nexus repository within a docker container deployed on a remote host, follow these steps:
Change directory to the
scripts/
folder and:a. First, install docker on your remote VPS, by running
./remote-install-docker-for-nexus.sh
(This is aimed at Debian like distros with the apt-get package manager)b. Then run
./remote-run-nexus-docker-img.sh
c. Make sure to allow port 8081 forwarding in your VPS firewall settings.
d. ssh into your remote vps and run the following code to retrieve the default admin password.
docker ps # with the resulting hash run docker exec -it HASH_VALUE sh ~sh: cat /nexus-data/admin.password
e. With the retrieved password from step d, navigate to REMOTE_ADDRESS:8081, login to nexus and start using the repository.
f. Make sure to change the password to the one in our .env file from step 6
NEXUS_ADMIN_PASSWORD=xxx
-
Setup Environment secrets and configuration
a. Be sure to have gradle 8 and java 17 installed, I can recommend using sdkman for this https://sdkman.io/install
b. Create an
.env
file inexercises/
folder with the following content:MYSQL_ROOT_PASSWORD=xxx MYSQL_DATABASE=team-member-projects MYSQL_USER=mysql-user MYSQL_PASSWORD=xxx
c. If you are executing the local steps on a remote host instead, be sure to open ports 3306 and 8080 and 8085
-
To run a local mysql docker container, mysqlp phpadmin container and a native java spring application locally
NOTE: If you are running this on a remote host from the get go, you first have to create
target_dir/exercises/
on your remote host via ssh, then recursively copy theexercises/
folder to your remote viascp -r exercises root@REMOTE_ADDRESS:~/target_dir/exercises
and you also have to change const HOST = "xxx" to your remote ip address inexercises/src/main/resources/static/index.html
!a. If you want to run the java app on localhost, set const HOST = "localhost" in
exercises/src/main/resources/static/index.html
cd exercises docker network create mysql-db-gui docker run --name mysqldb --env-file .env --network mysql-db-gui -p 3306:3306 -d mysql:9.0.1 # to connect as a mysql client to execute queries from another docker container run docker run -it --network mysql-db-gui --rm mysql:9.0.1 mysql -hmysqldb -umysql-user -p # to start phpmyadmin on port 8085 linked to the docker container db docker run --name phpmyadmin --network mysql-db-gui -d --link mysqldb:db -p 8085:80 phpmyadmin:5.2.1-apache # build and run .jar file running tomcat on port 8080 running as a service in the background with nohup & gradle clean build cd build/libs export DB_USER=mysql-user DB_PWD=sdfpokfepok2012d DB_SERVER=localhost DB_NAME=team-member-projects nohup java -jar docker-exercises-project-1.0-SNAPSHOT.jar &
b. Then you can connect to your phpmyadmin instance by accessing
localhost:8085
and logging in viaMYSQL_USER
andMYSQL_PASSWORD
c. You can connect to your java application by accessinglocalhost:8080
-
To run a mysql db and phpmyadmin with docker compose
cd exercises docker compose -f docker-compose-mysql.yaml up
-
To build and push the Java application as a docker image to nexus repository hosted in a remote VPS
cd exercises docker build -f Dockerfile -t java-app:1.0 . # docker run --name java-app -e DB_PWD=sdfpokfepok2012d --network mysql-db-gui -p 8080:8080 java-app:1.4 docker login REMOTE_ADDRESS_2:8082 Username: NEXUS_USER_1_ID Password: NEXUS_USER_1_PWD docker tag java-app:1.0 104.248.37.28:8082/java-app:1.0 docker push 104.248.37.28:8082/java-app:1.0
NOTE: Check in Demo Projects step 6 how to setup the new nexus docker container properly.
-
To run the entire stack with java-app image hosted and pulled from nexus on a remote server with one docker-compose command
First, if you haven't setup the remote hose with docker prior, you have to follow steps 4a) and 4b) from Demo Projects, so docker compose can be run by a service-user. Please remember the service-user password set during this setup as it will be queried when executing the following script.
Execute the deployment script supplying the service-user password and the desired java-app image version tag
cd scripts ./remote-compose-java-mysql-app.sh
NOTE: To configure environment variables, simply edit the
.env
file inexercises/
directory, where theDB_PWD
needed by your java application is stored asMYSQL_PASSWORD
or edit theexercises/Dockerfile
for additional environment vars that aren't supposed to be a secret.