Skip to content

Commit c7d437e

Browse files
authored
Merge pull request #1 from manning-ncsa/master
Corrected internal port in webapp docker run command
2 parents b872cfd + f32e3e0 commit c7d437e

10 files changed

+474
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
data/
22
*.pyc
3+
.DS_Store

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Let's build the front end:
9595

9696
To deploy locally, we need to link to `demo-mysql` and add environmental variables with `-e`:
9797

98-
docker run --name my-first-app -d -p 8080:8080 --link demo-mysql:remote-mysql -e MYSQL_USER=root -e MYSQL_PASS=<PASSWORD> -e MYSQL_SERVER=remote-mysql webapp
98+
docker run --name my-first-app -d -p 8080:8081 --link demo-mysql:remote-mysql -e MYSQL_USER=root -e MYSQL_PASS=<PASSWORD> -e MYSQL_SERVER=remote-mysql webapp
9999

100100
Now you can access in your browser at [http://localhost:8080](http://localhost:8080)
101101

k8s-demo-app/Dockerfile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM python:3
2+
# Install (as root) the modules needed to run the application
3+
RUN pip install --no-cache-dir tornado gviz_api mysqlclient
4+
5+
# Create a demo folder
6+
RUN mkdir demo
7+
# Copy all the files inside the demo folder
8+
ADD ./src /demo
9+
# Change to /demo at run-time
10+
WORKDIR /demo
11+
# Execute this command when running the container, can be override
12+
CMD [ "python", "main.py" ]

k8s-demo-app/README.md

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
Build a web app with Kubernetes
2+
===============================
3+
4+
This tutorial shows how to build a Docker image to serve a web app and how to deploy that service using [Kubernetes](https://kubernetes.io/) (k8s). Unless otherwise stated, the commands are assumed to run from the working directory containing this `README.md` file.
5+
6+
Verify operation manually with Docker
7+
-------------------------------------
8+
9+
Deploy a container for the MySQL database service:
10+
```
11+
docker run -d --rm --name demo-app-db \
12+
-p 3306:3306 \
13+
-e MYSQL_ROOT_PASSWORD=password \
14+
mysql:5.6
15+
```
16+
Build the demo app Docker image:
17+
```
18+
docker build -t k8s-demo-app .
19+
```
20+
Deploy a container for the web app frontend:
21+
```
22+
docker run -d --rm --name demo-app \
23+
--link demo-app-db:mysql \
24+
-p 8080:8080 \
25+
-e HTTP_PORT=8080 \
26+
-e MYSQL_USER=root \
27+
-e MYSQL_PASS=password \
28+
-e MYSQL_SERVER=mysql \
29+
-e MYSQL_PORT=3306 \
30+
k8s-demo-app
31+
```
32+
View the running containes using `docker ps`:
33+
```
34+
$ docker ps
35+
36+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
37+
5d26164017cc k8s-demo-app "python main.py" 6 seconds ago Up 5 seconds 0.0.0.0:8080->8080/tcp demo-app
38+
e9b65488d224 mysql:5.6 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:3306->3306/tcp demo-app-db
39+
```
40+
Open [0.0.0.0:8080](0.0.0.0:8080) in your browser to view the web app in action. If you verified that it works, proceed to deployment via Kubernetes.
41+
42+
Deployment using Kubernetes via Minikube
43+
----------------------
44+
45+
Launch a local single-node cluster using [minikube](https://kubernetes.io/docs/tutorials/hello-minikube/):
46+
```
47+
minikube start
48+
```
49+
(_optional_) Open the dashboard for real-time status and control of the cluster:
50+
```
51+
minikube dashboard
52+
```
53+
Configure your shell session for local development:
54+
```
55+
eval $(minikube docker-env)
56+
```
57+
Minikube runs a k8s cluster in a virtual machine (VM) which will not see the `k8s-demo-app` image you built earlier on the host machine (use `docker image list` to check), so build it "again" in Minikube:
58+
```
59+
docker build -t k8s-demo-app .
60+
```
61+
Verify that the image is available to Docker locally:
62+
```
63+
$ docker image list
64+
65+
REPOSITORY TAG IMAGE ID CREATED SIZE
66+
k8s-demo-app latest 2aaa1d3c86a7 5 seconds ago 942MB
67+
...
68+
```
69+
Apply the k8s configuration file `k8s-demo-app.yaml`:
70+
```
71+
kubectl apply -f k8s-demo-app.yaml
72+
```
73+
If everything is deployed properly, you should see green check mark icons in the dashboard web view. Alternatively, you can view status using commands:
74+
```
75+
$ kubectl get deployment
76+
77+
NAME READY UP-TO-DATE AVAILABLE AGE
78+
demo-app 1/1 1 1 22m
79+
demo-app-db 1/1 1 1 22m
80+
81+
$ kubectl get pod
82+
83+
NAME READY STATUS RESTARTS AGE
84+
demo-app-58b96f7ffc-h528m 1/1 Running 3 22m
85+
demo-app-db-5fc7d9c565-wjmj2 1/1 Running 0 22m
86+
87+
$ kubectl get service
88+
89+
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
90+
demo-app NodePort 10.106.45.30 <none> 8080:32065/TCP 22m
91+
demo-app-db NodePort 10.109.151.26 <none> 3306:32542/TCP 22m
92+
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 42m
93+
```
94+
95+
Since your k8s cluster is running in a VM, you must use `minikube` to discover the demo app "external" URL so that you can open it in a browser:
96+
```
97+
$ minikube service list
98+
|----------------------|---------------------------|-----------------------------|-----|
99+
| NAMESPACE | NAME | TARGET PORT | URL |
100+
|----------------------|---------------------------|-----------------------------|-----|
101+
| default | demo-app | http://192.168.99.104:32065 |
102+
| default | demo-app-db | http://192.168.99.104:32542 |
103+
...
104+
```
105+
You can launch the web page directly using
106+
```
107+
minikube service demo-app
108+
```
109+
110+
---
111+
112+
<img src="./demoapp.png" />
113+
114+
---
115+
116+
You will notice that when you refresh the page, the same "pod" name is displayed because there is only one pod for the demo-app "deployment". (In this demo, "pod" is equivalent to "container" because each pod consists of only a single container.) Edit the deployment configuration file `k8s-demo-app.yaml` to specify a number of "replicas":
117+
```
118+
...
119+
apiVersion: apps/v1
120+
kind: Deployment
121+
metadata:
122+
name: demo-app
123+
spec:
124+
replicas: 3
125+
selector:
126+
matchLabels:
127+
app: demo-app
128+
template:
129+
...
130+
```
131+
Then simply reapply the config to the cluster:
132+
```
133+
kubectl apply -f k8s-demo-app.yaml
134+
```
135+
Now you should see three identical pods deployed (exact names will vary):
136+
```
137+
$ kubectl get pod
138+
139+
NAME READY STATUS RESTARTS AGE
140+
demo-app-58b96f7ffc-h528m 1/1 Running 3 37m
141+
demo-app-58b96f7ffc-n7m6q 1/1 Running 0 9s
142+
demo-app-58b96f7ffc-vn9v5 1/1 Running 0 9s
143+
demo-app-db-5fc7d9c565-wjmj2 1/1 Running 0 37m
144+
```
145+
When you refresh the web page a few times (using CTRL+SHIFT+R or equivalent cache-flushing method) you should see the pod name cycle through the three available pods.
146+
147+
<img src="./loadbalancer.gif" />

k8s-demo-app/demoapp.png

44.7 KB
Loading

k8s-demo-app/k8s-demo-app.yaml

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
# Define ingress controller
3+
---
4+
apiVersion: networking.k8s.io/v1beta1
5+
kind: Ingress
6+
metadata:
7+
name: demo-app
8+
annotations:
9+
nginx.ingress.kubernetes.io/rewrite-target: /
10+
spec:
11+
rules:
12+
- http:
13+
paths:
14+
- path: /demo
15+
backend:
16+
serviceName: demo-app
17+
servicePort: 8080
18+
# Define services
19+
---
20+
apiVersion: v1
21+
kind: Service
22+
metadata:
23+
name: demo-app
24+
spec:
25+
type: NodePort
26+
ports:
27+
- port: 8080
28+
selector:
29+
app: demo-app
30+
---
31+
apiVersion: v1
32+
kind: Service
33+
metadata:
34+
name: demo-app-db
35+
spec:
36+
type: NodePort
37+
ports:
38+
- port: 3306
39+
selector:
40+
app: demo-app-db
41+
---
42+
# Define deployments
43+
---
44+
apiVersion: apps/v1
45+
kind: Deployment
46+
metadata:
47+
name: demo-app
48+
spec:
49+
replicas: 1
50+
selector:
51+
matchLabels:
52+
app: demo-app
53+
template:
54+
metadata:
55+
labels:
56+
app: demo-app
57+
spec:
58+
containers:
59+
- image: k8s-demo-app:latest
60+
imagePullPolicy: IfNotPresent
61+
name: demo-app
62+
env:
63+
- name: HTTP_PORT
64+
value: "8080"
65+
- name: MYSQL_PASS
66+
value: "password"
67+
- name: MYSQL_USER
68+
value: "root"
69+
- name: MYSQL_SERVER
70+
value: "demo-app-db"
71+
- name: MYSQL_PORT
72+
value: "3306"
73+
ports:
74+
- containerPort: 8080
75+
name: demo-app
76+
---
77+
apiVersion: apps/v1
78+
kind: Deployment
79+
metadata:
80+
name: demo-app-db
81+
spec:
82+
selector:
83+
matchLabels:
84+
app: demo-app-db
85+
template:
86+
metadata:
87+
labels:
88+
app: demo-app-db
89+
spec:
90+
containers:
91+
- image: mysql:5.6
92+
imagePullPolicy: IfNotPresent
93+
name: demo-app-db
94+
env:
95+
- name: MYSQL_ROOT_PASSWORD
96+
value: "password"
97+
ports:
98+
- containerPort: 3306
99+
name: demo-app-db

k8s-demo-app/loadbalancer.gif

1.4 MB
Loading

k8s-demo-app/src/Settings.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
""" Settings for application"""
2+
import os
3+
DEBUG = True
4+
DIRNAME = os.path.dirname(__file__)
5+
STATIC_PATH = os.path.join(DIRNAME, 'static')
6+
TEMPLATE_PATH = os.path.join(DIRNAME, 'templates')

0 commit comments

Comments
 (0)