ECE366 - Lesson 9
Hosting on the Cloud, Testing
Instructor: Professor Hong
## Adding React to Docker Compose
Dockerfile
```
# pull official base image
FROM node:18
# set working directory
WORKDIR /app
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install app dependencies
COPY package.json ./
COPY package-lock.json ./
RUN npm install --silent
RUN npm install react-scripts@3.4.1 -g --silent
# add app
COPY . ./
# start app
CMD npm start
```
## Docker-Compose
docker-compose.yaml
```
services:
ui:
build: .
ports:
- 3000:3000
```
## Putting it all together
## DB SQL Files - Initializing db
```
CREATE DATABASE rps;
GRANT ALL PRIVILEGES ON DATABASE rps TO postgres;
```
## DB SQL Files - Player table
```
\c rps
CREATE TABLE player (
player_name varchar(50) NOT NULL,
password varchar(50) NOT NULL,
win int DEFAULT 0,
loss int DEFAULT 0,
draw int DEFAULT 0,
PRIMARY KEY (player_name)
);
```
## DB SQL Files - Move table
```
\c rps
CREATE TABLE move (
move varchar(50) NOT NULL,
PRIMARY KEY (move)
);
```
## DB SQL Files - Game table
```
\c rps
CREATE SEQUENCE game_id_seq start with 1;
CREATE TABLE game (
game_id int NOT NULL DEFAULT nextval('game_id_seq'),
p1 varchar(50) NOT NULL,
p2 varchar(50) NOT NULL,
current_turn int NOT NULL DEFAULT 1,
num_turn int NOT NULL DEFAULT 5,
p1_points int NOT NULL DEFAULT 0,
p2_points int NOT NULL DEFAULT 0,
winner varchar(50) NULL,
PRIMARY KEY (game_id),
FOREIGN KEY (p1) REFERENCES player(player_name),
FOREIGN KEY (p2) REFERENCES player(player_name),
FOREIGN KEY (winner) REFERENCES player(player_name)
);
```
## DB SQL Files - Game History table
```
\c rps
CREATE TABLE game_history (
game_id int NOT NULL,
turn int NOT NULL,
p1_move varchar(50) NOT NULL,
p2_move varchar(50) NOT NULL,
winner varchar(50) NOT NULL,
PRIMARY KEY (game_id, turn),
FOREIGN KEY (game_id) REFERENCES game(game_id),
FOREIGN KEY (p1_move) REFERENCES move(move),
FOREIGN KEY (p2_move) REFERENCES move(move),
FOREIGN KEY (winner) REFERENCES player(player_name)
);
```
## DB SQL Files - Sample Data
```
\c rps
ALTER SEQUENCE game_id_seq RESTART;
DELETE from move WHERE 1=1;
DELETE from game_history WHERE 1=1;
DELETE from game WHERE 1=1;
DELETE from player WHERE 1=1;
INSERT INTO move (move) VALUES ('rock');
INSERT INTO move (move) VALUES ('paper');
INSERT INTO move (move) VALUES ('scissors');
INSERT INTO player (player_name, password) VALUES ('isaiah', 'password');
INSERT INTO player (player_name, password) VALUES ('malek', 'password');
INSERT INTO player (player_name, password) VALUES ('irene', 'password');
INSERT INTO game (p1, p2, current_turn) VALUES ('isaiah', 'malek', 1);
INSERT INTO game (p1, p2, current_turn) VALUES ('isaiah', 'irene', 1);
INSERT INTO game_history (game_id, turn, p1_move, p2_move, winner) VALUES (2, 1, 'rock', 'scissors', 'isaiah');
UPDATE game SET current_turn = 2 WHERE game_id = 2;
INSERT INTO game_history (game_id, turn, p1_move, p2_move, winner) VALUES (2, 2, 'rock', 'scissors', 'isaiah');
UPDATE game SET current_turn = 3 WHERE game_id = 2;
INSERT INTO game_history (game_id, turn, p1_move, p2_move, winner) VALUES (2, 3, 'scissors', 'paper', 'isaiah');
UPDATE game SET current_turn=4, winner='isaiah' WHERE game_id = 2;
```
## Initializing database
Dockerfile
```
FROM postgres
# Copy the SQL files to the container
COPY init.sql /docker-entrypoint-initdb.d/0_init.sql
COPY users.sql /docker-entrypoint-initdb.d/1_users.sql
COPY game.sql /docker-entrypoint-initdb.d/2_game.sql
```
## Spring Boot Service
```
FROM maven:3.9.6-eclipse-temurin-21 AS build
ADD . /project
WORKDIR /project
RUN mvn -e -Dmaven.test.skip package
FROM eclipse-temurin:latest
COPY --from=build /project/target/rpsjpa-0.0.1-SNAPSHOT.jar /app/rps.jar
ENTRYPOINT java -jar /app/rps.jar
```
## Update Proxy
package.json, main part of json
```
"proxy": "http://app:8080/",
```
## React UI
Dockerfile
```
# pull official base image
FROM node:20
# set working directory
WORKDIR /app
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install app dependencies
COPY package.json ./
COPY package-lock.json ./
RUN npm install --silent
RUN npm install react-scripts@3.4.1 -g --silent
# add app
COPY . ./
# start app
CMD npm start
```
## Docker-Compose
docker-compose.yaml
```
services:
db:
image: postgres
build:
context: db
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=password
expose:
- 5432:5432
ports:
- 5432:5432
restart: always
app:
build: server/rps
expose:
- 8080:8080
ports:
- 8080:8080
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=password
depends_on:
- db
ui:
build: client
ports:
- 3000:3000
depends_on:
- app
```
## RPS Game Logic
- Add server side logic
- Add UI to communicate with server
## Your First Azure Container
## Installing CLI
- [https://learn.microsoft.com/en-us/cli/azure/install-azure-cli](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
- Azure Login:
- WSL: ```az login --use-device-code```
- Mac: ```az login```
## Your First Container
- [https://learn.microsoft.com/en-us/azure/container-instances/container-instances-quickstart](https://learn.microsoft.com/en-us/azure/container-instances/container-instances-quickstart)
```
$ az group create --name myResourceGroup --location eastus
$ az container create --resource-group myResourceGroup --name mycontainer --image mcr.microsoft.com/azuredocs/aci-helloworld --dns-name-label aci-demo --ports 80
$ az container show --resource-group myResourceGroup --name mycontainer --query "{FQDN:ipAddress.fqdn,ProvisioningState:provisioningState}" --out table
```
- Run the site provided
- You will have to update your dns label name
## Azure With Docker Compose
## Sample
[https://learn.microsoft.com/en-us/azure/container-instances/tutorial-docker-compose](https://learn.microsoft.com/en-us/azure/container-instances/tutorial-docker-compose)
```$ az acr repository show --name --repository azure-vote-front```
- remove the initial directory in the above command
- wait a few minutes after pushing before the IP address works
## Create a New React App
```
npx create-react-app myapp
cd myapp
npm install
npm start
```
## Dockerfile
```
FROM node:16.13.1-alpine as build
RUN npm install -g serve # A simple webserver
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 80
CMD ["serve", "-s", "build", "-l", "80"]
```
## Docker-compose.yaml
```
version: '3'
services:
ui:
build: .
image: samplereactacr.azurecr.io/ui
container_name: samplereact
ports:
- "80:80"
```
```
docker compose build
docker compose up
```
Note: We're using port 80
## Create Azure Parts
- Create an Azure Resource Group
- Create an Azure Container Registry
- Create an Azure Container Instance docker context
```
az login --use-device-code
az acr login --name samplereactacr
docker context create aci samplereactaci
docker context ls
```
## Push to Azure and Run Container Instances
```
docker-compose push
docker context use samplereactaci
docker compose up
docker ps
```
## Azure With Docker Compose
## RPS
- Removed firebase authentication for simplicity
```
curl localhost:8080/api/getUsers
```
Dockerfile
```
FROM maven:3.8.7-eclipse-temurin-19 AS build
ADD . /project
WORKDIR /project
RUN mvn -e package
FROM eclipse-temurin:latest
COPY --from=build /project/target/rps-0.0.1-SNAPSHOT.jar /app/rps.jar
ENTRYPOINT ["java","-jar","/app/rps.jar"]
```
## Create Azure Parts
- Create an Azure Resource Group
- Create an Azure Container Registry
- Create an Azure Container Instance docker context
```
az login --use-device-code
az acr login --name rpsacr
docker context create aci rpsaci
docker context ls
```
## docker-compose.yaml
```
services:
db:
build: db
image: rpsacr.azurecr.io/db
container_name: db
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=password
expose:
- 5432:5432
ports:
- 5432:5432
restart: always
app:
build: server/rps
image: rpsacr.azurecr.io/app
container_name: app
ports:
- 8080:8080
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=password
depends_on:
- db
```
## Push to Azure and Run Container Instances
```
docker-compose push
docker context use rpsaci
docker compose up
docker ps
```
## Check db and server
- Check dbeaver
- host: IP address
- port: 5432
- database: rps
- username/password: postgres/password
- Curl the IP address and API
```
curl 4.156.198.75:8080/api/getUsers
```
## Adding the React UI Separately
Dockerfile
```
FROM node:16.13.1-alpine as build
RUN npm install -g serve # A simple webserver
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 80
CMD ["serve", "-s", "build", "-l", "80"]
```
- Update IP address of server
## Adding the React UI Separately
docker-compose.yaml
```
version: '3'
services:
ui:
build: .
image: rpsacr.azurecr.io/ui
container_name: uitest
ports:
- "80:80"
```
## Push to Azure and Run Container Instances
```
docker compose build
docker-compose push
docker context use rpsaci
docker compose up
docker ps
```