[Backend #36] Automatic deploy to Kubernetes with Github Action

[Backend #36] Automatic deploy to Kubernetes with Github Action


[Backend #36] Automatic deploy to Kubernetes with Github Action

In this lecture, we will learn how to use Github Action to automatically deploy a web application to the Kubernetes cluster on AWS EKS.
- Join us on Discord: https://bit.ly/techschooldc
- Get the course on Udemy: https://bit.ly/backendudemy
- Buy us a coffee: https://www.buymeacoffee.com/techschool
- Full series playlist: https://bit.ly/backendmaster
- Github repository: https://github.com/techschool/simplebank
---

In this backend master class, we’re going to learn everything about how to design, develop, and deploy a complete backend system from scratch using PostgreSQL, Golang, and Docker.

TECH SCHOOL - From noob to pro
   / techschoolguru  
At Tech School, we believe that everyone deserves a good and free education. We create high-quality courses and tutorials in Information Technology. If you like the videos, please feel free to share and subscribe to support the channel or buy us a coffee: https://www.buymeacoffee.com/techschool


Content

0.19 -> Hello everyone, and welcome back to the backend master class.
3.35 -> It’s been a long journey!
5.56 -> We have learned a lot about how to design, develop and deploy
8.59 -> A golang backend web application from scratch.
11.2 -> However, until now, we’re still doing the deployment part manually
15.889 -> by running the kubectl command in the terminal.
18.95 -> So, in this last lecture of the course,
21.6 -> I’m gonna show you how to automate it using Github Action.
25.24 -> Alright, let’s start!
27.73 -> As you can see, in the previous lectures,
30.38 -> we have stored all the kubernetes deployment yaml files in the eks folder.
35.469 -> So all we have to do now is to install kubectl in the github action,
39.85 -> then use it to deploy these files to the production cluster.
43.829 -> To do that, let’s open the github deploy workflow file,
47.269 -> First, I’m gonna rename this build job to deploy,
51.359 -> because now we’re not just building the image, but we’re also deploying it.
56.28 -> Then we will search for kubectl action in the github marketplace.
59.409 -> There are several results, but I’m gonna use the Kubectl tool installer from Azure.
66.19 -> So let’s open it,
68.5 -> And copy this code snippet.
70.7 -> OK, now in our deploy.yaml file, let’s add a new step.
75.75 -> I’m gonna name it Install kubectl
79.82 -> And paste in the code snippet that we’ve just copied.
82.74 -> Let’s fix the indentation.
86.34 -> Then we should put the latest version of kubernetes here.
89.74 -> You can use this link to find out the latest stable version.
92.89 -> In my case, it is 1.21.3
95.83 -> Alright, after this step, kubectl will be installed on the github runner machine.
102.67 -> Next step, we will deploy the docker image from ECR to our EKS cluster.
108.8 -> This step should be run at the end of the workflow.
112.86 -> Here I use a pipe because we’re gonna run multiple commands
116.19 -> to deploy different types of resources to the cluster.
119.75 -> First, the aws-auth resource.
123.17 -> For now, we only use it to grant github-ci user access to the cluster,
127.4 -> But later, you can add more users to this file if you want.
131.25 -> So let’s copy its name,
134.45 -> And in the deploy workflow, we’re gonna run
136.74 -> kubectl apply -f eks/aws-auth.yaml to deploy it.
145.27 -> The second thing we must deploy is the deployment resource.
149.61 -> This resource will manage the deployment of our simple-bank API container.
154.93 -> Here you can see that it will download this specific image tag from ECR.
159.59 -> But in fact, what we want is,
161.84 -> Whenever we push new changes to the master branch,
164.9 -> It will build and tag the image as latest version,
168.51 -> And that latest version image should be redeployed to the Kubernetes cluster.
173.18 -> So here we should change the tag to latest.
176.53 -> And because of this change, we must also update the build and push image step.
181.23 -> By now, every image has a different tag, corresponding to the commit ID on the master branch.
187.959 -> We will change it a bit so that the new image will also be tagged as latest,
193.11 -> And then use the all-tags option to push all of the tags to Amazon ECR.
198.79 -> To do that, in the docker build command, let’s add -t latest
205.18 -> And in the docker push command, let’s add -a option.
209.99 -> We should also remove the image tag at the end of the image name.
213.92 -> OK, now we can use the kubectl command to apply the deployment.yaml to production.
219.75 -> Next, we do the same thing to deploy service.yaml to the cluster.
226.02 -> Then the issuer to manage the TLS certificates.
230.24 -> And finally, the ingress to route external traffic to the internal simple-bank API service.
236.9 -> Alright, I think that should be it!
240.099 -> All of our resources have been added to the step in the deploy workflow.
243.98 -> Let’s open the terminal and push these changes to Github.
249.44 -> First I’m gonna create a new branch called ft/ci-deploy
254.81 -> Then add all the changes
258.19 -> Commit it with this message: update github-ci to deploy to amazon EKS.
265.25 -> And finally, push the new branch to GitHub.
269.65 -> Now let’s open this URL to create a pull request to merge it to master.
274.53 -> OK, the PR has been created.
277.35 -> Let’s review it a bit!
279.63 -> We’ve changed the job’s name to deploy,
285.03 -> Added a step to install kubectl.
287.64 -> Rebuild the docker image with the latest tag,
291.94 -> Push the image with all of its tags to Amazon ECR.
295.75 -> And finally, use kubectl command to deploy the image
299.28 -> to the production Kubernetes cluster on Amazon EKS.
302.46 -> There are also some small changes I made in the README file,
306.93 -> but we don’t need to care about them.
309.27 -> However, we should pay attention to the deployment,
313.16 -> As we’re specifying here, it will pull the image with the latest tag from ECR.
318.5 -> But in case there’s already an image with the latest tag on the local machine,
322.57 -> Kubernetes will just use it, and not try to pull the image from ECR.
327.979 -> This might be a problem because we’re now tagging every new image with the same latest
332.37 -> tag.
333.49 -> So what happens is, although the latest tag is the same, its associated image will be
338.729 -> different.
340.04 -> Therefore, we have to add 1 more thing to the deployment.yaml file.
345.13 -> It’s called image pull policy.
348.59 -> And we must set it to “Always”
350.62 -> to make sure that Kubernetes will always pull the latest image from ECR
355.389 -> before deploying new containers.
357.31 -> Alright, let’s open the terminal to add this new change,
363.38 -> Commit it with this message: “add image pull policy always”
369.32 -> And push it to Github.
370.91 -> OK, let’s go back to our pull request and refresh.
376.5 -> Here we go, the image pull policy has been added.
381.18 -> All other yaml files of the ingress, the issuer, and the service look good to me.
387.6 -> So it’s time to merge the PR to see how it goes.
390.61 -> Bute note that you must make sure that the github-ci user has enough permissions
395.639 -> to deploy changes to the EKS cluster.
398.72 -> This is something we’ve done in one of the previous lectures.
402.49 -> As you can see here, in the IAM service,
405.33 -> My github-ci user already has Full Access to the EKS cluster.
410.449 -> OK, so let’s go ahead and click Squash and Merge.
415.34 -> Confirm it.
417.01 -> And delete the feature branch.
419.88 -> Now if we open the master branch of the repo,
423.05 -> We can see that the CI/CD process to build and deploy
426.229 -> a new image to production has been started.
428.99 -> Let’s follow this link to see more details.
432.34 -> OK, the image is being built.
435.889 -> It will take a while for it to complete.
438.66 -> Oops, Looks like the workflow failed.
442.3 -> The image has been pushed to ECR,
444.34 -> But somehow, it failed to deploy the image to EKS.
448.3 -> First, let’s open amazon ECR to check the image.
453.96 -> Here we can see a new image, but it doesn’t have the latest tag.
457.949 -> It only has 1 tag, which is the commit hash as usual.
462.27 -> So this is one of the problems we must fix.
466.009 -> Now let’s see more details in the failing step.
468.99 -> It says The connection to the server localhost was refused.
473.46 -> So it seems that kubectl is trying to connect to a cluster on local host
477.789 -> instead of the production EKS cluster.
480.72 -> That’s because I forgot 1 step to update kubeconfig to point to the production cluster.
487.68 -> We can find the production cluster’s info in the AWS console.
491.44 -> Then let’s open the deploy workflow and add a new step.
496.41 -> I’m gonna name it “Update kube config”
500.38 -> And we will run this command:
502.669 -> Aws eks update-kubeconfig
505.91 -> Followed by the name of the cluster, which is simple-bank,
510.3 -> And its region, which is eu-west-1.
515.14 -> That would fix 1 of our problems.
518.39 -> The 2nd one is the latest tag of the image is not being pushed to ECR as we expected.
523.909 -> Let’s look into the logs of the build image step to find out why.
529.34 -> The logs is quite long, but if we scroll down to the tagging part,
533.84 -> We can see that it’s has been tagged with the correct commit hash here.
537.92 -> But the latest tag doesn’t look good.
540.5 -> Its image name is also “latest” instead of the link to ECR as the one above.
545.66 -> So we’ve found the issue.
548.07 -> Let’s go back to the deploy workflow.
551.16 -> Here we have to fix the tag by adding the correct image name to its prefix
556.05 -> Just like that, and I think we’re good to go.
559.75 -> Now let’s save the file, and push it to github.
562.61 -> I’m gonna add the change we’ve just made,
566.25 -> Commit it with a message saying “fix image tag and update kube config”
572.42 -> Then git push origin ft/ci-deploy.
575.89 -> Alright, now we have to create a new pull request to merge the fix to master.
582.63 -> Oh, looks like the PR cannot be merged automatically.
586.7 -> The reason is that we’ve previously used Squash and merge,
591 -> So the commit history on our local machine is different from the one on Github’s master
595.64 -> branch.
597.05 -> To fix this, we have to rebase our branch with the latest version of master branch.
602.38 -> So first I will checkout the master branch on local,
605.88 -> Run git pull to fetch and merge all the new changes
609.05 -> from the remote master branch on Github to our local master branch.
613.85 -> Then check out the ft/ci-deploy branch,
617.31 -> And run git rebase master.
618.779 -> Of course, there will be some conflicts because the commit history is different.
624.61 -> So let’s fix it!
626.87 -> The conflict is in the deployment.yaml file.
630.75 -> Here we can see the current change and the incoming change.
633.94 -> In this case, it’s pretty simple, since we only add a new image pull policy.
639.91 -> So let’s just accept the current change.
643.31 -> OK now, go back to the terminal and check the status
647.72 -> The conflict has been resolved,
650.21 -> So we can just add the fix,
652.38 -> And then run “git base –continue” to complete the rebase process.
656.91 -> Alright, now let’s push the change to Github.
660.91 -> Note that it won’t work if we just push as normal,
664.12 -> because the commit history has been rewritten when we rebase with the master branch.
669.209 -> So the local commit history will be different from the one on github.
673.25 -> We have to use -f option to force Github to replace the change history.
679.12 -> And voila, the change has been pushed successfully.
681.79 -> It’s kind of painful, but sometimes we might need to do it.
686.56 -> We can avoid this situation by always pulling the latest changes
690.529 -> from the remote master branch first, before creating a new branch.
695.16 -> OK, now the changes look good on Github,
698.85 -> We can go ahead and create the pull request.
701.44 -> Let’s review it!
704.25 -> Here we have corrected the way we tag the latest image,
708.24 -> And here we have updated the kube config to point to the Amazon EKS cluster.
713.35 -> Everything looks good to me!
715.09 -> So it’s time to merge the PR.
717.87 -> OK, the unit tests succeeded.
719.97 -> Let’s squash and merge!
722.43 -> Confirm it!
724.07 -> And delete the feature branch.
726.45 -> Alright, now let’s see how the deploy workflow run.
731.55 -> The image is being built at the moment.
734.779 -> While waiting for it to complete, we can go to Amazon ECR,
738.37 -> And open the simple bank repository.
741.99 -> Once the new image is pushed, it will show up here.
745.57 -> OK, back to the workflow.
748.23 -> The image is being pushed to ECR.
751.3 -> Now the update kube config step is done,
754.39 -> Then the image is being deployed to Amazon EKS.
757.2 -> And a bit later, everything is done.
761.3 -> The workflow is completed successfully this time.
764.61 -> Awesome!
765.61 -> If we look at the logs of the build image step,
768.58 -> We can see that it has been tagged correctly with the latest tag.
773.05 -> And if we refresh the ECR repo page, we can see the newest image with 2 tags:
778.37 -> 1 is the commit hash, and the other is latest.
781.959 -> That’s exactly what we expected.
785.19 -> Cool, now let’s open the k9s console to verify that the correct image is deployed
790.8 -> to production!
791.8 -> I’m gonna search for all services.
795.47 -> Then open the simple-bank API service in the list.
799.29 -> As you can see, 2 pods of this service are up and running.
803.21 -> Let’s describe this pod.
805.99 -> And look at the image!
807.48 -> It has the latest tag, exactly as we wanted.
811.5 -> We can also check the image ID to see if it’s using the correct latest image or not.
817.38 -> Here we can see its full commit hash.
819.57 -> Let’s compare it with the one on ECR page.
823.47 -> We have to open the image details to see its full digest hash.
827.91 -> You can easily see that it matches the one that we see in k9s console.
832.13 -> Perfect!
833.13 -> Let’s do 1 last step to verify that the API is working well.
838.23 -> I’m gonna open Postman,
841.08 -> And send the login request that we’ve already prepared in the previous lecture.
845.3 -> Awesome!
846.3 -> It’s successful!
847.899 -> And this brings us to the end of this video.
850.47 -> It is also the end of the backend master class course.
853.05 -> I know it still doesn’t cover everything you need to know about backend development.
857.51 -> There are still a lot of advanced topics I want to share with you.
861.89 -> But I guess it would be more suitable to make them in another course.
865.279 -> Anyway, I hope you have enjoyed this backend master class,
869.87 -> And hope that it can help you somehow in your projects.
872.97 -> Thanks a lot for watching,
875.079 -> Happy learning!
876.079 -> And see you in the next course!

Source: https://www.youtube.com/watch?v=GVY-zze0V_U