From 7aac56d7fe62b9cb72077771804a818195fb0a68 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Wed, 7 Feb 2024 18:05:27 +0000 Subject: [PATCH 01/11] Add migrating go video. Signed-off-by: Adrian Mouat --- .../chainguard-images/videos/migrating_go.md | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 content/chainguard/chainguard-images/videos/migrating_go.md diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md new file mode 100644 index 0000000000..171db1b65d --- /dev/null +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -0,0 +1,232 @@ +--- +title: "Migrating a Dockerfile for a Go application to use Chainguard Images" +linktitle: "Migrating Go Applications to Chainguard" +lead: "" +description: "How to migrate an existing Dockerfile to Chainguard Images in order toimprove security and reduce file size." +type: "article" +date: 2024-02-07T01:21:01+00:00 +lastmod: 2024-02-07T15:21:01+00:00 +draft: false +images: [] +menu: + docs: + parent: "chainguard-images" +weight: 30 +toc: true +--- + +{{< youtube IuEOyACeJE8 >}} + +## Tools used in this video + +* [Docker](https://docker.com) + +## Resources + +[Statically Linking Go](https://mt165.co.uk/blog/static-link-go/) + +## Transcript + +In this video, I'm going to show how easy it is to port an existing Dockerfile to use a Chainguard Image base, and how that can help to improve the image, especially in terms of security. + +I'll be using the free tier of Chainguard Images here, so you can do everything in this video on your own projects today. + +The example I'm going to use is porting an existing Golang project to use the Chainguard Go and Static images, but a very similar technique can be used for other compiled languages, such as Rust and C, especially where you can produce a statically linked executable. + +Okay, so over to the terminal. + +Okay, so I have this simple Go project. + +We can take a look at the main part of the code. + +It's extremely simple. + +All we're doing is creating a web server that listens on port 8080 and responds with the text: "Hello world." + +We also have a Dockerfile to build our application. + +It's extremely simple as well. + +We're using the Dockerhub Golang image, copying over the source, and running Go build. + +So let's try building that. + +I've built it before, so that ran really fast. + +We can try running it. + +I should be able to access it. + +Okay, so that all works. + +It's a really nice, simple Go web server. + +Let's take a look at how we can change it to use a Chainguard Image. + +The easiest thing we can do, literally a one-line change, is just to modify this to point out the Chainguard Go image. + +With any luck, that will build just the same. + +So I'll go back to this original build statement. + +We'll call it something different so we can compare it later. + +Okay, that's built. + +Now we want to check it runs. + +I do need to first stop the old one. + +Okay, let's try running it again. + +It's running. + +Let's check it works. + +Okay, so that works identically. + +A one-line change, and we've made no difference to the actual running application. + +But let's investigate this a little bit more. + +So if I do 'docker images' on go-web-app, well this is a pretty large image at 892 megabytes. + +If I run it on our new image, it's 775 megabytes. + +So that's 120 megabytes saving, but still quite a large image. + +More interestingly, if I try Docker Scout Quick View to take a look at the CVEs, if I run it on Go web app, we can see there's 42 lower vulnerabilities in there. + +So there's quite a bit going on in there. + +We can also see there's 303 packages. + +So there's a lot of stuff in this image. + +Let's compare it to the Chainguard Image. + +There's no CVEs and there's only 85 packages. + +So this one change has really improved the security posture by getting rid of these 42 low CVEs. + +But there's a lot more we can do. + +Let's take a look at the Dockerfile again. + +So we're using this Chainguard Go image, but we don't need everything in this image when we're actually running the image. + +We just need the Go compiler, for instance, to build the server, but we don't need the Go compiler in the final image. + +So what we can do is create a multi-stage build. + +And I'm going to use the Chainguard static image to house the final production application. + +So the static image is really simple. + +It has very little in it, just sort of the minimum you need to run a typical Linux application. + +So it has TLS certificates so you can talk to web applications over TLS. + +It has Unix directories like /tmp and /home, and it doesn't have a lot else. + +It's only a few megabytes in size, but contains a few more things than say scratch that you need for typical applications. + +OK, what we're going to do here is I'm going to copy from the previous build to the Dockerfile up here. + +I'm going to copy the hello executable, which is at /work hello to /hello. + +Now it said copy from builder, so I'll need to name this first step builder. + +And that will build this hello executable and copy it into my production image. + +And then my entry point is now /hello. + +So there is one more thing we need to do. + +The static image does not include any libraries like glibc or anything. + +It just has it's just for running statically compiled binaries. + +So we need to tell Go to produce a statically compiled binary that contains everything it needs to run and doesn't rely on system libraries. + +And we can do that by saying cgo enabled equals zero. + +In some cases, you might find you need to pass a few more flags, depending on which Go libraries you use. + +And I'll link a blog in the notes that explains when you need to do this and what you need to do. + +But in this case, cgo enabled equals zero will allow us to build our static binary. + +So I think that's all I need to do. + +We'll see if I got it right. + +Let's find the Docker build step. + +I'm going to call this distroless. + +So when you create an image with just the bare minimum in it to run your application, we quite often call it a distroless image. + +No, it doesn't even have a shell or a package manager. + +OK, let's see. + +Let's see if that builds. + +Yep, that built. + +Excellent. + +I think I still have the old one running. + +So let's get rid of the old web app. + +No, I always get that wrong. + +OK, and let's run this one. + +I call it web-app-distroless. + +I hope so. + +That's running. + +Let's see if it works. + +Excellent. + +So this application still works exactly the same as it did at the start of this video. + +But if I take a look at the web app distroless, the big difference is that now it's only eight point five megabytes in size. + +So we went from the original Golang image, which is eight hundred and ninety two megabytes, to a Chainguard Image, which was seven hundred seventy five megabytes, down to eight point five one megabytes. + +And it still all works the same. + +So that's a big saving in terms of space. + +It also means it's a lot quicker to transfer about. + +It's a lot quicker to start up on your nodes, etc. + +And most importantly, it should still have zero CVEs. + +Yes. + +If you don't have access to Docker Scout quick view, you can use other scanners, of course. + +There's things like Snyk and Grype. + +It's a great free one that we use quite a lot in Chainguard. + +But that's really all I want to talk about. + +So please do go and try out our static images. + +They do work great with go, but also they work with Rust, C, etc. + +And we also have a variance that include things like the Glibc libraries. + +If you just need a very minimal image with Glibc and nothing else to run your application. + +OK, please try it out and let me know how you get on. From 20a761eb2bc013128301c939524a277454953bbc Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Wed, 7 Feb 2024 20:12:51 +0000 Subject: [PATCH 02/11] Fix description. Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 171db1b65d..7c0449d308 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -2,7 +2,7 @@ title: "Migrating a Dockerfile for a Go application to use Chainguard Images" linktitle: "Migrating Go Applications to Chainguard" lead: "" -description: "How to migrate an existing Dockerfile to Chainguard Images in order toimprove security and reduce file size." +description: "How to migrate an existing Dockerfile for an application that can be statically compiled to Chainguard Images in order to improve security and reduce file size." type: "article" date: 2024-02-07T01:21:01+00:00 lastmod: 2024-02-07T15:21:01+00:00 From 53c89ca732c14bcd2c892ce25a113d8005c82e31 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:36:32 +0000 Subject: [PATCH 03/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 7c0449d308..b516b3eeef 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -89,7 +89,7 @@ A one-line change, and we've made no difference to the actual running applicatio But let's investigate this a little bit more. -So if I do 'docker images' on go-web-app, well this is a pretty large image at 892 megabytes. +So if I do `docker images` on `go-web-app`, well this is a pretty large image at 892 megabytes. If I run it on our new image, it's 775 megabytes. From 73e31d27e3afcdb81fbb2467b1ae5afeed2ebf05 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:36:39 +0000 Subject: [PATCH 04/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index b516b3eeef..1f7c4cd105 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -127,7 +127,7 @@ It has very little in it, just sort of the minimum you need to run a typical Lin So it has TLS certificates so you can talk to web applications over TLS. -It has Unix directories like /tmp and /home, and it doesn't have a lot else. +It has Unix directories like `/tmp` and `/home`, and it doesn't have a lot else. It's only a few megabytes in size, but contains a few more things than say scratch that you need for typical applications. From 9cb5c5f613e199fb20e2ea9d6dcd537174ed90c8 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:36:44 +0000 Subject: [PATCH 05/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 1f7c4cd105..44a5cb38d8 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -133,7 +133,7 @@ It's only a few megabytes in size, but contains a few more things than say scrat OK, what we're going to do here is I'm going to copy from the previous build to the Dockerfile up here. -I'm going to copy the hello executable, which is at /work hello to /hello. +I'm going to copy the `hello` executable, which is at `/work/hello` to `/hello`. Now it said copy from builder, so I'll need to name this first step builder. From 9dd4e99efbb4bac04538905f98ae072967e45172 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:36:51 +0000 Subject: [PATCH 06/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 44a5cb38d8..66ac0f48ab 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -139,7 +139,7 @@ Now it said copy from builder, so I'll need to name this first step builder. And that will build this hello executable and copy it into my production image. -And then my entry point is now /hello. +And then my entry point is now `/hello`. So there is one more thing we need to do. From 3a31806ee48295dc33a5b0dd24b11faac01583f3 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:37:13 +0000 Subject: [PATCH 07/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 66ac0f48ab..3c7d595a78 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -155,7 +155,7 @@ In some cases, you might find you need to pass a few more flags, depending on wh And I'll link a blog in the notes that explains when you need to do this and what you need to do. -But in this case, cgo enabled equals zero will allow us to build our static binary. +But in this case, `CGO_enabled=0` will allow us to build our static binary. So I think that's all I need to do. From 195cc64a0642031bf4516edfc5113059f4ea7292 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:37:19 +0000 Subject: [PATCH 08/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 3c7d595a78..d95246919e 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -185,7 +185,7 @@ No, I always get that wrong. OK, and let's run this one. -I call it web-app-distroless. +I call it `web-app-distroless`. I hope so. From 0987c5ffa5d57c9b2472589dadab6757452ecab0 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:37:28 +0000 Subject: [PATCH 09/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index d95246919e..8851477e81 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -197,7 +197,7 @@ Excellent. So this application still works exactly the same as it did at the start of this video. -But if I take a look at the web app distroless, the big difference is that now it's only eight point five megabytes in size. +But if I take a look at the web app distroless, the big difference is that now it's only 8.5 megabytes in size. So we went from the original Golang image, which is eight hundred and ninety two megabytes, to a Chainguard Image, which was seven hundred seventy five megabytes, down to eight point five one megabytes. From cddcec74d11e0f19b9b9ea3991aa2a0a8f69143d Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:37:37 +0000 Subject: [PATCH 10/11] Update content/chainguard/chainguard-images/videos/migrating_go.md Co-authored-by: ltagliaferri Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index 8851477e81..d697d2f2e4 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -199,7 +199,7 @@ So this application still works exactly the same as it did at the start of this But if I take a look at the web app distroless, the big difference is that now it's only 8.5 megabytes in size. -So we went from the original Golang image, which is eight hundred and ninety two megabytes, to a Chainguard Image, which was seven hundred seventy five megabytes, down to eight point five one megabytes. +So we went from the original Golang image, which is 892 megabytes, to a Chainguard Image, which was 775 megabytes, down to 8.51 megabytes. And it still all works the same. From ebeacc7f33f834da9e4e7edba11b0615158da545 Mon Sep 17 00:00:00 2001 From: Adrian Mouat Date: Thu, 8 Feb 2024 09:41:06 +0000 Subject: [PATCH 11/11] Minor fix to transcript. Signed-off-by: Adrian Mouat --- content/chainguard/chainguard-images/videos/migrating_go.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/chainguard/chainguard-images/videos/migrating_go.md b/content/chainguard/chainguard-images/videos/migrating_go.md index d697d2f2e4..0878196ccc 100644 --- a/content/chainguard/chainguard-images/videos/migrating_go.md +++ b/content/chainguard/chainguard-images/videos/migrating_go.md @@ -143,9 +143,9 @@ And then my entry point is now `/hello`. So there is one more thing we need to do. -The static image does not include any libraries like glibc or anything. +The static image does not include any libraries like Glibc or anything. -It just has it's just for running statically compiled binaries. +It just has enough for running statically compiled binaries. So we need to tell Go to produce a statically compiled binary that contains everything it needs to run and doesn't rely on system libraries.