Skip to content

Commit ed4ee90

Browse files
sgalsalehemosbaugh
andauthored
feat: build k0s images with chainguard (#793)
* feat: build k0s images with chainguard --------- Co-authored-by: Ethan Mosbaugh <[email protected]>
1 parent 9a5ec22 commit ed4ee90

File tree

14 files changed

+552
-10
lines changed

14 files changed

+552
-10
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Update image deps
2+
3+
on:
4+
schedule:
5+
- cron: '0 4 * * *'
6+
workflow_dispatch:
7+
inputs:
8+
k0s-version:
9+
description: 'K0s version for discovering image versions'
10+
required: false
11+
12+
jobs:
13+
update-k0s-images:
14+
runs-on: ubuntu-20.04
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
19+
- name: Setup Go
20+
uses: actions/setup-go@v5
21+
with:
22+
go-version-file: go.mod
23+
24+
- name: Compile buildtools
25+
run: make buildtools
26+
27+
- name: Update k0s images
28+
env:
29+
REGISTRY_SERVER: docker.io
30+
REGISTRY_USER: ${{ secrets.DOCKERHUB_USER }}
31+
REGISTRY_PASS: ${{ secrets.DOCKERHUB_PASSWORD }}
32+
run: ./output/bin/buildtools update images k0s
33+
34+
- name: Create Pull Request # creates a PR if there are differences
35+
uses: peter-evans/create-pull-request@v6
36+
id: cpr
37+
with:
38+
token: ${{ secrets.AUTOMATED_PR_GH_PAT }}
39+
commit-message: 'Update image versions'
40+
title: 'Automated image updates'
41+
branch: automation/image-dependencies
42+
delete-branch: true
43+
labels: |
44+
automated-pr
45+
images
46+
type::security
47+
draft: false
48+
base: "main"
49+
body: "Automated changes by the [image-deps-updater](https://github.com/replicatedhq/embedded-cluster/blob/main/.github/workflows/image-deps-updater.yaml) GitHub action"
50+
51+
- name: Check outputs
52+
if: ${{ steps.cpr.outputs.pull-request-number }}
53+
run: |
54+
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
55+
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ VERSION ?= $(shell git describe --tags --dirty)
22
UNAME := $(shell uname)
33
ARCH := $(shell uname -m)
44
APP_NAME = embedded-cluster
5+
COREDNS_IMAGE = proxy.replicated.com/anonymous/replicated/ec-coredns
6+
COREDNS_VERSION = 1.11.3-r3@sha256:7996a7ee8e1b7fec9a6dc216b01f0047cafbd551562bde44a2c6615ef8f3dbfc
7+
CALICO_NODE_IMAGE = proxy.replicated.com/anonymous/replicated/ec-calico-node
8+
CALICO_NODE_VERSION = 3.26.1-r16@sha256:f2d58c94a900bf33174d81cb270dfdf070350954fd2e4e7edeccc2dad2f855b6
9+
METRICS_SERVER_IMAGE = proxy.replicated.com/anonymous/replicated/ec-metrics-server
10+
METRICS_SERVER_VERSION = 0.6.4-r9@sha256:bd7d9ada28e299979174b2094d1eec7d653f793730b320dc7e90763c92452268
511
ADMIN_CONSOLE_CHART_REPO_OVERRIDE =
612
ADMIN_CONSOLE_CHART_VERSION = 1.112.1-build.1
713
ADMIN_CONSOLE_IMAGE_OVERRIDE =
@@ -38,6 +44,12 @@ LD_FLAGS = -X github.com/replicatedhq/embedded-cluster/pkg/defaults.K0sVersion=$
3844
-X github.com/replicatedhq/embedded-cluster/pkg/defaults.TroubleshootVersion=$(TROUBLESHOOT_VERSION) \
3945
-X github.com/replicatedhq/embedded-cluster/pkg/defaults.KubectlVersion=$(KUBECTL_VERSION) \
4046
-X github.com/replicatedhq/embedded-cluster/pkg/defaults.LocalArtifactMirrorImage=$(LOCAL_ARTIFACT_MIRROR_IMAGE_LOCATION) \
47+
-X github.com/replicatedhq/embedded-cluster/pkg/config/images.CoreDNSImage=$(COREDNS_IMAGE) \
48+
-X github.com/replicatedhq/embedded-cluster/pkg/config/images.CoreDNSVersion=$(COREDNS_VERSION) \
49+
-X github.com/replicatedhq/embedded-cluster/pkg/config/images.CalicoNodeImage=$(CALICO_NODE_IMAGE) \
50+
-X github.com/replicatedhq/embedded-cluster/pkg/config/images.CalicoNodeVersion=$(CALICO_NODE_VERSION) \
51+
-X github.com/replicatedhq/embedded-cluster/pkg/config/images.MetricsServerImage=$(METRICS_SERVER_IMAGE) \
52+
-X github.com/replicatedhq/embedded-cluster/pkg/config/images.MetricsServerVersion=$(METRICS_SERVER_VERSION) \
4153
-X github.com/replicatedhq/embedded-cluster/pkg/addons/adminconsole.ChartRepoOverride=$(ADMIN_CONSOLE_CHART_REPO_OVERRIDE) \
4254
-X github.com/replicatedhq/embedded-cluster/pkg/addons/adminconsole.Version=$(ADMIN_CONSOLE_CHART_VERSION) \
4355
-X github.com/replicatedhq/embedded-cluster/pkg/addons/adminconsole.ImageOverride=$(ADMIN_CONSOLE_IMAGE_OVERRIDE) \

cmd/buildtools/k0s.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"fmt"
7+
"os"
8+
"os/exec"
9+
"path/filepath"
10+
"strings"
11+
12+
"github.com/sirupsen/logrus"
13+
"github.com/urfave/cli/v2"
14+
)
15+
16+
var k0sComponents = []struct {
17+
name string
18+
makefileVar string
19+
}{
20+
{
21+
name: "coredns",
22+
makefileVar: "COREDNS_VERSION",
23+
},
24+
{
25+
name: "calico-node",
26+
makefileVar: "CALICO_NODE_VERSION",
27+
},
28+
{
29+
name: "metrics-server",
30+
makefileVar: "METRICS_SERVER_VERSION",
31+
},
32+
}
33+
34+
var updateK0sImagesCommand = &cli.Command{
35+
Name: "k0s",
36+
Usage: "Updates the k0s images",
37+
UsageText: environmentUsageText,
38+
Flags: []cli.Flag{
39+
&cli.StringFlag{
40+
Name: "k0s-version",
41+
Usage: "The version of k0s to use to determine image versions",
42+
},
43+
},
44+
Action: func(c *cli.Context) error {
45+
logrus.Infof("updating k0s images")
46+
47+
k0sVersion := c.String("k0s-version")
48+
if k0sVersion != "" {
49+
if err := runCommand("make", "pkg/goods/bins/k0s", fmt.Sprintf("K0S_VERSION=%s", k0sVersion), "K0S_BINARY_SOURCE_OVERRIDE="); err != nil {
50+
return fmt.Errorf("failed to make k0s: %w", err)
51+
}
52+
} else {
53+
if err := runCommand("make", "pkg/goods/bins/k0s"); err != nil {
54+
return fmt.Errorf("failed to make k0s: %w", err)
55+
}
56+
}
57+
58+
if err := runCommand("make", "apko"); err != nil {
59+
return fmt.Errorf("failed to make apko: %w", err)
60+
}
61+
62+
if os.Getenv("REGISTRY_PASS") != "" {
63+
if err := runCommand(
64+
"make",
65+
"apko-login",
66+
fmt.Sprintf("REGISTRY=%s", os.Getenv("REGISTRY_SERVER")),
67+
fmt.Sprintf("USERNAME=%s", os.Getenv("REGISTRY_USER")),
68+
fmt.Sprintf("PASSWORD=%s", os.Getenv("REGISTRY_PASS")),
69+
); err != nil {
70+
return fmt.Errorf("failed to apko login: %w", err)
71+
}
72+
}
73+
74+
wolfiAPKIndex, err := GetWolfiAPKIndex()
75+
if err != nil {
76+
return fmt.Errorf("failed to get APK index: %w", err)
77+
}
78+
79+
for _, component := range k0sComponents {
80+
upstreamVersion, err := getUpstreamVersion(component.name)
81+
if err != nil {
82+
return fmt.Errorf("failed to get upstream version for %s: %w", component.name, err)
83+
}
84+
85+
packageVersion, err := GetWolfiPackageVersion(wolfiAPKIndex, component.name, upstreamVersion)
86+
if err != nil {
87+
return fmt.Errorf("failed to get package version for %s: %w", component.name, err)
88+
}
89+
90+
if err := runCommand(
91+
"make",
92+
"apko-build-and-publish",
93+
fmt.Sprintf("IMAGE=%s/replicated/ec-%s:%s", os.Getenv("REGISTRY_SERVER"), component.name, packageVersion),
94+
fmt.Sprintf("APKO_CONFIG=%s", filepath.Join("deploy", "images", component.name, "apko.tmpl.yaml")),
95+
fmt.Sprintf("PACKAGE_VERSION=%s", packageVersion),
96+
); err != nil {
97+
return fmt.Errorf("failed to build and publish apko for %s: %w", component.name, err)
98+
}
99+
100+
digest, err := getDigestFromBuildFile()
101+
if err != nil {
102+
return fmt.Errorf("failed to get digest from build file: %w", err)
103+
}
104+
105+
if err := SetMakefileVariable(component.makefileVar, fmt.Sprintf("%s@%s", packageVersion, digest)); err != nil {
106+
return fmt.Errorf("failed to set %s version: %w", component.name, err)
107+
}
108+
}
109+
110+
return nil
111+
},
112+
}
113+
114+
func getUpstreamVersion(name string) (string, error) {
115+
output, err := exec.Command("pkg/goods/bins/k0s", "airgap", "list-images", "--all").Output()
116+
if err != nil {
117+
return "", fmt.Errorf("list k0s images: %w", err)
118+
}
119+
120+
// example output:
121+
// quay.io/k0sproject/calico-node:v3.26.1-1
122+
// quay.io/k0sproject/coredns:1.11.3
123+
// quay.io/k0sproject/apiserver-network-proxy-agent:v0.1.4
124+
125+
version := ""
126+
scanner := bufio.NewScanner(bytes.NewReader(output))
127+
for scanner.Scan() {
128+
line := scanner.Text()
129+
if !strings.Contains(line, "/"+name+":") {
130+
continue
131+
}
132+
parts := strings.Split(line, ":")
133+
if len(parts) != 2 {
134+
return "", fmt.Errorf("incorrect number of parts in image line: %s", line)
135+
}
136+
version = strings.TrimPrefix(parts[1], "v")
137+
version = strings.Split(version, "-")[0]
138+
break
139+
}
140+
141+
if version == "" {
142+
return "", fmt.Errorf("%q image not found", name)
143+
}
144+
return version, nil
145+
}
146+
147+
func getDigestFromBuildFile() (string, error) {
148+
contents, err := os.ReadFile("build/digest")
149+
if err != nil {
150+
return "", fmt.Errorf("read build file: %w", err)
151+
}
152+
parts := strings.Split(string(contents), "@")
153+
if len(parts) != 2 {
154+
return "", fmt.Errorf("incorrect number of parts in build file")
155+
}
156+
return strings.TrimSpace(parts[1]), nil
157+
}
158+
159+
func runCommand(name string, args ...string) error {
160+
cmd := exec.Command(name, args...)
161+
cmd.Stdout = os.Stdout
162+
cmd.Stderr = os.Stderr
163+
return cmd.Run()
164+
}

cmd/buildtools/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
const environmentUsageText = `
1414
This script uses the following environment variables:
15-
- REGISTRY_SERVER: the registry server to push the chart to (used for authentication, e.g. index.docker.io)
15+
- REGISTRY_SERVER: the registry server to push the chart/image to (only used for authentication in the case of charts, e.g. index.docker.io)
1616
- REGISTRY_USER: the username to authenticate with.
1717
- REGISTRY_PASS: the password to authenticate with.
1818
- DESTINATION: the destination repository to push the chart to (e.g. oci://ttl.sh/embedded-cluster-charts)
@@ -29,7 +29,7 @@ func main() {
2929
Name: "buildtools",
3030
Usage: "Provide a set of tools for building embedded cluster binarires",
3131
Commands: []*cli.Command{
32-
addonCommand,
32+
updateCommand,
3333
},
3434
}
3535
if err := app.RunContext(ctx, os.Args); err != nil {

cmd/buildtools/addon.go renamed to cmd/buildtools/update.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,36 @@ import (
44
"github.com/urfave/cli/v2"
55
)
66

7-
var addonCommand = &cli.Command{
7+
var updateCommand = &cli.Command{
88
Name: "update",
9-
Usage: "Manage the embedded cluster addons",
10-
Flags: []cli.Flag{
11-
&cli.BoolFlag{
12-
Name: "force",
13-
Usage: "Pushes the addon chart even if no new version was found",
14-
},
15-
},
9+
Usage: "Manage the embedded cluster components",
1610
Subcommands: []*cli.Command{
1711
updateAddonCommand,
12+
updateImagesCommand,
1813
},
1914
}
2015

2116
var updateAddonCommand = &cli.Command{
2217
Name: "addon",
2318
Usage: "Update an embedded cluster addon by copying the chart to the Replicated registry and setting the version in the Makefile",
19+
Flags: []cli.Flag{
20+
&cli.BoolFlag{
21+
Name: "force",
22+
Usage: "Pushes the addon chart even if no new version was found",
23+
},
24+
},
2425
Subcommands: []*cli.Command{
2526
updateOpenEBSAddonCommand,
2627
updateSeaweedFSAddonCommand,
2728
updateRegistryAddonCommand,
2829
updateVeleroAddonCommand,
2930
},
3031
}
32+
33+
var updateImagesCommand = &cli.Command{
34+
Name: "images",
35+
Usage: "Update embedded cluster images",
36+
Subcommands: []*cli.Command{
37+
updateK0sImagesCommand,
38+
},
39+
}

0 commit comments

Comments
 (0)