Skip to content

Latest commit

 

History

History
388 lines (312 loc) · 16.9 KB

scalable-webapp-kubernetes.md

File metadata and controls

388 lines (312 loc) · 16.9 KB
copyright lastupdated
years
2017, 2018
2018-11-16

{:shortdesc: .shortdesc} {:new_window: target="_blank"} {:codeblock: .codeblock} {:screen: .screen} {:tip: .tip} {:pre: .pre}

Scalable web application on Kubernetes

This tutorial walks you through how to scaffold a web application, run it locally in a container, and then deploy it to a Kubernetes cluster created with {{site.data.keyword.containershort_notm}}. Additionally, you will learn how to bind a custom domain, monitor the health of the environment, and scale the application. {:shortdesc}

Containers are a standard way to package apps and all their dependencies so that you can seamlessly move the apps between environments. Unlike virtual machines, containers do not bundle the operating system. Only the app code, run time, system tools, libraries, and settings are packaged inside containers. Containers are more lightweight, portable, and efficient than virtual machines.

For developers looking to kickstart their projects, the {{site.data.keyword.dev_cli_notm}} CLI enables rapid application development and deployment by generating template applications that you can run immediately or customize as the starter for your own solutions. In addition to generating starter application code, Docker container image and CloudFoundry assets, the code generators used by the dev CLI and web console generate files to aid deployment into Kubernetes environments. The templates generate Helm charts that describe the application’s initial Kubernetes deployment configuration, and are easily extended to create multi-image or complex deployments as needed.

Objectives

{: #objectives}

  • Scaffold a starter application.
  • Deploy the application to the Kubernetes cluster.
  • Bind a custom domain.
  • Monitor the logs and health of the cluster.
  • Scale Kubernetes pods.

Services used

{: #services}

This tutorial uses the following runtimes and services:

This tutorial may incur costs. Use the Pricing Calculator to generate a cost estimate based on your projected usage.

Architecture

{: #architecture}

Architecture

  1. A developer generates a starter application with {{site.data.keyword.dev_cli_notm}}.
  2. Building the application produces a Docker container image.
  3. The image is pushed to a namespace in {{site.data.keyword.containershort_notm}}.
  4. The application is deployed to a Kubernetes cluster.
  5. Users access the application.

Before you begin

{: #prereqs}

Create a Kubernetes cluster

{: #create_kube_cluster}

{{site.data.keyword.containershort_notm}} delivers powerful tools by combining Docker and Kubernetes technologies, an intuitive user experience, and built-in security and isolation to automate the deployment, operation, scaling, and monitoring of containerized apps in a cluster of compute hosts.

The major portion of this tutorial can be accomplished with a Free cluster. Two optional sections relating to Kubernetes Ingress and custom domain require a Paid cluster of type Standard.

  1. Create a Kubernetes cluster from the {{site.data.keyword.Bluemix}} catalog.

    For ease of use, check the configuration details like the number of CPUs, memory and the number of worker nodes you get with Lite and Standard plans. {:tip}

    Kubernetes Cluster Creation on IBM Cloud

  2. Select the Cluster type and click Create Cluster to provision a Kubernetes cluster.

  3. Check the status of your Cluster and Worker Nodes and wait for them to be ready.

Configure kubectl

In this step, you'll configure kubectl to point to your newly created cluster going forward. kubectl is a command line tool that you use to interact with a Kubernetes cluster.

  1. Use ibmcloud login to log in interactively. Provide the organization (org), location and space under which the cluster is created. You can reconfirm the details by running ibmcloud target command.
  2. When the cluster is ready, retrieve the cluster configuration by setting MYCLUSTER environment variable to your cluster name:
    export MYCLUSTER=<CLUSTER_NAME>
    ibmcloud cs cluster-config ${MYCLUSTER}
    {: pre}
  3. Copy and paste the export command to set the KUBECONFIG environment variable as directed. To verify whether the KUBECONFIG environment variable is set properly or not, run the following command: echo $KUBECONFIG
  4. Check that the kubectl command is correctly configured
    kubectl cluster-info
    {: pre}

Create a starter application

{: #create_application}

The ibmcloud dev tooling greatly cuts down on development time by generating application starters with all the necessary boilerplate, build and configuration code so that you can start coding business logic faster.

  1. Start the ibmcloud dev wizard.

    ibmcloud dev create
    

    {: pre}

  2. Select Backend Service / Web App > Java - MicroProfile / JavaEE > Java Web App with Eclipse MicroProfile and Java EE (Web App) to create a Java starter. (To create a Node.js starter instead, use Backend Service / Web App > Node> Node.js Web App with Express.js (Web App) )

  3. Enter a name for your application.

  4. Select the resource group where to deploy this application.

  5. Do not add additional services.

  6. Do not add a DevOps toolchain, select manual deployment.

This generates a starter application complete with the code and all the necessary configuration files for local development and deployment to cloud on Cloud Foundry or Kubernetes. For an overview of the files generated, see Project Contents Documentation.

Build the application

You can build and run the application as you normally would using mvn for java local development or npm for node development. You can also build a docker image and run the application in a container to ensure consistent execution locally and on the cloud. Use the following steps to build your docker image.

  1. Ensure your local Docker engine is started.

    docker ps
    

    {: pre}

  2. Change to the generated project directory.

    cd <project name>
    

    {: pre}

  3. Build the application.

    ibmcloud dev build
    

    {: pre}

    This might take a few minutes to run as all the application dependencies are downloaded and a Docker image, which contains your application and all the required environment, is built.

Run the application locally

  1. Run the container.

    ibmcloud dev run
    

    {: pre}

    This uses your local Docker engine to run the docker image that you built in the previous step.

  2. After your container starts, go to http://localhost:9080/<nameofproject>. If you created a Node.js application, go to http://localhost:3000/.

Deploy application to cluster using helm chart

{: #deploy}

In this section, you first push the Docker image to the IBM Cloud private container registry, and then create a Kubernetes deployment pointing to that image.

  1. Find your namespace by listing all the namespace in the registry.

    ibmcloud cr namespaces

    {: pre} If you have a namespace, make note of the name for use later. If you don't have one, create it.

    ibmcloud cr namespace-add <Name>

    {: pre}

  2. Set MYNAMESPACE and MYPROJECT environment variables to your namespace and project name respectively

    export MYNAMESPACE=<NAMESPACE>

    {: pre}

    export MYPROJECT=<PROJECT_NAME>

    {: pre}

  3. Identify your Container Registry (e.g. registry.ng.bluemix.net) by running ibmcloud cr info

  4. Set MYREGISTRY env var to your registry.

    export MYREGISTRY=<REGISTRY>

    {: pre}

  5. Build and tag (-t)the docker image

    docker build . -t ${MYREGISTRY}/${MYNAMESPACE}/${MYPROJECT}:v1.0.0

    {: pre}

  6. Push the docker image to your container registry on IBM Cloud

    docker push ${MYREGISTRY}/${MYNAMESPACE}/${MYPROJECT}:v1.0.0

    {: pre}

  7. On an IDE, navigate to values.yaml under chart\YOUR PROJECT NAME and update the image repository value pointing to your image on IBM Cloud container registry. Save the file.

    For image repository details, run echo ${MYREGISTRY}/${MYNAMESPACE}/${MYPROJECT}

  8. Helm helps you manage Kubernetes applications through Helm Charts, which helps define, install, and upgrade even the most complex Kubernetes application. Initialize Helm by navigating to chart\YOUR PROJECT NAME and running the below command in your cluster

    helm init

    {: pre} To upgrade helm, run this command helm init --upgrade {:tip}

  9. To install a Helm chart, change to the chart\YOUR PROJECT NAME directory and run the below command

helm install . --name ${MYPROJECT}

{: pre} 10. Use kubectl get service ${MYPROJECT}-service for your Java application and kubectl get service ${MYPROJECT}-application-service for your Node.js application to identify the public port the service is listening on. The port is a 5-digit number(e.g., 31569) under PORT(S). 11. For the public IP of worker node, run the below command

ibmcloud cs workers ${MYCLUSTER}

{: pre} 12. Access the Java application at http://worker-ip-address:portnumber/nameofproject and Node.js application at http://worker-ip-address:portnumber

Use the IBM-provided domain for your cluster

{: #ibm_domain}

In the previous step, the application was accessed with a not standard port. The service was exposed by way of Kubernetes NodePort feature.

Paid clusters come with an IBM-provided domain. This gives you a better option to expose applications with a proper URL and on standard HTTP/S ports.

Use Ingress to set up the cluster inbound connection to the service.

Ingress

  1. Identify your IBM-provided Ingress domain
    ibmcloud cs cluster-get ${MYCLUSTER}
    
    {: pre} to find
    Ingress subdomain:	mycluster.us-south.containers.appdomain.cloud
    Ingress secret:		mycluster
    
    {: screen}
  2. Create an Ingress file ingress-ibmdomain.yml pointing to your domain with support for HTTP and HTTPS. Use the following file as a template, replacing all the values wrapped in <> with the appropriate values from the above output.service-name is the name under ==> v1/Service in the above step or run kubectl get svc to find the service name of type NodePort.
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-for-ibmdomain-http-and-https
    spec:
      tls:
      - hosts:
        -  <ingress-sub-domain>
        secretName: <ingress-secret>
      rules:
      - host: <ingress-sub-domain>
        http:
          paths:
          - path: /
            backend:
              serviceName: <service-name>
              servicePort: 9080
    {: codeblock}
  3. Deploy the Ingress
    kubectl apply -f ingress-ibmdomain.yml
    {: pre}
  4. Access your application at https://<ingress-sub-domain>/<nameofproject>

Use your own custom domain

{: #custom_domain}

To use your custom domain, you need to update your DNS records with either a CNAME record pointing to your IBM-provided domain or an A record pointing to the portable public IP address of the IBM-provided Ingress. Given a paid cluster comes with fixed IP addresses, an A record is a good option.

See Using the Ingress controller with a custom domain for more information.

with HTTP

  1. Create an Ingress file ingress-customdomain-http.yml pointing to your domain:
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-for-customdomain-http
    spec:
      rules:
      - host: <my-custom-domain.com>
        http:
          paths:
          - path: /
            backend:
              serviceName: <service-name>
              servicePort: 9080
    
    {: pre}
  2. Deploy the Ingress
    kubectl apply -f ingress-customdomain-http.yml
    {: pre}
  3. Access your application at http://<customdomain>/<nameofproject>

with HTTPS

If you were to try to access your application with HTTPS at this time https://<customdomain>/<nameofproject>, you will likely get a security warning from your web browser telling you the connection is not private. You would also get a 404 as the Ingress just configured would not know how to direct HTTPS traffic.

  1. Obtain a trusted SSL certificate for your domain. You'll need the certificate and the key: https://{DomainName}/docs/containers/cs_apps.html#custom_domain_cert You can use Let's Encrypt to generate trusted certificate.
  2. Save the cert and the key in base64 ascii format files.
  3. Create a TLS secret to store the cert and the key:
    kubectl create secret tls my-custom-domain-secret-name --cert=<custom-domain.cert> --key=<custom-domain.key>
    
    {: pre}
  4. Create an Ingress file ingress-customdomain-https.yml pointing to your domain:
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: ingress-customdomain-https
    spec:
      tls:
      - hosts:
        - <my-custom-domain.com>
        secretName: <my-custom-domain-secret-name>
      rules:
      - host: <my-custom-domain.com>
        http:
          paths:
          - path: /
            backend:
              serviceName: <service-name>
              servicePort: 9080
    
    {: pre}
  5. Deploy the Ingress:
    kubectl apply -f ingress-customdomain-https.yml
    
    {: pre}
  6. Access your application at https://<customdomain>/<nameofproject>.

Monitor application health

{: #monitor_application}

  1. To check the health of your application, navigate to clusters to see a list of clusters and click on the cluster you created above.
  2. Click Kubernetes Dashboard to launch the dashboard in a new tab.
  3. Select Nodes on the left pane, click the Name of the nodes and see the Allocation Resources to see the health of your nodes.
  4. To review the application logs from the container, select Pods, pod-name and Logs.
  5. To ssh into the container, identify your pod name from the previous step and run
    kubectl exec -it <pod-name> -- bash
    {: pre}

Scale Kubernetes pods

{: #scale_cluster}

As load increases on your application, you can manually increase the number of pod replicas in your deployment. Replicas are managed by a ReplicaSet. To scale the application to two replicas, run the following command:

kubectl scale deployment <nameofproject>-deployment --replicas=2

{: pre}

After a shortwhile, you will see two pods for your application in the Kubernetes dashboard (or with kubectl get pods). The Ingress controller in the cluster will handles the load balancing between the two replicas. Horizontal scaling can also be made automatic.

Refer to Kubernetes documentation for manual and automatic scaling:

Remove resources

  • Delete the cluster or only delete the Kubernetes artifacts created for the application if you plan to reuse the cluster.

Related content