Container-based software development is growing. Since it's easy to replicate the environment, developers generally create applications on their desktop, and debug and test them locally. Later they build and deploy the application to a Kubernetes cluster.
In this tutorial, I show you how two ways to deploy an application to a Kubernetes cluster on IBM Cloud:
- Using a
kubectl
CLI without a DevOps pipeline - Using a Tekton pipeline (which is Kubernetes-style continuous integration/continuous delivery pipeline)
To complete this tutorial, you need to:
-
Create an IBM Cloud account.
-
Get an instance of Kubernetes Service on IBM Cloud, which should take approximately 20 minutes.
-
Access a Kubernetes Cluster through the
kubectl
CLI. To access the instructions, go to IBM Cloud dashboard > [your cluster] > Access. -
Create a namespace on IBM Cloud container registry. To do so, go to your IBM Cloud dashboard and click Navigation > Kubernetes > Registry > Namespaces.
-
Configure the Git CLI. Clone the repository to your workstation using the following command:
git clone https://github.com/IBM/deploy-app-using-tekton-on-kubernetes.git
After your prerequisites are configured, this tutorial takes about 40 minutes.
You perform the following steps to build and deploy an application on a Kubernetes cluster.
- Write a Dockerfile for your application and build the container image using Dockerfile.
- Upload the built container image to the accessible container registry.
- Create a Kubernetes deployment using the container image and deploy the application to an IBM Cloud Kubernetes Service cluster using configuration (yaml) files.
For this tutorial, we have taken a simple "Hello world!" Node.js application to deploy on Kubernetes as shown.
const app = require('express')()
app.get('/', (req, res) => {
res.send("Hello from Appsody!");
});
var port = 3300;
var server = app.listen(port, function () {
console.log("Server listening on " + port);
})
module.exports.app = app;
The dockerfile Dockerfile
and the deployment configuration deploy.yaml
is available in the GitHub repository that you cloned earlier. The steps explained in this section help you to deploy your application to cluster using CLIs.
As a first step, you need to set the correct deploy target for the container image to upload to the accessible container registry. Depending on the region you created your cluster in, your image URL will be in the following format:
<REGION_ABBREVIATION>.icr.io/<YOUR_NAMESPACE>/<YOUR_IMAGE_NAME>:<VERSION>
The following command tells you the Registry API endpoint for your cluster. You can get region abbreviation from the output.
ibmcloud cr api
To get namespace use the following command.
ibmcloud cr namespaces
For example, deploy target for US-South region will be:
us.icr.io/test_namespace/builtApp:1.0
Run the following commands to deploy your application on a Kubernetes cluster.
cd ~/deploy-app-using-tekton-on-kubernetes/src
# Build and push it to IBM Cloud Container registry. Following command takes care of build and push to container registry and eliminates the overhead to run docker commands individually.
ibmcloud cr build -t us.icr.io/test_namespace/builtApp:1.0 .
# Verify whether the image is uploaded to the container registry
ibmcloud cr images
# Update deploy target in deploy.yaml
sed -i '' s#IMAGE#us.icr.io/test_namespace/builtApp:1.0# deploy.yaml
# Run deploy configuration
kubectl create -f deploy.yaml
# Verify output - pod and service should be up and running
kubectl get pods
kubectl get service
After successful deployment, your application is accessible at:
http://<public-ip-of-kubernetes-cluster>:32426/
where you can retrieve the public IP of a Kubernetes cluster from your IBM Cloud dashboard and the port 32426 is defined as nodePort
in deploy.yaml.
The steps above showed you got to deploy onto a Kubernetes cluster using CLIs. If you change your application after deployment, you need to rerun the steps again.
In order to build, test, and deploy application faster and more reliably, you need to automate this entire workflow. Following a continuous integration and delivery (CI/CD) methodology reduces the overhead of development and manual deployment processes, which can save you significant time and effort.
The next section of this tutorial explains the build and deploy approach using Tekton Pipelines.
Tekton is a powerful and flexible Kubernetes-native open source framework for creating CI/CD systems. It allows you to build, test, and deploy across multiple cloud providers or on-premises systems by abstracting away the underlying implementation details.
before I show you how to use Tekton Pipelines, here's a high-level overview of the concepts.
The Tekton Pipeline project extends the Kubernetes API by five additional custom resource definitions (CRDs) to define pipelines:
- A task is an individual job and defines a set of build steps such as compiling code, running tests, and building and deploying images.
- A Taskrun runs the task you defined. With taskrun, it's possible to execute a single task, which binds the inputs and outputs of the task.
- Pipeline describes a list of tasks that compose a pipeline.
- Pipelinerun defines the execution of a pipeline. It references the Pipeline to run and which PipelineResource(s) to use as input and output.
- The Pipelineresource defines an object that is an input (such as a Git repository) or an output (such as a Docker image) of the pipeline.
To automate the application’s build and deploy workflow using Tekton Pipelines, follow these steps:
As a very first step, add the Tekton Pipelines to your Kubernetes cluster using following command.
kubectl apply --filename https://storage.googleapis.com/tekton-releases/latest/release.yaml
The installation creates two pods which you can check using the following command. Wait until the pods are in running state.
kubectl get pods --namespace tekton-pipelines
For more information on this, refer to the Tekton documentation. After completing these steps, your Kubernetes cluster is ready to run Tekton Pipelines. Let’s start by creating the definition of custom resources.
In the example taken for this tutorial, the source code of the application, Dockerfile and deployment configuration is available in the GitHub repository that you cloned earlier.
To create the input pipeline resource to access the Git repository, do the following:
In the git.yaml
file, define the PipelineResource for the git repository:
- Specify the resource
type
as git. - Provide the git repository URL as
url
. revision
as the name of the branch of the git repository to be used.
The complete YAML file is available at ~/tekton-pipeline/resources/git.yaml
. Apply the file to the cluster as shown.
cd ~/tekton-pipeline
kubectl apply -f resources/git.yaml
A task defines the steps of the pipeline. To deploy an application to a cluster using source code in the Git repository, we define two tasks — build-image-from-source
and deploy-to-cluster
. In task definition, the parameters used as args are referred as $(inputs.params.<var_name>)
.
Define Build-image-from-source
This task includes two steps as follows:
-
list-src
step lists the source code from the cloned repository. It is being done just to verify whether source code is cloned properly. -
build-and-push
step builds the container image using Dockerfile and pushes the built image to the container registry. In this exampleKaniko
is used to build and push the image. There are other options also available for this purpose like buildah, podman etc. Kaniko uses the Dockerfile name, its location and destination to upload the container image as arguments.
All required parameters are passed through params. Apply the file to the cluster using following command.
kubectl apply -f task/build-src-code.yaml
Define Deploy-to-cluster
Now let us deploy application in a pod using the built container image, and make it available as a service to access from anywhere. This task uses the deployment configuration located as ~/src/deploy.yaml
. This task includes two steps:
-
update-yaml
step updates the container image url in place ofIMAGE
in deploy.yaml. -
deploy-app
step deploys the application in Kubernetes pod and expose it as a service using~/src/deploy.yaml
. This step useskubectl
to create deployment configuration on Kubernetes cluster.
All required parameters are passed through params.
Apply the file to the cluster as:
kubectl apply -f task/deploy-to-cluster.yaml
A pipeline lists the tasks to be executed. It provides the input, output resources, and input parameters required by each task. If there is any dependency between the tasks, that is also addressed.
In the tekton-pipeline/resources/pipeline.yaml
:
- Pipeline uses the above mentioned tasks
build-image-from-source
anddeploy-to-cluster
. - The
runAfter
key is used here because we need to execute the tasks one after the another. - PipelineResource (git repository) is provided through the
resources
key.
All required parameters are passed through params. Parameters value are defined in pipeline as $(params.imageUrl)
which is different than the args in task definition. Apply this configuration as:
kubectl apply -f pipeline/pipeline.yaml
To execute the pipeline, you need a PipelineRun resource definition. All required parameters are passed from PipelineRun. PipelineRun triggers the pipeline, and the pipeline, in turn, creates TaskRuns and so on. In a similar manner, all parameters get substituted down to the tasks.
If a parameter is not defined in PipelineRun, then the default value gets picked up from the params
under spec
from the resource definition itself. For example, pathToDockerfile
param is used in task build-image-from-source
, but its value is not provided in pipeline-run.yaml
. Because of this, its default value defined in ~/tekton-pipeline/build-src-code.yaml
is used during the task execution.
In the PipelineRun definition, tekton-pipeline/pipeline/pipeline-run.yaml
:
- References the Pipeline
application-pipeline
created throughpipeline.yaml
. - References the PipelineResource
git
to use as input. - Provides the value of parameters under
params
which are required during the execution of pipeline and the tasks. - Specifies a service account.
Note that through the pipeline, you can push images to the registry and deploy it to a cluster. So, you need to ensure that it has the sufficient privileges to access the container registry and the cluster. The credentials for the registry are provided by a ServiceAccount. So, you need to define a service account before executing Pipelinerun.
Note: Do not apply the PipelineRun file yet because you still need to define the service account for it.
To access the protected resources, set up a service account which uses secrets to create or modify Kubernetes resources. IBM Cloud Kubernetes Service is configured to use IBM Cloud Identity and Access Management (IAM) roles. These roles determine the actions that users can perform on IBM Cloud Kubernetes.
Generate an API key
To generate an API key using IBM Cloud Dashboard, follow the instructions in the IBM Cloud documentation. You can also use the following CLI command to create API key.
ibmcloud iam api-key-create MyKey -d "this is my API key" --file key_file.json
cat key_file.json | grep apikey
Copy the apikey
. You will use it in the next step.
Create secrets
To create a secret, use the following code. is the one that you created and is the registry API endpoint for your cluster; for example, us.icr.io.
kubectl create secret generic ibm-cr-secret --type="kubernetes.io/basic-auth" --from-literal=username=iamapikey --from-literal=password=<APIKEY>
kubectl annotate secret ibm-cr-secret tekton.dev/docker-0=<REGISTRY>
It creates a secret named as ibm-cr-secret
which will be used in the configuration file for the service account.
In the configuration file, tekton-pipeline/pipeline/service-account.yaml
:
- The
ServiceAccount
resource uses the secret generated aboveibm-cr-secret
. - As per the definition of a secret resource, the newly built secret is populated with an API token for the service account.
- The next step is to define roles. A Role can only be used to grant access to resources within a single namespace. Include appropriate resources and apiGroups in rules without which it fails with access issues.
- A role binding grants the permissions defined in a role to a user or set of users. It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted.
Apply this configuration as:
kubectl apply -f pipeline/service-account.yaml
Before executing Pipelinerun, modify imageUrl
and imageTag
in tekton-pipeline/pipeline/pipeline-run.yaml
. Refer to the Setup Deploy Target
section above to decide on an image URL and tag. If imageURL is us.icr.io/test_namespace/builtApp and image tag is 1.0, then update configuration file as:
sed -i '' s#IMAGE_URL#us.icr.io/test_namespace/builtApp# pipeline/pipeline-run.yaml
sed -i '' s#IMAGE_TAG#1.0# pipeline/pipeline-run.yaml
Now, create the pipelinerun configuration.
kubectl create -f pipeline/pipeline-run.yaml
It will create pipeline with a below message on terminal.
pipelinerun.tekton.dev/application-pipeline-run created
To check the status of the pipeline created:
kubectl describe pipelinerun application-pipeline-run
You may need to rerun this command based on the status. It shows the interim status as:
Status: Conditions: Last Transition Time: 2019-11-11T06:51:06Z Message: Not all Tasks in the Pipeline have finished executing Reason: Running Status: Unknown Type: Succeeded ... ... Events:
Once the execution of your pipeline is complete, you should see the following as an output of the describe
command:
Status: Completion Time: 2019-11-07T09:41:59Z Conditions: Last Transition Time: 2019-11-07T09:41:59Z Message: All Tasks have completed executing Reason: Succeeded Status: True Type: Succeeded .. .. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Succeeded 0s pipeline-controller All Tasks have completed executing
In case of failure, it shows which task has failed. It also gives you the additional details to check logs. To know more details about a resource, for instance, "pipeline", use the kubectl describe
command to get information.
kubectl describe <resource> <resource-name>
To verify whether the pod and service is running as expected, check the output of the following commands.
kubectl get pods # Output should be something like this NAME READY STATUS RESTARTS AGE app-59dff7b655-7ggbt 1/1 Running 0 81s application-pipeline-run-build-image-from-source-2m62g-pod-f4eb96 0/3 Completed 0 119s application-pipeline-run-deploy-application-kg2jm-pod-89f884 0/3 Completed 0 89s kubectl get service # Output NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE app NodePort xxx.xx.xx.xxx 3300:32426/TCP 4m51s
After successful execution of pipelinerun
, the application is accessible at:
http://<public-ip-of-kubernetes-cluster>:32426/
where you can retrieve the public IP of your Kubernetes cluster from your IBM Cloud dashboard, and the port 32426 is defined as nodePort in deploy.yaml
.
In this way, you deploy your application using Tekton Pipeline. This tutorial covers the basics of Tekton Pipeline to get you started on building your own pipelines. There are more features available like webhooks, web-based dashboards. Do try it out with IBM Cloud Kubernetes Service.
Tekton is one of the tools available in the open source project Kabanero. Kabanero brings together key technologies into a microservices-based framework for building modern cloud-native applications. Kabanero has Codewind which helps to build cloud-native applications, Appsody which helps to build and deploy cloud-native applications and Tekton which is Kubernetes style CI/CD pipeline. Each project has its own open source community and independent releases. The Kabanero open source project is included within IBM Cloud Pak for Applications as Kabanero Enterprise. The Cloud Pak for Applications provides a faster, more secure way to move your business applications to cloud, in container enabled environment. Cloud Pak for Applications is built and supported on Red Hat OpenShift. Explore and try out with the help of this developer guide.