-
Notifications
You must be signed in to change notification settings - Fork 0
Docker Containerization
- Before running the development script, place a .env into each microservice folder with the information included in #resources in Discord.
npm run installsnpm run docker-up- Start respective servers you are working with
- Before running the production script, place a .env into the ROOT directory with the information included in #resources in Discord.
npm run installsnpm run containerized
PUBLIC
- 3000 - Shopper App
- 3001 - Admin App
- 3002 - Vendor API
- 3003 - Vendor App
- 3010 - Auth Service
- 3011 - Product Service
- 3012 - Orders Service
- 3013 - Key Service
- 3014 - Account Service
- 5432 - Auth Service Development postgres instance
- 5433 - Orders Service Development postgres instance
- 5434 - Product Service Development postgres instance
- 5435 - Key Service Development postgres instance
- 5436 - Account Service Development postgres instance
When running docker-up, the following commands are executed under package.json:
"docker-up": "npm run docker-auth-up && npm run docker-order-up && npm run docker-product-up",
"docker-auth-up": "cd AuthService && docker-compose up -d",
"docker-product-up": "cd ProductService && docker-compose up -d",
"docker-order-up": "cd OrderService && docker-compose up -d",
"docker-down": "npm run docker-auth-down && npm run docker-order-down && npm run docker-product-down",
"docker-auth-down": "cd AuthService && docker-compose down",
"docker-product-down": "cd ProductService && docker-compose down",
"docker-order-down": "cd OrderService && docker-compose down",
"installs": "npm install && npm run install-admin && npm run install-shopper && npm run install-vendor-app && npm run install-vendor-api && npm run install-auth && npm run install-order && npm run install-product",As you can see, running docker-up daisy chains into the commands directly underneath. To explain what it does in english, running this command will cd into every microservice directory and run docker-compose up -d. This command will trigger the docker-compose.yml file inside of each microservice
version: '3.7'
services:
postgres:
container_name: cse187-mockazon
image: postgres
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- ./sql/databases.sql:/docker-entrypoint-initdb.d/1.databases.sql
- ./sql/schema.sql:/docker-entrypoint-initdb.d/2.schema.sql
- ./sql/test.sql:/docker-entrypoint-initdb.d/3.test.sql
- ./sql/data.sql:/docker-entrypoint-initdb.d/4.data.sqlThis file tells docker to spin up a database at port 5432 and populates that database with the files inside of /sql
IMPORTANT
Every microservice has a unique port it needs to map for each of its databases. In this example, we are mapping 5432:5432. We can't however have two databases mapped to the same port, so in other microservices we do 5433:5432, 5434:5432, etc. To explain the porting, the first part of the port is the incoming port and the last part is the port within the container it maps to. You don't need to know the full details, as long as you have a unique incoming port number for every microservices development database. You can check the ports and their associated services below.
As you can see, each microservice now has its own database to work with, similar to how you are used to in previous assignments! From here you can just spin up the respective servers you are working with and go from there!
Before running the containerized command, make sure you run npm run installs
When running npm run containerized, the following things occur:
"containerized": "npm run build && docker-compose up --build",
"build": "npm run build-auth && npm run build-products && npm run build-orders && npm run build-admin && npm run build-vendorapp && npm run build-shopper && npm run build-vendorapi",
"build-auth": "cd AuthService && npm run build",
"build-products": "cd ProductService && npm run build",
"build-orders": "cd OrderService && npm run build",
"build-admin": "cd Admin && npm run build",
"build-vendorapp": "cd VendorApp && npm run build",
"build-vendorapi": "cd VendorAPI && npm run build",
"build-shopper": "cd Shopper && npm run build",This set of commands just cd's into every directory and runs npm run build on them to generate a build folder. This build folder is crucial for creating the production container. It then runs docker-compose up --build on the root directory docker-compose file
version: '3.7'
services:
shopper:
container_name: shopper
env_file: .env
build:
context: ./Shopper
dockerfile: Dockerfile
depends_on:
- postgres
ports:
- "3000:3000"
admin:
container_name: admin
env_file: .env
build:
context: ./Admin
dockerfile: Dockerfile
depends_on:
- postgres
ports:
- "3001:3001"
vendor_api:
container_name: vendor_api
env_file: .env
build:
context: ./VendorAPI
dockerfile: Dockerfile
depends_on:
- postgres
ports:
- "3002:3002"
vendor_app:
container_name: vendor_app
env_file: .env
build:
context: ./VendorApp
dockerfile: Dockerfile
depends_on:
- postgres
ports:
- "3003:3003"
microservice:
container_name: microservice
env_file: .env
build:
context: .
dockerfile: Microservice.Dockerfile
depends_on:
- postgres
postgres:
container_name: database
image: postgres:alpine
environment:
POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ./sql/databases.sql:/docker-entrypoint-initdb.d/1.databases.sql
- ./AuthService/sql/schema.sql:/docker-entrypoint-initdb.d/2.schema.sql
- ./AuthService/sql/data.sql:/docker-entrypoint-initdb.d/3.data.sql
- ./ProductService/sql/schema.sql:/docker-entrypoint-initdb.d/4.schema.sql
- ./ProductService/sql/data.sql:/docker-entrypoint-initdb.d/5.data.sql
- ./OrderService/sql/schema.sql:/docker-entrypoint-initdb.d/6.schema.sql
- ./OrderService/sql/data.sql:/docker-entrypoint-initdb.d/7.data.sqlThis might seem horrifying at first, but don't worry! Its actually quite easy to track and we will walk through it together. Each of these "services" are their own little containers that the compose file creates. These containers have these field:
- conatiner name
- name of the container
- env_file
- environment variables included (from the root)
- build
- Specifications for building the container
- search in the "context" directory for a dockerfile named Dockerfile
- depends on
- Before this container is built, build the postgres container
- ports:
- ports exposed to the public. Notice the ports that are exposed are ONLY for the public apps and not the microservices
Cool! Now lets take a look at one of the dockerfiles this yaml builds from
Here we will talk about the microservice dockerfile at the root level directory as it is the most complex and the other dockerfiles follow suit
FROM node:20-alpine
WORKDIR /home/app
COPY package.json /home/app/
COPY package-lock.json /home/app/
COPY .env /home/app/
COPY AuthService/build/ /home/app/AuthService/build/
COPY AuthService/package.json /home/app/AuthService/
COPY AuthService/package-lock.json /home/app/AuthService
COPY ProductService/build/ /home/app/ProductService/build/
COPY ProductService/package.json /home/app/ProductService/
COPY ProductService/package-lock.json /home/app/ProductService
COPY OrderService/build/ /home/app/OrderService/build/
COPY OrderService/package.json /home/app/OrderService/
COPY OrderService/package-lock.json /home/app/OrderService
RUN npm run cis
CMD npm run startYou can think of this dockerfile as a set of instruction to create the operating system the microservices will live in.
FROM node:20-alpineSpecifies to install node in this container (Also includes a lightweight version of Ubuntu ~5mb)
WORKDIR /home/appChange the working directory WITHIN THE CONTAINER
COPY package.json /home/app/
COPY package-lock.json /home/app/
COPY .env /home/app/Copy the package.json, package-lock.json, and .env from the repository to the container
COPY AuthService/build/ /home/app/AuthService/build/
COPY AuthService/package.json /home/app/AuthService/
COPY AuthService/package-lock.json /home/app/AuthServiceCopy the microservices build folder along with the package.json and package-lock.json into the container
RUN npm run cisThis runs npm run cis INSIDE of the docker container. Because we have just copied the package.json file into this container, this command will work. This command is basically a lighter weight version of npm install that uses the package-lock.json files.
CMD npm run startThis starts every microservice inside of the container. Below is the exact functionality of npm run cis AND npm run start
"cis": "npm ci && npm run ci-auth && npm run ci-products && npm run ci-orders",
"ci-auth": "cd AuthService && npm ci",
"ci-products": "cd ProductService && npm ci",
"ci-orders": "cd OrderService && npm ci",
"start": "concurrently --kill-others \"npm run start-auth\" \"npm run start-products\" \"npm run start-orders\"",
"start-auth": "cd AuthService && npm start",
"start-products": "cd ProductService && npm start",
"start-orders": "cd OrderService && npm start"Once you understand this dockerfile, the rest should be easy to follow. Notice some dockerfiles have
EXPOSE 3000This is just a simple way to tell the container that port 3000 will be exposed to the public.
In the production environment, instead of creating a new instance of postgres within each container we have ONE instance of postgres that spawns a database for every microservice. The compose file then runs the data and schema sql files inside of each microservice in the instance. This looks like the following:
postgres:
container_name: database
image: postgres:alpine
environment:
POSTGRES_PORT: ${POSTGRES_PORT}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- ./sql/databases.sql:/docker-entrypoint-initdb.d/1.databases.sql
- ./AuthService/sql/schema.sql:/docker-entrypoint-initdb.d/2.schema.sql
- ./AuthService/sql/data.sql:/docker-entrypoint-initdb.d/3.data.sql
- ./ProductService/sql/schema.sql:/docker-entrypoint-initdb.d/4.schema.sql
- ./ProductService/sql/data.sql:/docker-entrypoint-initdb.d/5.data.sql
- ./OrderService/sql/schema.sql:/docker-entrypoint-initdb.d/6.schema.sql
- ./OrderService/sql/data.sql:/docker-entrypoint-initdb.d/7.data.sqlI trust you to be able to follow this yourself.

Due to the differences between production and development environments, the URL's for calling a microservices will change very slightly. This is how the fetch url will be structured:
http://${process.env.MICROSERVICE_URL||'localhost'}:3010/api/v0/authenticateMICROSERVICE_URL=microserviceThis is our microservice url, the above url essentials equates to
http://localhost:3010/api/v0/authenticatein development and
http://microservice:3010/api/v0/authenticatein production. This is necessary because we cannot access the microservice via localhost in production because they are separate containers.
Along with fetch urls, database pools are set up as follows:
import { Pool } from 'pg';
const pool = new Pool({
host: (process.env.POSTGRES_HOST || 'localhost'),
port: + (process.env.POSTGRES_PORT || 5434),
database: process.env.POSTGRES_DB,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
});
export { pool };This is for the same reason as fetch URL's
Creating a new microservice can seem really daunting at first as there are a few steps involved but don't worry, its not quite as complicated as it sounds. These kind of things seem really scary but once you get the hang of it you will think "huh oh that wasn't so bad" and feel amazing about yourself!
To create a new microservice, first just create the directory and the structure of the service. The first thing you want to worry about is setting it up so it works in development, and that's incredibly easy!
- Create a docker-compose.yml file in the root of the microservice and copy+paste one from another microservice. Then pick a port from the first numbers in "5432:5432" to something that is not being used by another microservice.
Inside of the root package.json, add this to the set of commands in
"docker-up": "npm run docker-auth-up && npm run docker-order-up && npm run docker-product-up",
"docker-auth-up": "cd AuthService && docker-compose up -d"thats it for development!
For production, modify the existing Microservice.Dockerfile in the root directory and copy in the build folder, package.json, and package-lock.json like so
COPY AuthService/build/ /home/app/AuthService/build/
COPY AuthService/package.json /home/app/AuthService/
COPY AuthService/package-lock.json /home/app/AuthServiceOnce that is done, list the port of the microservice at the top of this wiki. Then add the microservice to the root package.json under the "cis" and "start" commands.