Hướng dẫn deploy application to kubernetes từ gitlabci
In this blog post we’ll go through the steps of creating an automated deployment pipeline for Kubernetes using GitLab. In the end we’ll have a simple Go application running that very excitingly returns “Hello, World!”. Show PrerequisitesBefore we can begin our quest for automation, we’ll need to set up some tools. Many alternatives of course exist to the tools that I pick. Feel free to use any other option, but make sure to make any necessary changes if you are following along with this post. Let’s begin with setting up a Kubernetes cluster. There are many ways to get one, and it does not really matter how you set one up. I’m personally happy with the eksctl utility which makes it really easy to set up an AWS EKS Cluster. Please note that there is some pricing involved with spinning up this cluster. You pay $0.20 per hour for the Amazon EKS control plane. You’ll also pay $0.0228 per hour for the Check out the documentation on eksctl.io to install and configure the tool. Then you can spin up the Kubernetes cluster with the following command:
This will take around 10 to 15 minutes. Once the cluster is created, you can set up your
0 Check to see if your worker node has properly registered with the following command:
1 Finally we’ll create a
2 service account that we’ll use to deploy to Kubernetes from GitLab. Create a file called
3 with the following contents:
Apply these settings with the following command:
4 This will create a new service account and attach admin permissions to it. Keep in mind that in production environments you’ll definitely want to use a role with only the minimum permissions required. Docker registryNext up we’re going to set up a Docker registry to which we can push the Go “Hello, World!” application that we’ll dockerize. Feel free to use any registry that you’re familiar with. If you don’t have one yet, you can easily create one for free at the Docker Hub. You can also create a private repository if you don’t like sharing your Dockerfile with the whole world. To get a sneak peek of what we’ll build, you can find my reposity in the Docker hub: sanderknape/go-hello-world. Once you have an account, create a repository called
5. GitLabGitLab is free to use. If you don’t have an account yet, you can get one at the . After you have created an account, create a new repository and call it
6. It’s up to you if you set it up publicly or privately. My project is public so feel free to take a look. To be able to push code from your laptop to the repository, you need to set up an SSH key. Check out the GitLab documentation to learn how to do this. Specifying configurationAs we’re going to connect to both the Docker Hub and to Kubernetes, we need to specify some authentication configuration. When you’re in your repository, use the left menu to open up the
7. We’re going to add the following configuration:
Be sure to enable the
7 flag for at least the
0, the
9 and the
3. Click
1. Building our Docker imageIt’s finally time to get to the good stuff. All code that we’re going to write can be found in my GitLab repository. We’ll set up this repository step by step. First, create a new directory and run
2. Follow the instructions in your GitLab repository to “sync” your local repository with it. Let’s create a dockerized Go app first that we’ll push to that repo. The Go application is a super simple webserver that just returns “Hello, World!”. Create a file called
3 and add the following content:
If you have Go installed you can run the webserver as follows (if you don’t have it installed, you can also wait with running it until we have dockerized the app in a minute):
4 You can open up your browser, navigate to
5 and you should see the fine words “Hello, World!”. Next up, let’s create the Dockerfile. In the same directory create a new file called
6 and add the following content:
If you are not familiar with multi-stage builds this may look a little confusing. We first build the application in the official Golang Docker image. As this image contains all the tools required to build Go images (and more), this image is a little over 100MB. However, to actually run the application, all we really need is just a bare-bones OS. Therefore, starting at line 6, we build the final Docker image based on the alpine OS. This is only about 6MB in size. We grab the application artifact created earlier from that build, and put it in
7. We then tell Docker to start the container by running our app in the last line. Build this Docker image as follows:
8 Next, be sure that the Go application we tested earlier isn’t still running. It would fail the next command as port 8080 is then already in use. We can now run our application through Docker as follows:
9 Open up your browser again and visit
5. You should again see the famous words. Building Docker in GitLabThe next step is to build this Docker image in GitLab and push it to our Docker registry. Create a new file
1 and add the following content:
As we’re going to build a Docker image inside of another Docker image, we enable the Docker in Docker service. Next we’ll use the predefined variable
2 to tag the image. We do this as we want to know exactly which code from our Git repository this Dockerfile contains. In addition, if we would simply use
3, rollbacks wouldn’t work in Kubernetes as rolling back from
3 to
3 doesn’t make a lot of sense. In the
6 steps we use the previously set environment variables to connect with the Docker hub. We then build and push the Docker image to our repository. Push the three files that we created to your GitLab repository. This will automatically trigger the build job. Through the left navigation, go to
7 and open up your job. You should see a succesful push to Docker Hub. Navigate to Docker hub and you should find the first Docker image! Kubernetes deploymentsWith our Docker image now available to be consumed, it’s time to push it to our Kubernetes cluster. We’re going to create a Kubernetes Deployment. This is a Kubernetes resource that wraps Docker containers and controls their lifecycle. It makes sure to restart the containers if they are stopped and ensures that the right amount of containers is running. It can also perform rolling updates and use health checks to see if the containers are still working. Create a new file called
8 and add the following content:
The configuration also contains rolling updates configuration and health checks (the liveness and readiness probes). Though we won’t really touch these in this blog post, you can change these settings to get a better feeling for how deployments work. Find the
9 and replace it with the tag that you pushed earlier to the Docker Hub. This is only temporary: we’ll replace this later once we create the GitLab pipeline. Assuming you’ve correctly configured your
0 earlier, you are now able to deploy this image to your Kubernetes cluster with the following command:
1 Run a
2 and you should see output similar to the following:
It may be that the status is still in
3, if the image is still being downloaded (luckily only just 5MB!). To ensure our pods our working, let’s set up a proxy to one of the containers. First, ensure that your previous tests with Go and the Docker image are not still running. Opening up
5 should give a connection-refused error. Copy/paste one of the names of the pods and run the following command:
5 Open up your browser again and you should once again see “Hello, World!”. This time coming from your Kubernetes cluster. Deployment through GitLabNext up we’re going to run this deployment through GitLab. First remove the deployment we just created with the following command:
6 Ensure that no pods are running with
2. Now, replace the SHA you added earlier with the string
9 again. This will be replaced with the latest SHA in our GitLab pipeline. Add the following new stage at the end of your
1 file:
We use an existing Docker image that already has
0 installed. We then configure the cluster, user and context with the environment variables we set earlier so that we can connect to the cluster. When setting the cluster we can unfortunately not directly set the
1 as no flag exists for it. There is a GitHub issue open for this. We therefore set the CA data using an additional command. We also perform a
2 to replace the with the short SHA of the Docker image that we just pushed to the Docker registry. This may feel a little dirty/hacky; I’ll share a different way to do this in a future blog post using Helm. (UPDATE: check out my new blog post on improving Kubernetes deployments with Helm). Finally, higher up in the file find the
3 array. Add
4 after
6. Push these changes to your GitLab repository. The new
4 step will have applied the deployment to Kubernetes. Run
2 to see your pods running again. In addition, if you run a
8, you can see the image that is pulled from Docker Hub. You can verify that this is indeed the latest tag that was pushed to the hub. Like before, run
5 on one of the pods to verify that it can succesfully accept connections. And that was it - you now have a fully automated pipeline that deploys from your laptop to a Kubernetes cluster! TeardownRemove the Kubernetes cluster with the following command: `t3.small`0 Keeping the Docker Hub and GitLab up and running won’t cost you anything, though you can of course delete the resources we created. ConclusionIn this blog post we created a fully automated deployment pipeline to Kubernetes using GitLab. While the pipeline doesn’t contain any automated (unit) testing or promotions of the application through different environments, it should give enough of an idea on how to build a pipeline with such features for Kubernetes. Happy deploying! |