From c473dd5c8ce4b519dae941180d85fba301b6a758 Mon Sep 17 00:00:00 2001 From: Damian Czaja Date: Wed, 28 Aug 2024 15:41:41 +0200 Subject: [PATCH] KUBE-503: add Github Actions workflow to build container image, add Helm chart --- .github/workflows/build.yaml | 99 +++++++++++++++++++ Dockerfile | 5 +- charts/cast-cloud-proxy/.helmignore | 23 +++++ charts/cast-cloud-proxy/Chart.yaml | 7 ++ .../cast-cloud-proxy/templates/_helpers.tpl | 62 ++++++++++++ .../templates/deployment.yaml | 53 ++++++++++ .../templates/serviceaccount.yaml | 13 +++ charts/cast-cloud-proxy/values.yaml | 67 +++++++++++++ cmd/proxy/main.go | 2 +- go.mod | 2 +- internal/castai/dummy/roundtripper.go | 1 + 11 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/build.yaml create mode 100644 charts/cast-cloud-proxy/.helmignore create mode 100644 charts/cast-cloud-proxy/Chart.yaml create mode 100644 charts/cast-cloud-proxy/templates/_helpers.tpl create mode 100644 charts/cast-cloud-proxy/templates/deployment.yaml create mode 100644 charts/cast-cloud-proxy/templates/serviceaccount.yaml create mode 100644 charts/cast-cloud-proxy/values.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..431d9e1 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,99 @@ +name: Build +on: + push: + branches: + - main + release: + types: + - published + pull_request: + branches: + - main + +jobs: + build: + name: Build + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: 1.22.6 + + - name: Cache Go modules + uses: actions/cache@v3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-build-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build- + + - name: Get release tag + if: github.event_name == 'release' + run: echo "RELEASE_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + + - name: Build Go binary amd64 + run: go build -ldflags "-s -w -X main.GitCommit=$GITHUB_SHA -X main.GitRef=$GITHUB_REF -X main.Version=${RELEASE_TAG:-commit-$GITHUB_SHA}" -o bin/castai-cloud-proxy-amd64 ./cmd/proxy + env: + GOOS: linux + GOARCH: amd64 + CGO_ENABLED: 0 + + - name: Build Go binary arm64 + run: go build -ldflags "-s -w -X main.GitCommit=$GITHUB_SHA -X main.GitRef=$GITHUB_REF -X main.Version=${RELEASE_TAG:-commit-$GITHUB_SHA}" -o bin/castai-cloud-proxy-arm64 ./cmd/proxy + env: + GOOS: linux + GOARCH: arm64 + CGO_ENABLED: 0 + + - name: Test + run: go test -race ./... + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Google Artifact Registry + uses: docker/login-action@v3 + with: + registry: us-docker.pkg.dev + username: _json_key + password: ${{ secrets.ARTIFACT_BUILDER_JSON_KEY }} + + - name: Build and push main + if: github.event_name != 'release' + uses: docker/build-push-action@v3 + with: + context: . + push: true + platforms: linux/arm64,linux/amd64 + tags: | + us-docker.pkg.dev/castai-hub/library/cloud-proxy:${{ github.sha }} + + - name: Build and push release + if: github.event_name == 'release' + uses: docker/build-push-action@v3 + with: + context: . + push: true + platforms: linux/arm64,linux/amd64 + tags: | + us-docker.pkg.dev/castai-hub/library/cloud-proxy:${{ env.RELEASE_TAG }} + us-docker.pkg.dev/castai-hub/library/cloud-proxy:latest + + #- name: Docker pull for fossa main + # if: github.event_name == 'release' + # run: docker pull us-docker.pkg.dev/castai-hub/library/cloud-proxy:${{ env.RELEASE_TAG }} + # + #- name: FOSSA scan docker image + # if: github.event_name == 'release' + # continue-on-error: true + # uses: fossas/fossa-action@v1 + # with: + # api-key: ${{ secrets.FOSSA_API_KEY }} + # container: us-docker.pkg.dev/castai-hub/library/cloud-proxy:${{ env.RELEASE_TAG }} + diff --git a/Dockerfile b/Dockerfile index 4bdab84..e3f0295 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,6 @@ FROM gcr.io/distroless/static-debian11 -#FROM ubuntu:latest -# TODO: Multi-arch build +ARG TARGETARCH="amd64" -COPY bin/castai-cloud-proxy-amd64 /usr/local/bin/castai-cloud-proxy +COPY bin/castai-cloud-proxy-$TARGETARCH /usr/local/bin/castai-cloud-proxy CMD ["castai-cloud-proxy"] diff --git a/charts/cast-cloud-proxy/.helmignore b/charts/cast-cloud-proxy/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/cast-cloud-proxy/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/cast-cloud-proxy/Chart.yaml b/charts/cast-cloud-proxy/Chart.yaml new file mode 100644 index 0000000..3b11c9e --- /dev/null +++ b/charts/cast-cloud-proxy/Chart.yaml @@ -0,0 +1,7 @@ +# TODO: move to https://github.com/castai/helm-charts +apiVersion: v2 +name: cloud-proxy +description: CAST AI cloud-proxy chart +type: application +version: 0.1.0 +appVersion: "v0.0.1" diff --git a/charts/cast-cloud-proxy/templates/_helpers.tpl b/charts/cast-cloud-proxy/templates/_helpers.tpl new file mode 100644 index 0000000..1936ca2 --- /dev/null +++ b/charts/cast-cloud-proxy/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cast-cloud-proxy.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "cast-cloud-proxy.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cast-cloud-proxy.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cast-cloud-proxy.labels" -}} +helm.sh/chart: {{ include "cast-cloud-proxy.chart" . }} +{{ include "cast-cloud-proxy.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cast-cloud-proxy.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cast-cloud-proxy.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "cast-cloud-proxy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "cast-cloud-proxy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/cast-cloud-proxy/templates/deployment.yaml b/charts/cast-cloud-proxy/templates/deployment.yaml new file mode 100644 index 0000000..bc0694b --- /dev/null +++ b/charts/cast-cloud-proxy/templates/deployment.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "cast-cloud-proxy.fullname" . }} + labels: + {{- include "cast-cloud-proxy.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "cast-cloud-proxy.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "cast-cloud-proxy.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "cast-cloud-proxy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/cast-cloud-proxy/templates/serviceaccount.yaml b/charts/cast-cloud-proxy/templates/serviceaccount.yaml new file mode 100644 index 0000000..7c28e67 --- /dev/null +++ b/charts/cast-cloud-proxy/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "cast-cloud-proxy.serviceAccountName" . }} + labels: + {{- include "cast-cloud-proxy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/charts/cast-cloud-proxy/values.yaml b/charts/cast-cloud-proxy/values.yaml new file mode 100644 index 0000000..71d1aac --- /dev/null +++ b/charts/cast-cloud-proxy/values.yaml @@ -0,0 +1,67 @@ +# Default values for cast-cloud-proxy. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: us-docker.pkg.dev/castai-hub/library/cloud-proxy + pullPolicy: IfNotPresent + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# TODO: add probes +#livenessProbe: +# httpGet: +# path: / +# port: http +#readinessProbe: +# httpGet: +# path: / +# port: http + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index d0dec73..f1a1e50 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -53,7 +53,7 @@ func main() { go func() { loggerClientProxy := log.New(os.Stderr, "[CLUSTER PROXY] ", log.LstdFlags) loggerClientProxy.Println("Starting proxy client") - conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { loggerClientProxy.Panicf("Failed to connect to server: %v", err) } diff --git a/go.mod b/go.mod index 74ed9ea..6dcdbd4 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.13.0 golang.org/x/oauth2 v0.22.0 + golang.org/x/sync v0.8.0 google.golang.org/api v0.193.0 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 @@ -30,7 +31,6 @@ require ( go.opentelemetry.io/otel/trace v1.28.0 // indirect golang.org/x/crypto v0.26.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.6.0 // indirect diff --git a/internal/castai/dummy/roundtripper.go b/internal/castai/dummy/roundtripper.go index 93801c6..71eb8a0 100644 --- a/internal/castai/dummy/roundtripper.go +++ b/internal/castai/dummy/roundtripper.go @@ -30,6 +30,7 @@ func (p *HttpOverGrpcRoundTripper) RoundTrip(request *http.Request) (*http.Respo for h, v := range request.Header { headers[h] = strings.Join(v, ",") } + protoReq := &proto.HttpRequest{ RequestID: requestID, Method: request.Method,