diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5ae04d665b08c..c767cc908032e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -275,12 +275,19 @@ jobs: - name: ls artifacts run: ls artifacts + - name: Publish Helm + run: | + set -euxo pipefail + ./scripts/helm.sh --push + mv ./dist/*.tgz ./artifacts/ + - name: Publish Release run: | ./scripts/publish_release.sh \ ${{ (github.event.inputs.dry_run || github.event.inputs.snapshot) && '--dry-run' }} \ ./artifacts/*.zip \ ./artifacts/*.tar.gz \ + ./artifacts/*.tgz \ ./artifacts/*.apk \ ./artifacts/*.deb \ ./artifacts/*.rpm diff --git a/Dockerfile b/Dockerfile index 489c7266485ca..6dcdcc21205bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,4 +14,9 @@ LABEL \ # The coder binary is injected by scripts/build_docker.sh. ADD coder /opt/coder +# Create coder group and user. +RUN addgroup -g 1000 coder && \ + adduser -D -g "" -h /home/coder -G coder -u 1000 -S -s /bin/sh coder +USER coder:coder + ENTRYPOINT [ "/opt/coder", "server" ] diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 0000000000000..0e8a0eb36f4ca --- /dev/null +++ b/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/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000000000..2b73b7c6d641c --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +name: coder +description: Remote development environments on your infrastructure +home: https://github.com/coder/coder + +# version and appVersion are injected at release and will always be shown as +# 0.1.0 in the repository. +type: application +version: "0.1.0" +appVersion: "0.1.0" + +# Coder has a hard requirement on Kubernetes 1.19, as this version introduced +# the networking.k8s.io/v1 API. +kubeVersion: ">= 1.19.0-0" + +keywords: + - coder + - terraform +sources: + - https://github.com/coder/coder/tree/main/helm +icon: https://helm.coder.com/coder_logo_black.png +maintainers: + - name: Coder Technologies, Inc. + email: support@coder.com + url: https://coder.com/contact diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 0000000000000..e723c6f1e9197 --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,33 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "coder.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "coder.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "coder.selectorLabels" -}} +app.kubernetes.io/name: {{ include "coder.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "coder.labels" -}} +helm.sh/chart: {{ include "coder.chart" . }} +{{ include "coder.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000000000..cc4a66839e3ad --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: coder + labels: + {{- include "coder.labels" . | nindent 4 }} +spec: + # NOTE: this is currently not used as coder v2 does not support high + # availability yet. + # replicas: {{ .Values.coder.replicaCount }} + replicas: 1 + selector: + matchLabels: + {{- include "coder.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "coder.selectorLabels" . | nindent 8 }} + spec: + restartPolicy: Always + terminationGracePeriodSeconds: 60 + containers: + - name: coder + image: "{{ .Values.coder.image.repo }}:{{ .Values.coder.image.tag | default (printf "v%v" .Chart.AppVersion) }}" + imagePullPolicy: {{ .Values.coder.image.pullPolicy }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + env: + {{- if .Values.coder.tls.secretName }} + - name: CODER_ADDRESS + value: "0.0.0.0:8443" + - name: CODER_TLS_ENABLE + value: "true" + - name: CODER_TLS_CERT_FILE + value: /etc/ssl/certs/coder/tls.crt + - name: CODER_TLS_KEY_FILE + value: /etc/ssl/certs/coder/tls.key + {{- else }} + - name: CODER_ADDRESS + value: "0.0.0.0:8080" + {{- end }} + {{- with .Values.coder.env -}} + {{ toYaml . | nindent 12 }} + {{- end }} + ports: + {{- if .Values.coder.tls.secretName }} + - name: https + containerPort: 8443 + protocol: TCP + {{- else }} + - name: http + containerPort: 8080 + protocol: TCP + {{- end }} + readinessProbe: + httpGet: + path: /api/v2/buildinfo + port: http + livenessProbe: + httpGet: + path: /api/v2/buildinfo + port: http diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml new file mode 100644 index 0000000000000..84c47d9107da9 --- /dev/null +++ b/helm/templates/service.yaml @@ -0,0 +1,25 @@ +{{- if .Values.coder.service.enable }} +--- +apiVersion: v1 +kind: Service +metadata: + name: coder + labels: + {{- include "coder.labels" . | nindent 4 }} +spec: + type: {{ .Values.coder.service.type }} + ports: + {{- if .Values.coder.tls.secretName }} + - name: https + port: 443 + targetPort: https + protocol: TCP + {{- else }} + - name: http + port: 80 + targetPort: http + protocol: TCP + {{- end }} + selector: + {{- include "coder.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000000000..2090296dc467d --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,71 @@ +# coder -- Primary configuration for `coder server`. +coder: + # NOTE: this is currently not used as coder v2 does not support high + # availability yet. + # # coder.replicaCount -- The number of Kubernetes deployment replicas. + # replicaCount: 1 + + # coder.image -- The image to use for Coder. + image: + # coder.image.repo -- The repository of the image. + repo: "ghcr.io/coder/coder" + # coder.image.tag -- The tag of the image, defaults to {{.Chart.AppVersion}} + # if not set. + tag: "" + # coder.image.pullPolicy -- The pull policy to use for the image. See: + # https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy + pullPolicy: IfNotPresent + + # coder.env -- The environment variables to set for Coder. These can be used + # to configure all aspects of `coder server`. Please see `coder server --help` + # for information about what environment variables can be set. + # + # Note: The following environment variables are set by default and cannot be + # overridden: + # - CODER_ADDRESS: set to 0.0.0.0:80 and cannot be changed. + # - CODER_TLS_ENABLE: set if tls.secretName is not empty. + # - CODER_TLS_CERT_FILE: set if tls.secretName is not empty. + # - CODER_TLS_KEY_FILE: set if tls.secretName is not empty. + env: + - name: CODER_ACCESS_URL + value: "https://coder.example.com" + #- name: CODER_PG_CONNECTION_URL + # value: "postgres://coder:password@postgres:5432/coder?sslmode=disable" + + # coder.tls -- The TLS configuration for Coder. + tls: + # coder.tls.secretName -- The name of the secret containing the TLS + # certificate. The secret should exist in the same namespace as the Helm + # deployment and should be of type "kubernetes.io/tls". The secret will be + # automatically mounted into the pod if specified, and the correct + # "CODER_TLS_*" environment variables will be set for you. + secretName: "" + + # coder.resources -- The resources to request for Coder. These are optional + # and are not set by default. + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + # coder.service -- The Service object to expose for Coder. + service: + # coder.service.enable -- Whether to create the Service object. + enable: true + # coder.service.type -- The type of service to expose. See: + # https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: LoadBalancer + # coder.service.externalTrafficPolicy -- The external traffic policy to use. + # You may need to change this to "Local" to preserve the source IP address + # in some situations. + # https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip + externalTrafficPolicy: Cluster + # coder.service.loadBalancerIP -- The IP address of the LoadBalancer. If not + # specified, a new IP will be generated each time the load balancer is + # recreated. It is recommended to manually create a static IP address in + # your cloud and specify it here in production to avoid accidental IP + # address changes. + loadBalancerIP: "" diff --git a/scripts/helm.sh b/scripts/helm.sh new file mode 100755 index 0000000000000..5978a5f373937 --- /dev/null +++ b/scripts/helm.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +# This script creates a Helm package for the given version. It will output a +# .tgz file at the specified path, and may optionally push it to the Coder OSS +# repo. +# +# ./helm.sh [--version 1.2.3] [--output path/to/coder.tgz] [--push] +# +# If no version is specified, defaults to the version from ./version.sh. +# +# If no output path is specified, defaults to +# "$repo_root/dist/coder_helm_$version.tgz". +# +# If the --push parameter is specified, the resulting artifact will be published +# to the Coder OSS repo. This requires `gsutil` to be installed and configured. + +set -euo pipefail +# shellcheck source=scripts/lib.sh +source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" + +version="" +output_path="" +push=0 + +args="$(getopt -o "" -l version:,output:,push -- "$@")" +eval set -- "$args" +while true; do + case "$1" in + --version) + version="$2" + shift 2 + ;; + --output) + output_path="$(realpath "$2")" + shift 2 + ;; + --push) + push="1" + shift + ;; + --) + shift + break + ;; + *) + error "Unrecognized option: $1" + ;; + esac +done + +# Remove the "v" prefix. +version="${version#v}" +if [[ "$version" == "" ]]; then + version="$(execrelative ./version.sh)" +fi + +if [[ "$output_path" == "" ]]; then + cdroot + mkdir -p dist + output_path="$(realpath "dist/coder_helm_$version.tgz")" +fi + +# Check dependencies +dependencies helm + +# Make a destination temporary directory, as you cannot fully control the output +# path of `helm package` except for the directory name :/ +cdroot +temp_dir="$(mktemp -d)" + +cdroot +cd ./helm +log "--- Packaging helm chart for version $version ($output_path)" +helm package \ + --version "$version" \ + --app-version "$version" \ + --destination "$temp_dir" \ + . 1>&2 + +log "Moving helm chart to $output_path" +cp "$temp_dir"/*.tgz "$output_path" +rm -rf "$temp_dir" + +if [[ "$push" == 1 ]]; then + log "--- Publishing helm chart..." + # TODO: figure out how/where we want to publish the helm chart +fi diff --git a/scripts/version.sh b/scripts/version.sh index 220da35328a27..628fdef3e4ba0 100755 --- a/scripts/version.sh +++ b/scripts/version.sh @@ -15,6 +15,11 @@ set -euo pipefail source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" cdroot +if [[ "${CODER_FORCE_VERSION:-}" != "" ]]; then + echo "$CODER_FORCE_VERSION" + exit 0 +fi + last_tag="$(git describe --tags --abbrev=0)" version="$last_tag"
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: