Containerizing an application means packaging it and all its dependencies into a single file. You can achieve this using a tool like Docker. The process of containerization involves creating a Dockerfile; which when built becomes a Docker image. Once you run the Docker image, it becomes a container.
An orchestration tool such as Kubernetes handles the coordination of your containers, providing a platform for managing, deploying, and scaling them. Kubernetes also offers mechanisms for securing containers, monitoring their performance, and managing updates.
Kubernetes and Docker are both popular DevOps tools that complement each other in the modern deployment cycle. Kubernetes provides orchestration and Docker provides the underlying infrastructure for containerized applications. Together, they provide a powerful platform for deploying and managing containerized applications.
The goal of this tutorial is to containerize a simple Hello World application and ship it to a Kubernetes cluster using Minikube. At the end of this tutorial, you will have deployed an application locally and understood how it works.
Prerequisites
To utilize this tutorial, you need the following:
A Kubernetes cluster set up and configured. This tutorial uses a local Kubernetes cluster via Minikube. Check out this article to learn how to set up Minikube.
Docker installed on your machine. Follow the steps in the Docker installation documentation to install it.
Fundamental understanding of Docker and Kubernetes. You can take a crash course here.
Step 1 - Clone the Application
Clone the Hello World application from Google Cloud's official GitHub samples repository.
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
After cloning, navigate to the application folder:
cd kubernetes-engine-samples/quickstarts/hello-app
Step 2 - Dockerize the Application
Dockerizing an application is the process of containerizing (packaging) it using Docker.
This step explains how to write a Dockerfile, build a Docker image, and run it as a Docker container.
Write the Dockerfile
Although this project already contains a Dockerfile, it is important to understand what each step does so you can modify it to suit your needs.
To see the Dockerfile, run the following command:
vi Dockerfile
You should see the following content:
# Copyright 2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START gke_quickstarts_hello_app_dockerfile] FROM golang:1.21.0 as builder WORKDIR /app RUN go mod init hello-app COPY *.go ./ RUN CGO_ENABLED=0 GOOS=linux go build -o /hello-app FROM gcr.io/distroless/base-debian11 WORKDIR / COPY --from=builder /hello-app /hello-app ENV PORT 8080 USER nonroot:nonroot CMD ["/hello-app"] # [END gke_quickstarts_hello_app_dockerfile]
Here's a breakdown of the Dockerfile:
Base image:
FROM golang:1.21.0 as builder
This line specifies the base image for the first stage of the build process. It uses the official
golang
image version1.21.0
as a starting point for building the application.Working directory:
WORKDIR /app
This sets the working directory inside the container to
/app
.Initialize Go module:
RUN go mod init hello-app
This initializes a Go module named
hello-app
. Go modules are a dependency management system introduced in Go 1.11.Copy source code:
COPY *.go ./
This copies all
.go
files from the host machine's current directory into the/app
directory inside the container.Build application:
RUN CGO_ENABLED=0 GOOS=linux go build -o /hello-app
This builds the Go application located in the
/app
directory inside the container.It compiles the application for Linux (
GOOS=linux
) and disables CGO (CGO_ENABLED=0
) to ensure that the resulting binary is statically linked and doesn't depend on external libraries.The
-o
flag specifies the output binary's location, which is/hello-app
in this case.Second stage - minimal base image:
FROM gcr.io/distroless/base-debian11
This command starts the second stage of the Dockerfile using the minimal base image
gcr.io/distroless/base-debian11
.This image provides only the minimal dependencies required to run the application, making it smaller and potentially more secure than a full-fledged Linux distribution.
Working Directory:
WORKDIR /
This sets the working directory inside the container to the root directory.
Copy Binary from First Stage:
COPY --from=builder /hello-app /hello-app
This copies the compiled binary
hello-app
from the builder stage into the root directory of the final image.Set Environment Variable:
ENV PORT 8080
This sets an environment variable named
PORT
to8080
. This environment variable likely tells the application which port to listen on.Set User:
USER nonroot:nonroot
This sets the user that the container will run as. It's common practice to run containers with a non-root user for security reasons.
Command to Run Application:
CMD ["/hello-app"]
This specifies the command to run when the container starts. In this case, it runs the
hello-app
binary, which was copied into the container earlier.To learn more about Dockerfiles, see the Dockerfile reference.
Build the Docker image
To build the image from the Dockerfile, run the command below:
docker build -t hello-app .
Run the Docker container
When you run a Docker image, it becomes a container.
To run the Docker image, execute the command below:
docker run -d -p 8080:8080 hello-app
You can view all the running containers on your machine by running the command below:
docker ps
View this application on your browser using
http://localhost:8080
or via thecurl
command.You will get the following output:
**Figure 1:** Docker container output
Step 3 - Push the Docker Image to Docker Hub
Docker images need to be publicly accessible before they can be pulled by Kubernetes.
For this reason, you will push the image to a public registry called Docker hub.
To push the Docker image, follow these steps:
Tag the Docker image
A tag identifies the build version you are pushing to Docker Hub, which helps you deploy a new image or retrieve an old one.
Tag the Docker image using the command below:
docker tag hello-app <DOCKER-HUB-USERNAME>/hello-app:1
Replace with the username of your Docker hub account.
Login to Docker hub
Authentication with Docker hub is required before you can push an image to the registry.
Use the command below to authenticate:
docker login -u "USERNAME" -p "PASSWORD" docker.io
Immediately you get the
Login Succeeded
output, you are ready to push your image.Push your image to Docker hub
Execute the following command to push your image to Docker hub:
docker push <DOCKER-HUB-USERNAME>/hello-app:1
You will get an output similar to this:
The push refers to repository [docker.io/<DOCKER-HUB-USERNAME>/hello-app] 30a020c37916: Pushed c8beeff22ce7: Pushed 714f56238fb5: Pushed f33e343848bd: Pushed 4cb10dd2545b: Pushed d2d7ec0f6756: Pushed 1a73b54f556b: Pushed e624a5370eca: Pushed d52f02c6501c: Pushed ff5700ec5418: Pushed accc3e6808c0: Pushed 6fbdf253bbc2: Pushed 54ad2ec71039: Pushed 1: digest: sha256:8952fed2b9099b11f7877aaf6dca796f642952e995365e5180ef2ecb788898ae size: 3033
Step 4 - Deploying to Kubernetes
To deploy the Hello World application, you need Kubernetes manifest files. This project includes pre-written deployment and service manifest files.
Use the commands below to view them:
cd manifests
ls
To deploy the application to Kubernetes, follow the steps below:
Create a deployment file
View the deployment file using the command below:
vi helloweb-deployment.yaml
This is the content of the file:
# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START gke_manifests_helloweb_deployment_deployment_helloweb] # [START container_helloapp_deployment] apiVersion: apps/v1 kind: Deployment metadata: name: helloweb labels: app: hello spec: selector: matchLabels: app: hello tier: web template: metadata: labels: app: hello tier: web spec: containers: - name: hello-app image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 ports: - containerPort: 8080 resources: requests: cpu: 200m # [END container_helloapp_deployment] # [END gke_manifests_helloweb_deployment_deployment_helloweb] ---
Here's a brief breakdown of the current deployment file:
apiVersion:
apiVersion: apps/v1
This specifies the API version of the Kubernetes object being created. In this case, it's using the
apps/v1
API version, which is commonly used for Deployments.kind:
kind: Deployment
This indicates the Kubernetes resource type being defined, which is a Deployment.
metadata:
metadata: name: helloweb labels: app: hello
This section defines metadata for the Deployment, including the name (
helloweb
) and labels (app: hello
).spec:
spec: selector: matchLabels: app: hello tier: web
This specifies the criteria used to select Pods to manage. In this case, it selects Pods with labels
app: hello
andtier: web
.template:
template: metadata: labels: app: hello tier: web spec: containers: - name: hello-app image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 ports: - containerPort: 8080 resources: requests: cpu: 200m
This section defines the Pod template used by the Deployment. It specifies the labels to apply to the Pods (
app: hello
andtier: web
) and the container(s) to run within each Pod.containers: This subsection defines the containers to run within the Pods. In this case, there is one container named
hello-app
.name: The name of the container.
image: The Docker image to use for the container. It pulls the image
us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
.ports: Specifies which ports the container exposes. Here, it exposes port
8080
.resources: Specifies the resource requirements for the container. Here, it requests 200 milliCPU (mCPU) for the container's CPU resource.
To know more about Kubernetes deployment files, see here.
Edit this file to use the Docker image created above. Once you do, you should have the following output:
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# [START gke_manifests_helloweb_deployment_deployment_helloweb]
# [START container_helloapp_deployment]
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-app-deployment
labels:
app: hello-app
spec:
replicas: 1
selector:
matchLabels:
app: hello-app
tier: web
template:
metadata:
labels:
app: hello-app
tier: web
spec:
containers:
- name: hello-app
image: <DOCKER-HUB-USERNAME>/hello-app:1
ports:
- containerPort: 8080
resources:
requests:
cpu: 200m
# [END container_helloapp_deployment]
# [END gke_manifests_helloweb_deployment_deployment_helloweb]
---
Take note of the line below:
image: <DOCKER-HUB-USERNAME>/hello-app:1
Make sure to replace <DOCKER-HUB-USERNAME>
with your Docker hub username.
Create a Load Balancer service file
A load balancer service is important because it exposes the application to the internet.
Access the pre-written service file by running the command below:
vi helloweb-service-load-balancer.yaml
This is the content of the file:
# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START gke_manifests_helloweb_service_load_balancer_service_helloweb] # [START container_helloapp_service_load_balancer] apiVersion: v1 kind: Service metadata: name: helloweb labels: app: hello tier: web spec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: hello tier: web # [END container_helloapp_service_load_balancer] # [END gke_manifests_helloweb_service_load_balancer_service_helloweb] ---
This service file defines a load balancer service named
helloweb
for exposing thehello-app
application to external traffic.The goal of this file is to ensure that the
hello-app
application is accessible from outside the Kubernetes cluster by routing traffic from port 80 to port 8080 on Pods labeled withapp: hello
andtier: web
.This service allows external clients to access the application via a public IP address or DNS name assigned by a cloud provider's load balancer.
Change the app name from
hello
tohello-app
to match the deployment file.Once you do, you should have the following output:
# Copyright 2021 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # [START gke_manifests_helloweb_service_load_balancer_service_helloweb] # [START container_helloapp_service_load_balancer] apiVersion: v1 kind: Service metadata: name: hello-app-service labels: app: hello-app tier: web spec: type: LoadBalancer ports: - port: 80 targetPort: 8080 selector: app: hello-app tier: web # [END container_helloapp_service_load_balancer] # [END gke_manifests_helloweb_service_load_balancer_service_helloweb] ---
Apply the deployment and service files
Applying the deployment and service files will create the resources in your Kubernetes cluster.
Using
kubectl
, run the commands below:kubectl apply -f helloweb-deployment.yaml kubectl apply -f helloweb-service-load-balancer.yaml
You should get an output similar to this:
deployment.apps/hello-app-deployment created service/hello-app-service created
Accessing the application
In order to access the application over the internet, you will need to use kubectl port-forwarding. This will allow you to create a stream between your local port and the port of your Kubernetes pod.
Port-forward your load balancer service using the command below:
kubectl port-forward service/hello-app-service 8000:80
View the application on your browser using
http://localhost:8000
or via thecurl
command.You should get the following output:
**Figure 2:** Kubernetes application output
With this, you have successfully deployed a containerized application to a Kubernetes cluster.
Make sure to clean up your resources by running the commands below:
kubectl delete -f helloweb-deployment.yaml
kubectl delete -f helloweb-service-load-balancer.yaml
Conclusion
This tutorial showed you how to deploy a containerized app to a Kubernetes cluster. You went through the process of containerizing the application and deploying it.
This tutorial mimics what happens when you use cloud managed Kubernetes services such as GKE, EKS, and AKS. Please feel free to use these services and note the differences in the deployment process.