Updated on 29.2.2024

How to deploy dockerized apps to Kubernetes on CentOS 8

Deploying dockerized apps to Kubernetes on CentOS 8

Kubernetes is a popular container orchestration system that lets you automate application deployment, scaling and management tasks via simple command line calls. This guide describes how to build and deploy a simple dockerized web app to a Kubernetes cluster on CentOS 8.

We’ve launched the UpCloud Managed Kubernetes, a fully managed container orchestration service with all the benefits of a self-maintained system but without any of the headaches! See how quick and easy it is to get started by following our dedicated tutorial.

This guide is divided into three main parts:

1. Testing out containers
2. Building a simple dockerized app using Dockerfile
3. Deploying the app to Kubernetes

If you do not yet have a running Kubernetes cluster, have a look at our earlier tutorial on how to install Kubernetes on CentOS 8.

Testing out containers

Let’s start by running a simple docker app to test the container platform.

1. Run hello-world app with the following command:

docker run hello-world

You should see the app print “Hello from Docker!” to your terminal towards the end of the output.

Running a known container pulls the required image from a public registry and saves it on your docker server.

2. Check the list of docker images

docker images

After running the hello-world app once, it should show up on the images list.

REPOSITORY    TAG      IMAGE ID       CREATED         SIZE
hello-world   latest   fce289e99eb9   15 months ago   1.84kB

Now let’s try a more advanced docker app

1. Run the Ubuntu docker app in interactive mode.

docker run -it ubuntu bash

On success, you’ll be brought directly to Ubuntu prompt.

2. Test the internet connection from inside docker app by running a command that requires network access.

On Ubuntu’s terminal prompt, run the following to check it has an internet connection.

apt update

On success, you should see something like the below.

Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
...
Get:17 http://archive.ubuntu.com/ubuntu bionic-backports/main amd64 Packages [2496 B]
Get:18 http://archive.ubuntu.com/ubuntu bionic-backports/universe amd64 Packages [4247 B] Fetched 17.7 MB in 5s (3439 kB/s)

Then stop the Ubuntu container with the following command.

exit

In case you cannot access the internet, you might see something similar to the error underneath.

Err:1 http://security.ubuntu.com/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com' Err:2 http://archive.ubuntu.com/ubuntu bionic InRelease Temporary failure resolving 'archive.ubuntu.com' ...

To fix this, make sure IP masquerade is enabled at the firewall and then try again.

firewall-cmd --add-masquerade --permanent
firewall-cmd --reload

OK, we’ve completed the first part, now let us move on to the next step.

Building a simple dockerized app using Dockerfile

Dockerizing apps is a great way of creating consistent and reliable environments for many tasks regardless of the underlying operating system.

For this example, we are going to make a simple Golang web server that takes input via the server URL and prints out a hello message.

1. Start by creating a new directory named “goserver”

mkdir goserver

2. Create a file named “main.go” in the goserver directory

vi goserver/main.go

Enter the following code, then save the file.

package main
import ( 
   "fmt"
   "net/http"
)
func main() {
   http.HandleFunc("/", HelloServer)
   http.ListenAndServe(":8080", nil)
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintf(w, "Hello, %s!n", r.URL.Path[1:])
}

3. Create another new file named “Dockerfile” with the following command.

vi Dockerfile

Then add the following content to that file, save and exit the text editor.

FROM golang:alpine as builder
WORKDIR /build
COPY /goserver .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main .
FROM scratch
COPY --from=builder /build/main /app/
WORKDIR /app
ENV PORT=8080
CMD ["./main"]

4. Next, build a docker image based on our goserver.

docker build -f Dockerfile -t goserver .

5. Additionally, you may wish to clean unused images from the build process.

docker system prune -f

6. Then check that your web app was added to the images list.

docker images

You should see a line such as in the example below.

REPOSITORY   TAG      IMAGE ID       CREATED          SIZE
goserver    latest   6c0fb70f56fe   55 seconds ago   7.41MB

7. Afterwards, test run the web app.

docker run -d -p 8090:8080 --name goserver goserver

8. You can verify that the deployment was successful by checking the running images.

docker ps -f name=goserver

You should see the “goserver” container running with the status “Up”.

CONTAINER ID   IMAGE       COMMAND    CREATED          STATUS          PORTS                    NAMES
a16ebdf117b9   goserver   "./main"   54 seconds ago   Up 53 seconds   0.0.0.0:8090->8080/tcp   goserver

Your web app is now reachable both locally and over the internet.

9. Call it on the command line, for example by using curl with the command below.

curl http://localhost:8090/Joe

You should have curl available but if not, install curl using sudo dnf install curl

You can also open the page in your web browser. Replace the public-ip-address with the IP of your Master node.

http://public-ip-address:8090/Joe

You should see the following response.

Hello, Joe!

12. Once done, stop the web server and remove the image.

docker stop goserver && docker rm goserver

Congratulations, you should now have an idea of what’s included in making simple dockerized apps.

Deploying a dockerized app to Kubernetes

We’ve now tested out the container platform and built our own dockerized web app, so the last thing to do is to deploy it on our Kubernetes cluster.

This part is referring to the Kubernetes configuration installed in our previous tutorial.

1. Create the following configuration file on the master node. Replace the <master_private_IP> with the private IP address of your master node.

cat > /etc/docker/daemon.json <<EOF
{
   "log-driver": "json-file",
   "log-opts": {
      "max-size": "100m"
   },
   "storage-driver": "overlay2",
   "storage-opts": [
      "overlay2.override_kernel_check=true"
   ],
   "insecure-registries": [ "<master_private_IP>:5000" ]
}
EOF

2. Add the exception for the registry also on all worker nodes. Again, replace the <master_private_IP> with the private IP address of your master node.

cat > /etc/docker/daemon.json <<EOF
{
   "insecure-registries": [ "<master_private_IP>:5000" ]
}
EOF

Then restart Docker on all nodes.

systemctl restart docker

Continue with the rest of the steps on the master node only.

We are going to be using a private registry container for storing and distributing our dockerized app in our cluster.

3. Get the latest version of the docker registry.

docker pull registry:2

4. Run the docker registry on port 5000 using the master node’s private IP address. Replace the <master_private_IP> with the correct address.

docker run -dit --restart=always -p <master_private_IP>:5000:5000 --name registry -e REGISTRY_STORAGE_DELETE_ENABLED=true registry:2

5. Next, create a deployment artefact for our “goserver” app.

Please be aware that indentation matters. This artefact is using two spaces for indentation.

vi deployment.yaml

Enter the following content and again replace the <master_private_IP> with the correct address.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goserver
spec:
  selector:
    matchLabels:
      app: goserver
  replicas: 2
  revisionHistoryLimit: 0
  progressDeadlineSeconds: 30
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 2
  template:
    metadata:
      labels:
        app: goserver
    spec:
      containers:
      - name: goserver
        image: <master_private_IP>:5000/goserver:v1
        ports:
        - hostPort: 8090
          containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: goserver
  name: goserver
spec:
  selector:
    app: goserver
  ports:
  - protocol: TCP
    port: 8090
    targetPort: 8080
  type: ClusterIP

6. Tag the docker app to add the private registry address and port. As before, replace the <master_private_IP> with the private IP address of your master node.

docker tag goserver:latest <master_private_IP>:5000/goserver:v1

7. Then check to make sure the tagged app was created.

docker images

It should show up on the list.

8. Push the tagged app to the private registry so it can be pulled by Kubernetes deployment. Again, replace the <master_private_IP> with the private IP address of your master node.

docker push <master_private_IP>:5000/goserver:v1

9. Check that the tagged app was successfully pushed to the registry by querying the registry. Replace the <master_private_IP> with the private IP address of your master node.

curl -s -X GET http://<master_private_IP>:5000/v2/goserver/tags/list
{"name":"goserver","tags":["v1"]}

Now that we have set up our private repository and pushed the docker image to it, it can be used to deploy the app onto our Kubernetes cluster.

10. Deploy our goserver using the command below.

kubectl apply -f deployment.yaml

11. Check that the deployment rollout succeeded.

kubectl rollout status deployment/goserver

12. You can also check that the pods are up and running.

kubectl get pods

13. You should now be able to access the web server on both master and worker nodes.

curl http://localhost:8090/Joe

Or open browser to http://<public-IP-address>:8090/Joe

Replace the <public-IP-address> with either the public IP address of your master or worker node.

You should see the familiar greeting.

Hello, Joe!

14. When you wish to delete the test app, revert the deployment with the following command.

kubectl delete -f deployment.yaml

Done!

All done!

When you need to update “goserver” codes, you need to dockerized again. Then you also need to push it to the registry with different tags (e.g. v2).

That’s all folks, happy dockerizing!

Yuwono Mujahidin

  1. I am new to kubernetes.
    I wanted to know that if we are just doing an shell/bash echo “Hello World ” in a dockerfile , can we get the result on the browser at a certain port in kubernetes.
    Do we need to have an existing application like nodejs/service like httpd always and then build the dockerfile. Then the app can be taken to k8s and be hosted on a web server port by k8s.

  2. Janne Ruostemaa

    Hi Akash, thanks for the question. The example of deploying a dockerized app can help adapt already existing containers for Kubernetes but it’s not necessary for creating new. If you are looking for a simple Hello world example, check out this guide from Kubernetes.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top