From 93abdd358ad0f18b15996e069dc62b70d336e40d Mon Sep 17 00:00:00 2001 From: Elie CHARRA Date: Wed, 21 Feb 2024 11:24:22 +0100 Subject: [PATCH] Initial commit --- .github/workflows/build.yml | 32 +++++++++++++++++++ README.md | 15 +++++++++ app/Dockerfile | 12 +++++++ app/go.mod | 3 ++ app/main.go | 32 +++++++++++++++++++ infra/helm/.helmignore | 23 ++++++++++++++ infra/helm/Chart.yaml | 24 ++++++++++++++ infra/helm/templates/_helpers.tpl | 47 ++++++++++++++++++++++++++++ infra/helm/templates/deployment.yaml | 32 +++++++++++++++++++ infra/helm/templates/service.yaml | 15 +++++++++ infra/helm/values.yaml | 18 +++++++++++ infra/spacelift/run.yaml | 10 ++++++ infra/spacelift/stack.yaml | 27 ++++++++++++++++ infra/tf/.terraform.lock.hcl | 36 +++++++++++++++++++++ infra/tf/main.tf | 3 ++ infra/tf/provider.tf | 3 ++ infra/tf/s3.tf | 10 ++++++ 17 files changed, 342 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 README.md create mode 100644 app/Dockerfile create mode 100644 app/go.mod create mode 100644 app/main.go create mode 100644 infra/helm/.helmignore create mode 100644 infra/helm/Chart.yaml create mode 100644 infra/helm/templates/_helpers.tpl create mode 100644 infra/helm/templates/deployment.yaml create mode 100644 infra/helm/templates/service.yaml create mode 100644 infra/helm/values.yaml create mode 100644 infra/spacelift/run.yaml create mode 100644 infra/spacelift/stack.yaml create mode 100644 infra/tf/.terraform.lock.hcl create mode 100644 infra/tf/main.tf create mode 100644 infra/tf/provider.tf create mode 100644 infra/tf/s3.tf diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1333985 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,32 @@ +name: Build docker image +on: + push: + branches: + - main +permissions: + contents: read + packages: write +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: ./app + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ghcr.io/spacelift-io/spacelift-operator-demo:latest + ghcr.io/spacelift-io/spacelift-operator-demo:${{ github.sha }} diff --git a/README.md b/README.md new file mode 100644 index 0000000..faebdec --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Deployment + +```shell +# Create a stack +kubectl apply -f infra/spacelift/stack.yaml &&\ +kubectl wait --for=jsonpath='{.status.ready}'=true stack/demo-stack --timeout 1h + +# Trigger a run +kubectl delete --ignore-not-found=true -f infra/spacelift/run.yaml &&\ +kubectl apply -f infra/spacelift/run.yaml &&\ +kubectl wait --for=jsonpath='{.status.argo.health}'=Healthy run/spacelift-operator-demo --timeout 1h + +# Deploy the app +helm upgrade --install operator-demo ./infra/helm/ --set 'image.tag=58de3fcc53659909a9779d3a5ed71aef1959b5a8' +``` diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 0000000..20c2dbb --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,12 @@ +FROM golang:1.21.7 as builder +WORKDIR /build +COPY . . +RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o demo . + +FROM scratch +USER 1000 +COPY --from=builder /build/demo /bin/demo +ENTRYPOINT ["/bin/demo"] + + + diff --git a/app/go.mod b/app/go.mod new file mode 100644 index 0000000..7ffef20 --- /dev/null +++ b/app/go.mod @@ -0,0 +1,3 @@ +module github.com/spacelift-io/spacelift-operator-demo + +go 1.21.7 diff --git a/app/main.go b/app/main.go new file mode 100644 index 0000000..5bca7d0 --- /dev/null +++ b/app/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "errors" + "fmt" + "log" + "net/http" + "os" +) + +func main() { + listenAddr := ":8888" + http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { + log.Println(request.Method, request.URL.String()) + if request.URL.Path != "/" { + writer.WriteHeader(http.StatusNotFound) + return + } + secrets := os.Environ() + body := "" + for i := 0; i < len(secrets); i++ { + body += fmt.Sprintf("%s\n", secrets[i]) + } + _, _ = writer.Write([]byte(body)) + }) + log.Printf("Listening on %s\n", listenAddr) + if err := http.ListenAndServe(listenAddr, nil); err != nil { + if !errors.Is(err, http.ErrServerClosed) { + log.Fatal(err) + } + } +} diff --git a/infra/helm/.helmignore b/infra/helm/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/infra/helm/.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/infra/helm/Chart.yaml b/infra/helm/Chart.yaml new file mode 100644 index 0000000..f422eea --- /dev/null +++ b/infra/helm/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: operator-demo +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.0.0" diff --git a/infra/helm/templates/_helpers.tpl b/infra/helm/templates/_helpers.tpl new file mode 100644 index 0000000..a6b2985 --- /dev/null +++ b/infra/helm/templates/_helpers.tpl @@ -0,0 +1,47 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "operator-demo.name" -}} +{{- default .Chart.Name | 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 "operator-demo.fullname" -}} +{{- $name := default .Chart.Name }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "operator-demo.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "operator-demo.labels" -}} +helm.sh/chart: {{ include "operator-demo.chart" . }} +{{ include "operator-demo.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "operator-demo.selectorLabels" -}} +app.kubernetes.io/name: {{ include "operator-demo.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/infra/helm/templates/deployment.yaml b/infra/helm/templates/deployment.yaml new file mode 100644 index 0000000..8cb7163 --- /dev/null +++ b/infra/helm/templates/deployment.yaml @@ -0,0 +1,32 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "operator-demo.fullname" . }} + labels: + {{- include "operator-demo.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "operator-demo.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "operator-demo.labels" . | nindent 8 }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + envFrom: + - secretRef: + optional: false + name: {{ .Values.app.envFromSecret }} diff --git a/infra/helm/templates/service.yaml b/infra/helm/templates/service.yaml new file mode 100644 index 0000000..047bf56 --- /dev/null +++ b/infra/helm/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "operator-demo.fullname" . }} + labels: + {{- include "operator-demo.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "operator-demo.selectorLabels" . | nindent 4 }} diff --git a/infra/helm/values.yaml b/infra/helm/values.yaml new file mode 100644 index 0000000..5c7957c --- /dev/null +++ b/infra/helm/values.yaml @@ -0,0 +1,18 @@ +replicaCount: 1 +image: + repository: ghcr.io/spacelift-io/spacelift-operator-demo + pullPolicy: IfNotPresent + tag: "" +service: + type: ClusterIP + port: 8888 +livenessProbe: + httpGet: + path: / + port: http +readinessProbe: + httpGet: + path: / + port: http +app: + envFromSecret: stack-output-spacelift-operator-demo diff --git a/infra/spacelift/run.yaml b/infra/spacelift/run.yaml new file mode 100644 index 0000000..5312f2f --- /dev/null +++ b/infra/spacelift/run.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: app.spacelift.io/v1beta1 +kind: Run +metadata: + name: spacelift-operator-demo + annotations: + argocd.argoproj.io/hook: Sync + argocd.argoproj.io/sync-wave: "-1" +spec: + stackName: demo-stack diff --git a/infra/spacelift/stack.yaml b/infra/spacelift/stack.yaml new file mode 100644 index 0000000..1c25024 --- /dev/null +++ b/infra/spacelift/stack.yaml @@ -0,0 +1,27 @@ +apiVersion: app.spacelift.io/v1beta1 +kind: Stack +metadata: + name: demo-stack + annotations: + argocd.argoproj.io/sync-wave: "-2" +spec: + name: spacelift-operator-demo + commitSHA: 58de3fcc53659909a9779d3a5ed71aef1959b5a8 + settings: + administrative: false + space: spacelift-operator-01HR9KQ590MFT6H6ETFJ657KR6 + namespace: spacelift-io + repository: spacelift-operator-demo + projectRoot: infra/tf + branch: main + managesStateFile: true + awsIntegration: + id: 01HRQ4YMJQTP5R6K8Q9N1NB3XM + read: true + write: true + vendorConfig: + terraform: + version: 1.6.2 + workflowTool: OPEN_TOFU + labels: + - argo diff --git a/infra/tf/.terraform.lock.hcl b/infra/tf/.terraform.lock.hcl new file mode 100644 index 0000000..57b15de --- /dev/null +++ b/infra/tf/.terraform.lock.hcl @@ -0,0 +1,36 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.40.0" + hashes = [ + "h1:Z5VaTP8jwXG60IfHLaUIT2T+W0XvKrPWpZyxVmUUdsw=", + "zh:1689604abc131df74ef66839273474ee69a79256655de726242819a19c8d9f40", + "zh:1777da5659cd5a85d078674a7a80239f37397912036cb98e695ef5097d5ff53c", + "zh:216a63569d03e8fd1785dce59ceab182c84cf60dec6080e52e4d8e4e8be10cf3", + "zh:29ef1afbc819c5f52818f76ec1232f424a1502294774e32405c6c5e81e189331", + "zh:4bd44590ff060fac4b776c276f914a0d2225e78ec8a1cf83ea4236b0b29c7cbb", + "zh:75cceb4d9fa1736bd3969c7df2d477272f2187ff2f321fb2240a76e99b0e1f30", + "zh:c8938042376000ee904abddb8756533f2f4d861313cd4b99833df860ff0ed5f7", + "zh:eafe59e7fd68fb8d814a81c6139bd9463874e85f252ffefc9eb696c2e4828de6", + "zh:eef0ed78b52050afdd07563fcb2a0a49c9651edaf45f5810be71d60b141bb13c", + "zh:ff169ae274cd3cde075a9d3bfc2c6555d6ab40d6f9ced73ef14d31ef4ee58779", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.0" + hashes = [ + "h1:6QMZ6JACl+V2t8daN5GTlw22EtG7nhc3BbkbJDw2a5M=", + "zh:486a1c921eab5c51a480f2eb0ad85173f207c9b7bb215f3893e58bc38d3b7c75", + "zh:6901b3afa4607d1e31934ba91ed2625215ada42b3518c3a9adeeac7a5f656dc3", + "zh:7e93752c9de710e417191353ad1a41b5a60432ab7ef4f8b556bf248297ec5e23", + "zh:c795d3d319e8ee7be972746b935963b7e772a6a14080261a35c03915c1f9ccb2", + "zh:cd4f8bcaf332828d1736c73874549c25e427737f136173c7b61e2df3db50e5d9", + "zh:e0103eb2e280989c3d9ffda5d6b413e8f583be21bc1d5754c6e9ca87ecc1c44a", + "zh:f4fbec2510322d5b7ad584a92436b5dbd0f2e897a3ec538932af59e245a4c8e4", + "zh:f5418842afd4aa7676e2456e425e8f573cb2b9bffd29bd7de09d91845644ab24", + "zh:f572a26f93d00ec42461ce478678366e570fa4497e2273f9d47f24cdfc4b42b4", + "zh:ff1f07c561a3f7f219b6fee1647a559933b5dd6181753e164c3978fd47a11685", + ] +} diff --git a/infra/tf/main.tf b/infra/tf/main.tf new file mode 100644 index 0000000..fb236b6 --- /dev/null +++ b/infra/tf/main.tf @@ -0,0 +1,3 @@ +output "BUCKET_URL" { + value = "https://${aws_s3_bucket.bucket.bucket_regional_domain_name}" +} diff --git a/infra/tf/provider.tf b/infra/tf/provider.tf new file mode 100644 index 0000000..e62fc36 --- /dev/null +++ b/infra/tf/provider.tf @@ -0,0 +1,3 @@ +provider "aws" { + region = "eu-west-1" +} diff --git a/infra/tf/s3.tf b/infra/tf/s3.tf new file mode 100644 index 0000000..ddfc3e4 --- /dev/null +++ b/infra/tf/s3.tf @@ -0,0 +1,10 @@ +resource "random_string" "random" { + length = 6 + special = false + numeric = false + upper = false +} + +resource "aws_s3_bucket" "bucket" { + bucket = "bucket-${random_string.random.result}" +}