In this section we will deploy the Mushroom App to GCP. For this we will create a VM instance in GCP and deploy the following container on the VM:
- api-service
- frontend-react
- Go to
http://localhost:9000/docs
and make sure you can see the API Docs
- Go to
http://localhost:3000/
and make sure you can see the prediction page
- Sign up in Docker Hub and create an Access Token
- Open a new terminal
- Login to the Hub:
docker login -u <USER NAME> -p <ACCESS TOKEN>
- Inside the folder
api-service
, make sure you are not in the docker shell - Build and Tag the Docker Image:
docker build -t <USER NAME>/mushroom-app-api-service -f Dockerfile .
- If you are on M1/2 Macs: Build and Tag the Docker Image:
docker build -t <USER NAME>/mushroom-app-api-service --platform=linux/amd64/v2 -f Dockerfile .
- Push to Docker Hub:
docker push <USER NAME>/mushroom-app-api-service
- We need to rebuild the frontend as we are building th react app for production release. So we use the
Dockerfile
instead of theDocker.dev
file - Inside the folder
frontend-react
, make sure you are not in the docker shell - Build and Tag the Docker Image:
docker build -t <USER NAME>/mushroom-app-frontend -f Dockerfile .
- Push to Docker Hub:
docker push <USER NAME>/mushroom-app-frontend
Docker Build, Tag & Push commands should look like this:
docker build -t dlops/mushroom-app-api-service --platform=linux/amd64/v2 -f Dockerfile .
docker push dlops/mushroom-app-api-service
docker build -t dlops/mushroom-app-frontend --platform=linux/amd64/v2 -f Dockerfile .
docker push dlops/mushroom-app-frontend
- Create a VM Instance from GCP
- When creating the VM, you can select all the default values but ensure to select:
- Machine Type: N2D
- Allow HTTP traffic
- Allow HTTPS traffic
- SSH into your newly created instance Install Docker on the newly created instance by running
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Check version of installed Dockersudo docker --version
sudo mkdir persistent-folder
sudo mkdir secrets
sudo mkdir -p conf/nginx
sudo chmod 0777 persistent-folder
sudo chmod 0777 secrets
sudo chmod -R 0777 conf
sudo mkdir persistent-folder
sudo mkdir secrets
sudo mkdir -p conf/nginx
sudo chmod 0777 persistent-folder
sudo chmod 0777 secrets
sudo chmod -R 0777 conf
- Create a file
bucket-reader.json
insidesecrets
folder with the secrets json provided - You can create a file using the echo command:
echo '<___Provided Json Key___>' > secrets/bucket-reader.json
sudo docker network create mushroom-app
Run the container using the following command
sudo docker run -d --name api-service \
-v "$(pwd)/persistent-folder/":/persistent \
-v "$(pwd)/secrets/":/secrets \
-p 9000:9000 \
-e GOOGLE_APPLICATION_CREDENTIALS=/secrets/bucket-reader.json \
-e GCS_BUCKET_NAME=mushroom-app-models \
--network mushroom-app dlops/mushroom-app-api-service
If you want to run in interactive mode like we id in development:
sudo docker run --rm -ti --name api-service \
-v "$(pwd)/persistent-folder/":/persistent \
-v "$(pwd)/secrets/":/secrets \
-p 9000:9000 \
-e GOOGLE_APPLICATION_CREDENTIALS=/secrets/bucket-reader.json \
-e GCS_BUCKET_NAME=mushroom-app-models \
-e DEV=1 \
--network mushroom-app dlops/mushroom-app-api-service
Run the container using the following command
sudo docker run -d --name frontend -p 3000:80 --network mushroom-app dlops/mushroom-app-frontend
- Create
nginx.conf
echo 'user nginx;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
gzip on;
gzip_disable "msie6";
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
server {
listen 80;
server_name localhost;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# API
location /api {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://api-service:9000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_buffering off;
}
# Frontend
location / {
rewrite ^/(.*)$ /$1 break;
proxy_pass http://frontend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_buffering off;
}
}
}
' > conf/nginx/nginx.conf
Run the container using the following command
sudo docker run -d --name nginx -v $(pwd)/conf/nginx/nginx.conf:/etc/nginx/nginx.conf -p 80:80 --network mushroom-app nginx:stable
You can access the deployed API using http://<Your VM IP Address>/
In this section we will deploy the Mushroom App to GCP using Ansible Playbooks. We will automate all the deployment steps we did previously.
Search for each of these in the GCP search bar and click enable to enable these API's
- Compute Engine API
- Service Usage API
- Cloud Resource Manager API
- Google Container Registry API
- Here are the step to create a service account:
- To setup a service account you will need to go to GCP Console, search for "Service accounts" from the top search box. or go to: "IAM & Admins" > "Service accounts" from the top-left menu and create a new service account called "deployment".
- Give the following roles:
- For
deployment
:- Compute Admin
- Compute OS Login
- Container Registry Service Agent
- Kubernetes Engine Admin
- Service Account User
- Storage Admin
- Then click done.
- This will create a service account
- On the right "Actions" column click the vertical ... and select "Create key". A prompt for Create private key for "deployment" will appear select "JSON" and click create. This will download a Private key json file to your computer. Copy this json file into the secrets folder.
- Rename the json key file to
deployment.json
- Follow the same process Create another service account called
gcp-service
- For
gcp-service
give the following roles:- Storage Object Viewer
- Then click done.
- This will create a service account
- On the right "Actions" column click the vertical ... and select "Create key". A prompt for Create private key for "gcp-service" will appear select "JSON" and click create. This will download a Private key json file to your computer. Copy this json file into the secrets folder.
- Rename the json key file to
gcp-service.json
Rather than each of installing different tools for deployment we will use Docker to build and run a standard container will all required software.
-
cd into
deployment
-
Go into
docker-shell.sh
ordocker-shell.bat
and changeGCP_PROJECT
to your project id -
Run
sh docker-shell.sh
ordocker-shell.bat
for windows -
Check versions of tools:
gcloud --version
ansible --version
kubectl version --client
- Check to make sure you are authenticated to GCP
- Run
gcloud auth list
Now you have a Docker container that connects to your GCP and can create VMs, deploy containers all from the command line
gcloud compute project-info add-metadata --project <YOUR GCP_PROJECT> --metadata enable-oslogin=TRUE
example:
gcloud compute project-info add-metadata --project ac215-project --metadata enable-oslogin=TRUE
cd /secrets
ssh-keygen -f ssh-key-deployment
cd /app
gcloud compute os-login ssh-keys add --key-file=/secrets/ssh-key-deployment.pub
From the output of the above command keep note of the username. Here is a snippet of the output
- accountId: ac215-project
gid: '3906553998'
homeDirectory: /home/sa_100110341521630214262
name: users/deployment@ac215-project.iam.gserviceaccount.com/projects/ac215-project
operatingSystemType: LINUX
primary: true
uid: '3906553998'
username: sa_100110341521630214262
The username is sa_100110341521630214262
- Add ansible user details in inventory.yml file
- GCP project details in inventory.yml file
- GCP Compute instance details in inventory.yml file
ansible-playbook deploy-docker-images.yml -i inventory.yml
ansible-playbook deploy-create-instance.yml -i inventory.yml --extra-vars cluster_state=present
Once the command runs successfully get the IP address of the compute instance from GCP Console and update the appserver>hosts in inventory.yml file
Install and setup all the required things for deployment.
ansible-playbook deploy-provision-instance.yml -i inventory.yml
ansible-playbook deploy-setup-containers.yml -i inventory.yml
You can SSH into the server from the GCP console and see status of containers
sudo docker container ls
sudo docker container logs api-service -f
To get into a container run:
sudo docker exec -it api-service /bin/bash
- Create nginx.conf file for defaults routes in web server
ansible-playbook deploy-setup-webserver.yml -i inventory.yml
Once the command runs go to http://<External IP>/
ansible-playbook deploy-create-instance.yml -i inventory.yml --extra-vars cluster_state=absent
In this section we will deploy the mushroom app to a K8s cluster
Search for each of these in the GCP search bar and click enable to enable these API's
- Compute Engine API
- Service Usage API
- Cloud Resource Manager API
- Google Container Registry API
- Kubernetes Engine API
-
cd deployment
-
Run
sh docker-shell.sh
ordocker-shell.bat
for windows -
Check versions of tools
gcloud --version
kubectl version
kubectl version --client
-
Check if make sure you are authenticated to GCP
-
Run
gcloud auth list
This step is only required if you have NOT already done this
ansible-playbook deploy-docker-images.yml -i inventory.yml
ansible-playbook deploy-k8s-cluster.yml -i inventory.yml --extra-vars cluster_state=present
kubectl get all
kubectl get all --all-namespaces
kubectl get pods --all-namespaces
kubectl get componentstatuses
kubectl get nodes
kubectl get pods --namespace=mushroom-app-cluster-namespace
kubectl get pod api-5d4878c545-47754 --namespace=mushroom-app-cluster-namespace
kubectl exec --stdin --tty api-5d4878c545-47754 --namespace=mushroom-app-cluster-namespace -- /bin/bash
- Copy the
nginx_ingress_ip
from the terminal from the create cluster command - Go to
http://<YOUR INGRESS IP>.sslip.io
ansible-playbook deploy-k8s-cluster.yml -i inventory.yml --extra-vars cluster_state=absent
We have already done this in the deployment tutorial but in case you have not done that step. Search for each of these in the GCP search bar and click enable to enable these API's
- Compute Engine API
- Service Usage API
- Cloud Resource Manager API
- Google Container Registry API
- Kubernetes Engine API
-
cd deployment
-
Run
sh docker-shell.sh
ordocker-shell.bat
for windows -
Check versions of tools
gcloud --version
kubectl version
kubectl version --client
-
Check if make sure you are authenticated to GCP
-
Run
gcloud auth list
gcloud container clusters create test-cluster --num-nodes 2 --zone us-east1-c
- Go to the Kubernetes Engine menu item to see the cluster details
- Click on the cluster name to see the cluster details
- Click on the Nodes tab to view the nodes
- Click on any node to see the pods running in the node
- Go to the Compute Engine menu item to see the VMs in the cluster
kubectl get all
kubectl get all --all-namespaces
kubectl get pods --all-namespaces
kubectl get componentstatuses
kubectl get nodes
kubectl apply -f deploy-k8s-tic-tac-toe.yml
kubectl get services
- Copy the
External IP
from thekubectl get services
- Go to
http://<YOUR EXTERNAL IP>
gcloud container clusters delete test-cluster --zone us-east1-c
If you want to debug any of the containers to see if something is wrong
- View running containers
sudo docker container ls
- View images
sudo docker image ls
- View logs
sudo docker container logs api-service -f
sudo docker container logs frontend -f
sudo docker container logs nginx -f
- Get into shell
sudo docker exec -it api-service /bin/bash
sudo docker exec -it frontend /bin/bash
sudo docker exec -it nginx /bin/bash