In this document, I try to demonstrate a use case of kubernetes to deploy a simple static web page.
The network in kubernetes usually will have a topology like the figure below. In this example, we will start from the bottom, which are pods, and will build up the network.
Example network topology (image from this article) |
---|
Step 0: have a webserver docker image ready with the contents of your web page
- There are various ways to deploy web server on the k8s. Here we assume that you have a docker image of the web server and all the contents of your pages.
- We will use "registry.kasi.re.kr/uwife/uwife_www" that I (Jae-Joon Lee) have personally created.
- The image is based on nginx web server and the copy of the web pages I will serve.
- The Dockerfile and all its contents are available at https://data.kasi.re.kr/gitlab/leejjoon/uwife-www
Step 1: Deployment
- The "deployment" resource is often used when you want scalable number of pods.
apiVersion: apps/v1 kind: Deployment metadata: name: uwife-www spec: replicas: 1 selector: matchLabels: app: uwife-www template: metadata: labels: app: uwife-www spec: containers: - name: uwife-www image: registry.kasi.re.kr/uwife/uwife_www
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get pods No resources found in default namespace. ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get deployments No resources found in default namespace. ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k apply -f deployment_uwife_www.yaml deployment.apps/uwife-www created ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get deployments NAME READY UP-TO-DATE AVAILABLE AGE uwife-www 0/1 1 0 7s ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get pods NAME READY STATUS RESTARTS AGE uwife-www-79b5cc8898-l585l 1/1 Running 0 17s ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get deployments NAME READY UP-TO-DATE AVAILABLE AGE uwife-www 1/1 1 1 20s |
---|
- We see that it has created a pod with an internal ip of 10.100.95.194.
- The ip is only accessible inside the k8s cluster (including, master and worker nodes).
- To test, lets login to the master node.
- Note that to login to the master (or worker nodes), you need to set the ssh-key properly while creating the cluster. You can
## Let's find out the ip address of the master node and ssh in to it. ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get nodes -o wide|grep master ## You are now logged into the master node, and you can check the connection to the pod with a simple curl command. |
---|
Step 2: Create a service for external connection.
- To access the pod from outside, you need to create a service resource for it.
- Here we will use "NodePort" type service. With the "NodePort" service, you will create a connection from a port in any of the worker nodes to the pod.
apiVersion: v1 kind: Service metadata: name: uwife-www spec: type: NodePort selector: app: uwife-www ports: - port: 80 targetPort: 80
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 24h ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k apply -f service_uwife_www.yaml service/uwife-www created ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 24h uwife-www NodePort 10.254.132.132 <none> 80:31349/TCP 4s |
---|
- Now, if you can reach any of the k8s nodes (only the worker nodes), you can reach the pod with the port number 31349
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get nodes NAME STATUS ROLES AGE VERSION spherex-k8s-10-n2fw4cjrwsza-master-0 Ready master 24h v1.18.2 spherex-k8s-10-n2fw4cjrwsza-node-0 Ready <none> 24h v1.18.2 spherex-k8s-10-n2fw4cjrwsza-node-1 Ready <none> 24h v1.18.2 spherex-k8s-10-n2fw4cjrwsza-node-2 Ready <none> 24h v1.18.2 spherex-k8s-10-n2fw4cjrwsza-node-3 Ready <none> 7h14m v1.18.2 ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ curl -I 10.0.1.223:31349 HTTP/1.1 200 OK Server: nginx/1.22.0 Date: Wed, 08 Jun 2022 11:01:17 GMT Content-Type: text/html Content-Length: 35 Last-Modified: Fri, 30 May 2014 06:14:51 GMT Connection: keep-alive ETag: "538821db-23" Accept-Ranges: bytes |
---|
- Similarly, you can assign a virtual ip by creating a "LoadBalancer" service.
- But, for now, the loadbalancer requires floating ip assigned to it, which can limit its usage.
- Instead, you can use Ingress resources. It can create a internal vip and/or use same ip for different services.
Step 3: Create am Ingress for external connection with routing.
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: default-internal-ingress annotations: kubernetes.io/ingress.class: "openstack" octavia.ingress.kubernetes.io/internal: "true" spec: rules: - host: k8s-10.gems0.org http: paths: - path: / pathType: Prefix backend: serviceName: uwife-www servicePort: 80
- Note that on line 7, we specify "internal" as true. Thus it won't try to allocate external floating ip.
- We also says the if the incoming traffic haas a target Host name of "k8s-10.gems0.org", the traffic will be forwarded to the "uwife-www" service.
- We are using "octavia" ingress controller for openstack, and it only allows NodePort service as a backend.
- Once you apply that yaml file to create the ingress object, you will see a ip address will be assigned (this can take several seconds). Note that this will automatically create an loadbalancer object in the openstack.
- And your web page accessible with the allocated ip (10.0.1.156 in this case), but the Header should specify the host name of k8s-10.gems0.org.
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get ing NAME CLASS HOSTS ADDRESS PORTS AGE default-internal-ingress <none> k8s-10.gems0.org 10.0.1.156 80 87m ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ curl -I -H "Host: k8s-10.gems0.org" 10.0.1.156 HTTP/1.1 200 OK Server: nginx/1.22.0 Date: Wed, 08 Jun 2022 11:29:10 GMT Content-Type: text/html Content-Length: 35 Last-Modified: Fri, 30 May 2014 06:14:51 GMT ETag: "538821db-23" Accept-Ranges: bytes |
---|
- Similarly, you can create an ingress object with an external floating ip. However, in this case, you can access multiple services by having different rules for different services (e.g., different host name)
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: default-external-ingress annotations: kubernetes.io/ingress.class: "openstack" octavia.ingress.kubernetes.io/internal: "false" spec: rules: - host: k8s-10.gems0.org http: paths: - path: / pathType: Prefix backend: serviceName: uwife-www servicePort: 80
- The only change we made (other than the name) is t set "internal" as false in line 7. Thus it will try to allocate the floating ip.
- In this case, the floating ip of "210.219.33.217" is assigned to this ingress object.
- Note that you can add multiple rules to the above yaml file and reapply to have this ingress object to forward your traffic to multiple services.
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get ing NAME CLASS HOSTS ADDRESS PORTS AGE default-external-ingress <none> k8s-10.gems0.org 210.219.33.217 80 88m default-internal-ingress <none> k8s-10.gems0.org 10.0.1.156 80 100m ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ curl -I -H "Host: k8s-10.gems0.org" 210.219.33.217 HTTP/1.1 200 OK Server: nginx/1.22.0 Date: Wed, 08 Jun 2022 11:36:33 GMT Content-Type: text/html Content-Length: 35 Last-Modified: Fri, 30 May 2014 06:14:51 GMT ETag: "538821db-23" Accept-Ranges: bytes |
---|
- Now, change your DNS seeting so that the host name of "k8s-10.gems0.org" to the ip of 210.219.33.217.
- We assume you have your own domain you can manipulate. If not, you may test it with nip hostname (https://nip.io/). In this case, duplicate the host rule in the yaml with the host name replaced with "210-219-33-217.nip.io"
- Once the DNS is set, you can access the side with the host name.
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ nslookup k8s-10.gems0.org Server: 127.0.0.53 Address: 127.0.0.53#53 Non-authoritative answer: k8s-10.gems0.org canonical name = k8s-ing217.gems0.org. Name: k8s-ing217.gems0.org Address: 210.219.33.217 ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ curl -I k8s-10.gems0.org HTTP/1.1 200 OK Server: nginx/1.22.0 Date: Wed, 08 Jun 2022 11:46:32 GMT Content-Type: text/html Content-Length: 35 Last-Modified: Fri, 30 May 2014 06:14:51 GMT ETag: "538821db-23" Accept-Ranges: bytes |
---|
- And now you can open the page in your web browser.
- Of course, the site is only accessible from the KAS intranet because of the KASAI firewall. If you want allow public access, you need to talk to the KASI computer management team to allow inbound traffic on that ip address.
- You can setup a ssl certificate for your site and make HTTPS connection accessible, but this won't be covered here.
Step 4: Scale out your web page.
- If your web page become super popular, a single web server cannot handle your traffic.
- The virtue of kubernetes is its ease of scaling out.
- You simply change the "replicas" number (line 6) and reapply. And you will have multiple pods serving your web page.
apiVersion: apps/v1 kind: Deployment metadata: name: uwife-www spec: replicas: 3 selector: matchLabels: app: uwife-www template: metadata: labels: app: uwife-www spec: containers: - name: uwife-www image: registry.kasi.re.kr/uwife/uwife_www
# We start with a single pod. ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get pods ## Edit the YAML file to increase the replica number and reapply. ## Wait for several seconds for the pods to start up. ## You now have 3 pods serving your web pages. ## The ingress and service objects you created will automatically divide the traffic to each pod. |
---|
- Note that the service object you created will automatically divide the traffic to each pod.
- In the example below, note the uwife-www service now have 3 endpoints pointing each pods.
ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES uwife-www-79b5cc8898-2sdkj 1/1 Running 0 19m 10.100.64.131 spherex-k8s-10-n2fw4cjrwsza-node-2 <none> <none> uwife-www-79b5cc8898-b67gb 1/1 Running 0 19m 10.100.205.195 spherex-k8s-10-n2fw4cjrwsza-node-1 <none> <none> uwife-www-79b5cc8898-l585l 1/1 Running 0 96m 10.100.95.194 spherex-k8s-10-n2fw4cjrwsza-node-3 <none> <none> ubuntu@spherex-gw:~/git/k8s-leejjoon-test/simple_webserver_uwife$ k describe svc uwife-www Name: uwife-www Namespace: default Labels: <none> Annotations: <none> Selector: app=uwife-www Type: NodePort IP Families: <none> IP: 10.254.132.132 IPs: <none> Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 31349/TCP Endpoints: 10.100.205.195:80,10.100.64.131:80,10.100.95.194:80 Session Affinity: None External Traffic Policy: Cluster Events: <none> |
---|