Skip to content

Commit

Permalink
Optimise func-utils image (knative#2686)
Browse files Browse the repository at this point in the history
* Use command instad of script in some tkn tasks

The "script" requires /bin/sh present in the image.

Signed-off-by: Matej Vašek <[email protected]>

* Add s2i-generate command to func-util image

The command encompasses some logic previously implemented as shell
script defined in tekton task. This allows us to remove sh/shell from
the func-util image.

Signed-off-by: Matej Vašek <[email protected]>

* Make func-util image "FROM scratch"

Signed-off-by: Matej Vašek <[email protected]>

* Change func-utils image tag latest->v2

Since there are backward incompatible changes we must not change how
'latest' tag work (at least for some time).

For this reason we change tag to v2, so newer versions of func use that
and older use 'latest' that is compatible with them.

Signed-off-by: Matej Vašek <[email protected]>

---------

Signed-off-by: Matej Vašek <[email protected]>
  • Loading branch information
matejvasek authored Feb 6, 2025
1 parent f8db896 commit 9c0c216
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 136 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: knative/actions/setup-go@main
- uses: docker/setup-qemu-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
Expand All @@ -189,12 +190,14 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
run: |
./hack/fetch-util-img-prerequisites.sh
for a in amd64 arm64 ppc64le s390x; do
CGO_ENABLED=0 go build -o "func-util-$a" -trimpath -ldflags '-w -s' ./cmd/func-util
done
docker buildx create --name multiarch --driver docker-container --use
docker buildx build . -f Dockerfile.utils \
--platform=linux/ppc64le,linux/s390x,linux/amd64,linux/arm64 \
--push \
-t "ghcr.io/knative/func-utils:latest" \
-t "ghcr.io/knative/func-utils:v2" \
--annotation index:org.opencontainers.image.description="Knative Func Utils Image" \
--annotation index:org.opencontainers.image.source="https://github.com/knative/func" \
--annotation index:org.opencontainers.image.vendor="https://github.com/knative/func" \
Expand Down
36 changes: 4 additions & 32 deletions Dockerfile.utils
Original file line number Diff line number Diff line change
@@ -1,41 +1,13 @@
FROM --platform=$BUILDPLATFORM scratch AS builder

ARG BUILDPLATFORM
ARG BUILDARCH
ARG TARGETPLATFORM
ARG TARGETARCH

ADD .artifacts/alpine-minirootfs-$BUILDARCH.tar.gz /

COPY .artifacts/go.tar.gz /tmp/go.tar.gz
RUN tar -C /usr/local -xzf /tmp/go.tar.gz
ENV PATH="/usr/local/go/bin:$PATH"

WORKDIR /workspace

COPY go.mod go.sum ./
RUN go mod download -x

COPY . .

RUN GOARCH=$TARGETARCH go build -o func-util -trimpath -ldflags '-w -s' ./cmd/func-util

#########################

FROM scratch

ARG TARGETARCH
ARG FUNC_UTIL_BINARY=func-util-$TARGETARCH

ADD .artifacts/alpine-minirootfs-$TARGETARCH.tar.gz /
ENV PATH=/

RUN apk add --no-cache tar
COPY $FUNC_UTIL_BINARY /func-util

COPY --from=builder /workspace/func-util /usr/local/bin/
RUN ln -s /usr/local/bin/func-util /usr/local/bin/deploy && \
ln -s /usr/local/bin/func-util /usr/local/bin/scaffold && \
ln -s /usr/local/bin/func-util /usr/local/bin/s2i && \
ln -s /usr/local/bin/func-util /usr/local/bin/sh && \
ln -s /usr/local/bin/func-util /usr/local/bin/socat
ADD func-util-symlinks.tgz /

LABEL \
org.opencontainers.image.description="Knative Func Utils Image" \
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ KVER ?= $(shell git describe --tags --match 'knative-*')

LDFLAGS := -X knative.dev/func/pkg/app.vers=$(VERS) -X knative.dev/func/pkg/app.kver=$(KVER) -X knative.dev/func/pkg/app.hash=$(HASH)

FUNC_UTILS_IMG ?= ghcr.io/knative/func-utils:latest
FUNC_UTILS_IMG ?= ghcr.io/knative/func-utils:v2
LDFLAGS += -X knative.dev/func/pkg/k8s.SocatImage=$(FUNC_UTILS_IMG)
LDFLAGS += -X knative.dev/func/pkg/k8s.TarImage=$(FUNC_UTILS_IMG)
LDFLAGS += -X knative.dev/func/pkg/pipelines/tekton.DeployerImage=$(FUNC_UTILS_IMG)
Expand Down
2 changes: 2 additions & 0 deletions cmd/func-util/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ func main() {
cmd = socat
case "sh":
cmd = sh
case "s2i-generate":
cmd = s2iGenerate
}

err := cmd(ctx)
Expand Down
143 changes: 143 additions & 0 deletions cmd/func-util/s2i_generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
//go:build exclude_graphdriver_btrfs || !cgo
// +build exclude_graphdriver_btrfs !cgo

package main

import (
"context"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"

"github.com/openshift/source-to-image/pkg/api"
"github.com/openshift/source-to-image/pkg/build"
"github.com/openshift/source-to-image/pkg/build/strategies"
"github.com/openshift/source-to-image/pkg/scm/git"
"github.com/spf13/cobra"

fn "knative.dev/func/pkg/functions"
)

func s2iGenerate(ctx context.Context) error {
cmd := newS2IGenerateCmd()
err := cmd.ExecuteContext(ctx)
if err != nil {
return fmt.Errorf("cannot s2i generate: %w", err)
}
return nil
}

type genConfig struct {
target string
pathContext string
builderImage string
registry string
imageScriptUrl string
logLevel string
envVars []string
}

func newS2IGenerateCmd() *cobra.Command {
var config genConfig

genCmd := &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
config.envVars = args
return runS2IGenerate(cmd.Context(), config)
},
}
genCmd.Flags().StringVar(&config.target, "target", "/gen-source", "")
genCmd.Flags().StringVar(&config.pathContext, "path-context", ".", "")
genCmd.Flags().StringVar(&config.builderImage, "builder-image", "", "")
genCmd.Flags().StringVar(&config.registry, "registry", "", "")
genCmd.Flags().StringVar(&config.imageScriptUrl, "image-script-url", "image:///usr/libexec/s2i", "")
genCmd.Flags().StringVar(&config.logLevel, "log-level", "0", "")

return genCmd
}

func runS2IGenerate(ctx context.Context, c genConfig) error {

wd, err := os.Getwd()
if err != nil {
return fmt.Errorf("cannot get working directory: %w", err)
}

funcRoot := filepath.Join(wd, c.pathContext)

// replace registry in func.yaml
f, err := fn.NewFunction(funcRoot)
if err != nil {
return fmt.Errorf("cannot load function: %w", err)
}
f.Registry = c.registry
err = f.Write()
if err != nil {
return fmt.Errorf("cannot write function: %w", err)
}

// append node_modules into .s2iignore
s2iIgnorePath := filepath.Join(funcRoot, ".s2iignore")
if fi, _ := os.Stat(s2iIgnorePath); fi != nil {
var file *os.File

file, err = os.OpenFile(s2iIgnorePath, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("cannot open s2i ignore file for append: %w", err)
}
defer func(file *os.File) {
_ = file.Close()

}(file)

_, err = file.Write([]byte("\nnode_modules"))
if err != nil {
return fmt.Errorf("cannot append node_modules directory to s2i ignore file: %w", err)
}
}

// prepare envvars
var envs = make([]api.EnvironmentSpec, 0, len(c.envVars))
for _, e := range c.envVars {
var es api.EnvironmentSpec
part := strings.SplitN(e, "=", 2)
switch len(part) {
case 1:
es.Name = part[0]
case 2:
es.Name = part[0]
es.Value = part[1]
default:
continue
}
if es.Name != "" {
envs = append(envs, es)
}
}

s2iConfig := api.Config{
Source: &git.URL{
URL: url.URL{Path: funcRoot},
Type: git.URLTypeLocal,
},
BuilderImage: c.builderImage,
ImageScriptsURL: c.imageScriptUrl,
KeepSymlinks: true,
Environment: envs,
AsDockerfile: filepath.Join(c.target, "Dockerfile.gen"),
}

builder, _, err := strategies.Strategy(nil, &s2iConfig, build.Overrides{})
if err != nil {
return fmt.Errorf("cannot create builder: %w", err)
}

_, err = builder.Build(&s2iConfig)
if err != nil {
return fmt.Errorf("cannot build: %w", err)
}

return nil
}
Binary file added func-util-symlinks.tgz
Binary file not shown.
60 changes: 0 additions & 60 deletions hack/fetch-util-img-prerequisites.sh

This file was deleted.

6 changes: 3 additions & 3 deletions hack/setup-testing-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ set -o errexit
set -o nounset
set -o pipefail

FUNC_UTILS_IMG="localhost:50000/knative/func-utils:latest"
FUNC_UTILS_IMG="localhost:50000/knative/func-utils:v2"

"$(dirname "$(realpath "$0")")/fetch-util-img-prerequisites.sh"
CGO_ENABLED=0 go build -o "func-util" -trimpath -ldflags '-w -s' ./cmd/func-util

docker build . -f Dockerfile.utils -t "${FUNC_UTILS_IMG}"
docker build . -f Dockerfile.utils -t "${FUNC_UTILS_IMG}" --build-arg FUNC_UTIL_BINARY=func-util
docker push "${FUNC_UTILS_IMG}"

# Build custom buildah image for tests.
Expand Down
2 changes: 1 addition & 1 deletion pkg/k8s/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
"k8s.io/client-go/tools/remotecommand"
)

var SocatImage = "ghcr.io/knative/func-utils:latest"
var SocatImage = "ghcr.io/knative/func-utils:v2"

// NewInClusterDialer creates context dialer that will dial TCP connections via POD running in k8s cluster.
// This is useful when accessing k8s services that are not exposed outside cluster (e.g. openshift image registry).
Expand Down
2 changes: 1 addition & 1 deletion pkg/k8s/persistent_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func DeletePersistentVolumeClaims(ctx context.Context, namespaceOverride string,
return client.CoreV1().PersistentVolumeClaims(namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, listOptions)
}

var TarImage = "ghcr.io/knative/func-utils:latest"
var TarImage = "ghcr.io/knative/func-utils:v2"

// UploadToVolume uploads files (passed in form of tar stream) into volume.
func UploadToVolume(ctx context.Context, content io.Reader, claimName, namespace string) error {
Expand Down
Loading

0 comments on commit 9c0c216

Please sign in to comment.