diff --git a/bin/init b/bin/init index 0c23523..c0bd490 100755 --- a/bin/init +++ b/bin/init @@ -88,7 +88,7 @@ gcloud compute routers nats create nat-config \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips \ --min-ports-per-vm=4095 \ - --tcp-established-idle-timeout=60 + --tcp-established-idle-timeout=60 # setup firewall to connect from gke to internal instance vms # https://cloud.google.com/kubernetes-engine/docs/troubleshooting#autofirewall @@ -113,3 +113,26 @@ gcloud projects add-iam-policy-binding ${PROJECT_ID} \ gcloud iam service-accounts add-iam-policy-binding ${CNRM_SA}@${PROJECT_ID}.iam.gserviceaccount.com \ --member="serviceAccount:${PROJECT_ID}.svc.id.goog[${CNRM_SA}/cnrm-controller-manager]" \ --role="roles/iam.workloadIdentityUser" + + + +export PROJECT_ID=$(gcloud config get-value core/project 2>/dev/null) +export CONCOURSE_SA=concourse +export CNRM_SA=cnrm-system +export CLUSTER_NAME=concourse +export PROJECT_REGION=europe-west4-a +gcloud container node-pools create concourse-windows-workers \ + --cluster=$CLUSTER_NAME \ + --location-policy + --machine-type=n1-standard-4 \ + --image-type=WINDOWS_LTSC_CONTAINERD \ + --enable-autoscaling \ + --enable-autoupgrade \ + --num-nodes=1 \ + --min-nodes=1 \ + --max-nodes=2 \ + --local-ssd-count 1 \ + --region "$PROJECT_REGION" \ + --tags=workers \ + --node-taints=workers=true:NoSchedule \ + --service-account=${CONCOURSE_SA}@${PROJECT_ID}.iam.gserviceaccount.com diff --git a/build/concourse/_vendir/templates/_helpers-windows.tpl b/build/concourse/_vendir/templates/_helpers-windows.tpl new file mode 100644 index 0000000..4d980fb --- /dev/null +++ b/build/concourse/_vendir/templates/_helpers-windows.tpl @@ -0,0 +1,8 @@ +{{- define "concourse.windows_worker.fullname" -}} +{{- $name := default "windows-worker" .Values.windows_worker.nameOverride -}} +{{- if .Values.fullnameOverride -}} +{{- printf "%s-%s" .Values.fullnameOverride $name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/build/concourse/_vendir/templates/_helpers.tpl b/build/concourse/_vendir/templates/_helpers.tpl index 9dd402c..3d2fa18 100644 --- a/build/concourse/_vendir/templates/_helpers.tpl +++ b/build/concourse/_vendir/templates/_helpers.tpl @@ -32,6 +32,8 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this {{- end -}} {{- end -}} + + {{/* Create a default fully qualified postgresql name. We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). diff --git a/build/concourse/_vendir/templates/windows-values.yaml b/build/concourse/_vendir/templates/windows-values.yaml new file mode 100644 index 0000000..0bee928 --- /dev/null +++ b/build/concourse/_vendir/templates/windows-values.yaml @@ -0,0 +1,2 @@ +windows_image: foundationalinfrastructure/concourse-windows +windows_imageTag: "latest" diff --git a/build/concourse/_vendir/templates/windows-worker-deployment.yaml b/build/concourse/_vendir/templates/windows-worker-deployment.yaml new file mode 100644 index 0000000..a497a45 --- /dev/null +++ b/build/concourse/_vendir/templates/windows-worker-deployment.yaml @@ -0,0 +1,163 @@ +{{- if .Values.windows_worker.enabled -}} +{{- if eq .Values.windows_worker.kind "Deployment" }} +apiVersion: {{ template "concourse.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "concourse.windows_worker.fullname" . }} + labels: + app: {{ template "concourse.windows_worker.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + {{- if not .Values.concourse.worker.autoscaling.maxReplicas }} + replicas: {{ .Values.windows_worker.replicas }} + {{- end }} + selector: + matchLabels: + app: {{ template "concourse.windows_worker.fullname" . }} + release: "{{ .Release.Name }}" + template: + metadata: + labels: + app: {{ template "concourse.windows_worker.fullname" . }} + release: "{{ .Release.Name }}" + {{- with .Values.windows_worker.labels }} +{{ toYaml . | trim | indent 8 }} + {{- end }} + {{- if .Values.windows_worker.annotations }} + annotations: +{{ toYaml .Values.windows_worker.annotations | indent 8 }} + {{- end }} + spec: + {{- if .Values.windows_worker.nodeSelector }} + nodeSelector: +{{ toYaml .Values.windows_worker.nodeSelector | indent 8 }} + {{- end }} + serviceAccountName: {{ if .Values.rbac.create }}{{ template "concourse.windows_worker.fullname" . }}{{ else }}{{ .Values.rbac.workerServiceAccountName }}{{ end }} + {{- if .Values.windows_worker.tolerations }} + tolerations: +{{ toYaml .Values.windows_worker.tolerations | indent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + {{- if .Values.windows_worker.priorityClassName }} + priorityClassName: {{ .Values.windows_worker.priorityClassName }} + {{- end }} + {{- if .Values.windows_worker.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.windows_worker.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if .Values.windows_worker.extraInitContainers }} + {{- toYaml .Values.windows_worker.extraInitContainers | nindent 8 }} + {{- end }} + containers: + {{- if .Values.windows_worker.sidecarContainers }} + {{- toYaml .Values.windows_worker.sidecarContainers | nindent 8 }} + {{- end }} + - name: {{ template "concourse.windows_worker.fullname" . }} + {{- if .Values.windows_imageDigest }} + image: "{{ .Values.windows_image }}@{{ .Values.windows_imageDigest }}" + {{- else }} + image: "{{ .Values.windows_image }}:{{ .Values.windows_imageTag }}" + {{- end }} + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + args: + - worker +{{- if .Values.windows_worker.livenessProbe }} + livenessProbe: +{{ toYaml .Values.windows_worker.livenessProbe | indent 12 }} +{{- end }} +{{- if .Values.windows_worker.readinessProbe }} + readinessProbe: +{{ toYaml .Values.windows_worker.readinessProbe | indent 12 }} +{{- end }} + env: +{{- include "concourse.worker.env" . | indent 12 }} +{{- if .Values.windows_worker.env }} +{{ toYaml .Values.windows_worker.env | indent 12 }} +{{- end }} + ports: + - name: worker-hc + containerPort: {{ .Values.concourse.worker.healthcheckBindPort }} +{{- if .Values.windows_worker.resources }} + resources: +{{ toYaml .Values.windows_worker.resources | indent 12 }} +{{- end }} + securityContext: + privileged: true + volumeMounts: + - name: concourse-keys + mountPath: {{ .Values.windows_worker.keySecretsPath | quote }} + readOnly: true + {{- if and (not (kindIs "invalid" .Values.secrets.workerAdditionalCerts)) (.Values.secrets.workerAdditionalCerts | toString) }} + - name: worker-additional-certs + mountPath: "{{ .Values.windows_worker.certsPath }}/worker-additional-certs.pem" + subPath: worker-additional-certs.pem + readOnly: true + {{- end }} + +{{- if .Values.windows_worker.additionalVolumeMounts }} +{{ toYaml .Values.windows_worker.additionalVolumeMounts | indent 12 }} +{{- end }} + affinity: +{{- if .Values.windows_worker.additionalAffinities }} +{{ toYaml .Values.windows_worker.additionalAffinities | indent 8 }} +{{- end }} + podAntiAffinity: + {{- if .Values.windows_worker.hardAntiAffinity }} + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: +{{- if .Values.windows_worker.hardAntiAffinityLabels }} +{{ toYaml .Values.windows_worker.hardAntiAffinityLabels | indent 16 }} +{{- else }} + app: {{ template "concourse.windows_worker.fullname" . }} + release: {{ .Release.Name | quote }} +{{- end }} + topologyKey: kubernetes.io/hostname + {{- else }} + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app: {{ template "concourse.windows_worker.fullname" . }} + release: {{ .Release.Name | quote }} + {{- end }} + volumes: +{{- if .Values.windows_worker.additionalVolumes }} +{{ toYaml .Values.windows_worker.additionalVolumes | indent 8 }} +{{- end }} + - name: pre-stop-hook + configMap: + name: {{ template "concourse.worker.fullname" . }} + - name: concourse-keys + secret: + secretName: {{ template "concourse.worker.fullname" . }} + defaultMode: 0400 + items: + - key: host-key-pub + path: host_key.pub + - key: worker-key + path: worker_key + {{- if and (not (kindIs "invalid" .Values.secrets.workerAdditionalCerts)) (.Values.secrets.workerAdditionalCerts | toString) }} + - name: worker-additional-certs + secret: + secretName: {{ template "concourse.worker.fullname" . }} + optional: true + items: + - key: worker-additional-certs + path: worker-additional-certs.pem + {{- end }} + {{- if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion }} + strategy: +{{ toYaml .Values.windows_worker.updateStrategy | indent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/build/concourse/_vendir/templates/windows-worker-statefulset.yaml b/build/concourse/_vendir/templates/windows-worker-statefulset.yaml new file mode 100644 index 0000000..9ce6fa4 --- /dev/null +++ b/build/concourse/_vendir/templates/windows-worker-statefulset.yaml @@ -0,0 +1,222 @@ +{{- if .Values.windows_worker.enabled -}} +{{- if eq .Values.windows_worker.kind "StatefulSet" }} +apiVersion: {{ template "concourse.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "concourse.windows_worker.fullname" . }} + labels: + app: {{ template "concourse.windows_worker.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + serviceName: {{ template "concourse.windows_worker.fullname" . }} + {{- if not .Values.concourse.worker.autoscaling.maxReplicas }} + replicas: {{ .Values.windows_worker.replicas }} + {{- end }} + selector: + matchLabels: + app: {{ template "concourse.windows_worker.fullname" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "concourse.windows_worker.fullname" . }} + release: "{{ .Release.Name }}" + {{- with .Values.windows_worker.labels }} +{{ toYaml . | trim | indent 8 }} + {{- end }} + annotations: + checksum/secrets: {{ include (print $.Template.BasePath "/worker-secrets.yaml") . | sha256sum }} + {{- if .Values.windows_worker.annotations }} +{{ toYaml .Values.windows_worker.annotations | indent 8 }} + {{- end }} + spec: + {{- if .Values.windows_worker.nodeSelector }} + nodeSelector: +{{ toYaml .Values.windows_worker.nodeSelector | indent 8 }} + {{- end }} + serviceAccountName: {{ if .Values.rbac.create }}{{ template "concourse.windows_worker.fullname" . }}{{ else }}{{ .Values.rbac.workerServiceAccountName }}{{ end }} + {{- if .Values.windows_worker.tolerations }} + tolerations: +{{ toYaml .Values.windows_worker.tolerations | indent 8 }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + {{- if .Values.windows_worker.priorityClassName }} + priorityClassName: {{ .Values.windows_worker.priorityClassName }} + {{- end }} + {{- if .Values.windows_worker.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.windows_worker.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.windows_worker.cleanUpWorkDirOnStart }} + initContainers: + {{- if .Values.windows_worker.extraInitContainers }} + {{- toYaml .Values.windows_worker.extraInitContainers | nindent 8 }} + {{- end }} + - name: {{ template "concourse.windows_worker.fullname" . }}-init-rm + {{- if .Values.windows_imageDigest }} + image: "{{ .Values.windows_image }}@{{ .Values.windows_imageDigest }}" + {{- else }} + image: "{{ .Values.windows_image }}:{{ .Values.windows_imageTag }}" + {{- end }} + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + securityContext: + privileged: true + command: + - /bin/bash + args: + - -ce + - |- + for v in $((btrfs subvolume list --sort=-ogen "{{ .Values.windows_worker.workDir }}" || true) | awk '{print $9}'); do + (btrfs subvolume show "{{ .Values.windows_worker.workDir }}/$v" && btrfs subvolume delete "{{ .Values.windows_worker.workDir }}/$v") || true + done + rm -rf "{{ .Values.windows_worker.workDir }}/*" + volumeMounts: + - name: concourse-work-dir + mountPath: {{ .Values.windows_worker.workDir | quote }} + {{- end }} + containers: + {{- if .Values.windows_worker.sidecarContainers }} + {{- toYaml .Values.windows_worker.sidecarContainers | nindent 8 }} + {{- end }} + - name: {{ template "concourse.windows_worker.fullname" . }} + {{- if .Values.windows_imageDigest }} + image: "{{ .Values.windows_image }}@{{ .Values.windows_imageDigest }}" + {{- else }} + image: "{{ .Values.windows_image }}:{{ .Values.windows_imageTag }}" + {{- end }} + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + args: + - worker +{{- if .Values.windows_worker.livenessProbe }} + livenessProbe: +{{ toYaml .Values.windows_worker.livenessProbe | indent 12 }} +{{- end }} +{{- if .Values.windows_worker.readinessProbe }} + readinessProbe: +{{ toYaml .Values.windows_worker.readinessProbe | indent 12 }} +{{- end }} + env: +{{- include "concourse.worker.env" . | indent 12 }} +{{- if .Values.windows_worker.env }} +{{ toYaml .Values.windows_worker.env | indent 12 }} +{{- end }} + ports: + - name: worker-hc + containerPort: {{ .Values.concourse.worker.healthcheckBindPort }} +{{- if .Values.windows_worker.resources }} + resources: +{{ toYaml .Values.windows_worker.resources | indent 12 }} +{{- end }} + securityContext: + privileged: true + volumeMounts: + - name: concourse-keys + mountPath: {{ .Values.windows_worker.keySecretsPath | quote }} + readOnly: true + - name: concourse-work-dir + mountPath: {{ .Values.windows_worker.workDir | quote }} + {{- if and (not (kindIs "invalid" .Values.secrets.workerAdditionalCerts)) (.Values.secrets.workerAdditionalCerts | toString) }} + - name: worker-additional-certs + mountPath: "{{ .Values.windows_worker.certsPath }}/worker-additional-certs.pem" + subPath: worker-additional-certs.pem + readOnly: true + {{- end }} + +{{- if .Values.windows_worker.additionalVolumeMounts }} +{{ toYaml .Values.windows_worker.additionalVolumeMounts | indent 12 }} +{{- end }} + affinity: +{{- if .Values.windows_worker.additionalAffinities }} +{{ toYaml .Values.windows_worker.additionalAffinities | indent 8 }} +{{- end }} + podAntiAffinity: + {{- if .Values.windows_worker.hardAntiAffinity }} + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: +{{- if .Values.windows_worker.hardAntiAffinityLabels }} +{{ toYaml .Values.windows_worker.hardAntiAffinityLabels | indent 16 }} +{{- else }} + app: {{ template "concourse.windows_worker.fullname" . }} + release: {{ .Release.Name | quote }} +{{- end }} + topologyKey: kubernetes.io/hostname + {{- else }} + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app: {{ template "concourse.windows_worker.fullname" . }} + release: {{ .Release.Name | quote }} + {{- end }} + volumes: +{{- if .Values.windows_worker.additionalVolumes }} +{{ toYaml .Values.windows_worker.additionalVolumes | indent 8 }} +{{- end }} + - name: pre-stop-hook + configMap: + name: {{ template "concourse.worker.fullname" . }} + - name: concourse-keys + secret: + secretName: {{ template "concourse.worker.fullname" . }} + defaultMode: 0400 + items: + - key: host-key-pub + path: host_key.pub + - key: worker-key + path: worker_key + {{- if and (not (kindIs "invalid" .Values.secrets.workerAdditionalCerts)) (.Values.secrets.workerAdditionalCerts | toString) }} + - name: worker-additional-certs + secret: + secretName: {{ template "concourse.worker.fullname" . }} + optional: true + items: + - key: worker-additional-certs + path: worker-additional-certs.pem + {{- end }} + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: concourse-work-dir + spec: + {{- if .Values.persistence.worker.selector }} + selector: {{- .Values.persistence.worker.selector | toYaml | nindent 10 }} + {{- end }} + accessModes: + - {{ .Values.persistence.worker.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.worker.size | quote }} + {{- if .Values.persistence.worker.storageClass }} + {{- if (eq "-" .Values.persistence.worker.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.persistence.worker.storageClass }}" + {{- end }} + {{- end }} + {{- else }} + {{ if include "concourse.are-there-additional-volumes.with-the-name.concourse-work-dir" . | not }} + - name: concourse-work-dir + emptyDir: + {{- if .Values.windows_worker.emptyDirSize }} + sizeLimit: {{ .Values.windows_worker.emptyDirSize | quote }} + {{- end }} + {{- end }} + {{- end }} + {{- if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion }} + updateStrategy: +{{ toYaml .Values.windows_worker.updateStrategy | indent 4 }} + {{- end }} + {{- if .Values.windows_worker.podManagementPolicy }} + podManagementPolicy: {{ .Values.windows_worker.podManagementPolicy }} + {{- end }} +{{- end }} +{{- end }} diff --git a/build/concourse/_vendir/values.yaml b/build/concourse/_vendir/values.yaml index ba43215..c71b132 100644 --- a/build/concourse/_vendir/values.yaml +++ b/build/concourse/_vendir/values.yaml @@ -15,6 +15,7 @@ fullnameOverride: ## Concourse image to use in both Web and Worker containers. ## image: concourse/concourse +windows_image: foundationalinfrastructure/concourse-windows ## Concourse image tag. ## ps.: release candidates are published under `concourse/concourse-rc` instead @@ -22,11 +23,13 @@ image: concourse/concourse ## Ref: https://hub.docker.com/r/concourse/concourse/tags/ ## imageTag: "7.8.1" +windows_imageTag: "latest" ## Specific image digest to use in place of a tag. ## Ref: https://kubernetes.io/docs/concepts/configuration/overview/#container-images ## imageDigest: +windows_imageDigest: ## Specify a imagePullPolicy regarding the fetching of container images. ## Ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images @@ -2588,6 +2591,244 @@ worker: ## emptyDirSize: + +## Configuration values for Concourse windows Worker components. +## For more information regarding the characteristics of +## Concourse Workers, see https://concourse-ci.org/concourse-worker.html +## +windows_worker: + + ## Enable or disable the worker component. + ## This can allow users to create web only releases by setting this to false + ## + enabled: false + + ## Selects kind of Deployment. Valid Options are: StatefulSet | Deployment + ## Using Deployment leads to ephemeral workers. Meaning workers do not + ## share state between restarts + ## + kind: StatefulSet + + ## Override the components name (defaults to worker). + ## + nameOverride: + + ## Removes any previous state created in `concourse.worker.workDir`. + ## + cleanUpWorkDirOnStart: true + + ## Number of replicas. + ## + replicas: 2 + + ## Array of extra containers to run alongside the Concourse worker + ## container. + ## + ## Example: + ## + ## - name: myapp-container + ## image: busybox + ## command: ['sh', '-c', 'echo Hello && sleep 3600'] + ## + sidecarContainers: [] + + ## Array of extra initContainers to run alongside the Concourse worker + ## container. + ## + ## Example: + ## - name: myapp-init-container + ## image: busybox + ## command: ['sh', '-c', 'echo Hello && sleep 3600'] + ## + extraInitContainers: [] + + ## Minimum number of workers available after an eviction + ## Ref: https://kubernetes.io/docs/admin/disruptions/ + ## + minAvailable: 1 + + ## Configures the liveness probe used to determine if the Worker component is up. + ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ + ## + livenessProbe: + failureThreshold: 5 + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 3 + httpGet: + path: / + port: worker-hc + + ## Configures the readiness probes. + ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ + ## + readinessProbe: {} + + ## Configure resource requests and limits. + ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: + requests: + cpu: "100m" + memory: "512Mi" + + ## Configure additional environment variables for the + ## worker container(s) + ## + ## Example: + ## + ## - name: CONCOURSE_NAME + ## value: "anything" + ## + env: [] + + ## For managing where secrets should be mounted for worker agents + ## + keySecretsPath: "c:/concourse-keys" + + workDir: "c:/concourse-work-dir" + + ## For managing where additional certs should be added into a worker. + ## You can add additional certs with secrets.workerAdditionalCerts + ## + certsPath: "c:/etc/ssl/certs" + + ## Configure additional volumeMounts for the + ## worker container(s) + ## + ## Example: + ## - name: concourse-baggageclaim + ## mountPath: /baggageclaim + ## + additionalVolumeMounts: [] + + ## Additional Labels to be added to the worker pods. + ## + ## Example: + ## key1: "value1" + ## key2: "value2" + ## + ## Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + labels: {} + + ## Annotations to be added to the worker pods. + ## + ## Example: + ## + ## iam.amazonaws.com/role: arn:aws:iam::123456789012:role/concourse + ## + annotations: {} + + ## Node selector for the worker nodes. + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + ## + nodeSelector: {} + + ## Additional affinities to add to the worker pods. + ## Useful if you prefer to run workers on non-spot instances, for example. + ## + ## Example: + ## + ## nodeAffinity: + ## preferredDuringSchedulingIgnoredDuringExecution: + ## - weight: 50 + ## preference: + ## matchExpressions: + ## - key: spot + ## operator: NotIn + ## values: + ## - "true" + ## + additionalAffinities: {} + + ## Configure additional volumes for the + ## worker container(s). + ## Example: + ## + ## - name: concourse-baggageclaim + ## hostPath: + ## path: /dev/nvme0n1 + ## type: BlockDevice + ## + ## + ## As a special exception, this allows taking over the `concourse-work-dir` + ## volume (from the default emptyDir) if `persistence.enabled` is false: + ## + ## additionalVolumes: + ## - name: concourse-work-dir + ## hostPath: + ## path: /mnt/locally-mounted-fast-disk/concourse + ## type: DirectoryOrCreate + ## + additionalVolumes: [] + + ## Whether the workers should be forced to run on separate nodes. + ## This is accomplished by setting their AntiAffinity with requiredDuringSchedulingIgnoredDuringExecution as opposed to preferred + ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity-beta-feature + ## + hardAntiAffinity: false + + ## Set of labels to use in the hard anti affinity rule. + ## + ## Example: + ## hardAntiAffinity: true + ## hardAntiAffinityLabels: + ## application: concourse + ## + hardAntiAffinityLabels: {} + + ## Tolerations for the worker nodes. + ## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + ## For example: + ## + ## - key: "toleration=key" + ## operator: "Equal" + ## value: "value" + ## effect: "NoSchedule" + ## + tolerations: [] + + ## Pod priority class to assign to worker pods. + ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#pod-priority + priorityClassName: + + ## Time to allow the pod to terminate before being forcefully terminated. This should provide time for + ## the worker to retire, i.e. drain its tasks. See https://concourse-ci.org/worker-internals.html for worker + ## lifecycle semantics. + ## + terminationGracePeriodSeconds: 60 + + ## Strategy for StatefulSet updates (requires Kubernetes 1.6+) + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset + ## + ## Strategy for Deployment updates + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + ## + updateStrategy: + type: RollingUpdate +# rollingUpdate: +# maxSurge: 25% +# maxUnavailable: 1 + + ## Pod Management strategy (requires Kubernetes 1.7+) + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + ## "OrderedReady" is default. "Parallel" means worker pods will launch or terminate + ## in parallel. + ## + ## Ignored for Kind Deployment + podManagementPolicy: Parallel + + ## When persistance is disabled this value will be used to limit the emptyDir volume size + ## Ref: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir + ## + ## Example: 20Gi + ## + emptyDirSize: + + ## Persistent Volume Storage configuration. ## Ref: https://kubernetes.io/docs/user-guide/persistent-volumes ## diff --git a/build/concourse/scrub_default_creds.yml b/build/concourse/scrub_default_creds.yml index 5431f4c..8b982a4 100644 --- a/build/concourse/scrub_default_creds.yml +++ b/build/concourse/scrub_default_creds.yml @@ -16,4 +16,4 @@ spec: spec: #@overlay/match by=overlay.subset(None),expects="0+" #@overlay/remove - initContainers: + initContainers: \ No newline at end of file diff --git a/build/concourse/values.yml b/build/concourse/values.yml index 6fb13fa..2e4a58c 100644 --- a/build/concourse/values.yml +++ b/build/concourse/values.yml @@ -77,6 +77,26 @@ worker: nodeSelector: cloud.google.com/gke-local-ssd: "true" cloud.google.com/gke-nodepool: "concourse-workers" + resources: + requests: + cpu: "3000m" + +windows_worker: + enabled: false + replicas: 1 + tolerations: + - key: "workers" + operator: "Equal" + value: "true" + effect: "NoSchedule" + - key: "node.kubernetes.io/os" + operator: "Equal" + value: "windows" + effect: "NoSchedule" + kind: Deployment + nodeSelector: + cloud.google.com/gke-local-ssd: "true" + cloud.google.com/gke-nodepool: "concourse-windows-workers" resources: requests: cpu: "3000m" \ No newline at end of file diff --git a/config/concourse/_ytt_lib/concourse/rendered.yml b/config/concourse/_ytt_lib/concourse/rendered.yml index 187a183..06b9750 100644 --- a/config/concourse/_ytt_lib/concourse/rendered.yml +++ b/config/concourse/_ytt_lib/concourse/rendered.yml @@ -342,6 +342,7 @@ spec: spec: nodeSelector: cloud.google.com/gke-local-ssd: "true" + cloud.google.com/gke-nodepool: concourse-workers serviceAccountName: default tolerations: - effect: NoSchedule @@ -473,3 +474,6 @@ spec: path: worker_key strategy: type: RollingUpdate +--- +windows_image: foundationalinfrastructure/concourse-windows +windows_imageTag: latest diff --git a/docs/windows-workers.md b/docs/windows-workers.md new file mode 100644 index 0000000..f53b88f --- /dev/null +++ b/docs/windows-workers.md @@ -0,0 +1,111 @@ +# Windows Workers +see PR https://github.com/concourse/concourse-chart/pull/317 + +a new concourse version bump (with vendir) wil override our changes made in the following files +`./build/concourse/_vendir/templates/_helpers.tpl` +`./build/concourse/_vendir/templates/windows-worker-deloyment.yml` +`./build/concourse/_vendir/templates/windows-worker-statefullset.yml` +`./build/concourse/_vendir/values.yml` + +## how to create a windows docker container. + +create a windows server +see https://cloud.google.com/compute/docs/create-windows-server-vm-instance +select: + Machine type: `e2-micro` + operating system: `Windows Server` + Version: `Windows Server 2019 DataCenter Core for Containers` + +connecto the vm with rdp also state in the above url + +we currently we use the foundationalinfrastructure account +https://hub.docker.com/repository/docker/foundationalinfrastructure/concourse-windows + +DockerFile + +``` +# escape=` +FROM mcr.microsoft.com/windows/servercore:ltsc2019 as download + +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] + +ENV CONCOURSE_VERSION="7.8.3" + +# Download file +RUN Invoke-WebRequest ('https://github.com/concourse/concourse/releases/download/v{0}/concourse-{0}-windows-amd64.zip' -f $env:CONCOURSE_VERSION) -OutFile 'concourse.zip' -UseBasicParsing ; ` + Expand-Archive concourse.zip -DestinationPath C:\ ; ` + Remove-Item -Path concourse.zip + +# clean env +FROM mcr.microsoft.com/windows/servercore:ltsc2019 + +COPY --from=download C:\concourse\bin\concourse.exe /concourse.exe + + +ENTRYPOINT ["\\concourse.exe"] +``` +docker build -t foundationalinfrastructure/concourse-windows +docker push foundationalinfrastructure/concourse-windows + +## configure concourse for the windows docker container +### create a windows gke node +export the proper enviorment variables e.g. +``` +export PROJECT_ID=$(gcloud config get-value core/project 2>/dev/null) +export CONCOURSE_SA=concourse +export CNRM_SA=cnrm-system +export CLUSTER_NAME=concourse +export PROJECT_REGION=europe-west4-a +``` +``` +gcloud container node-pools create concourse-windows-workers \ + --cluster=$CLUSTER_NAME \ + --machine-type=n1-standard-4 \ + --image-type=WINDOWS_LTSC_CONTAINERD \ + --enable-autoscaling \ + --enable-autoupgrade \ + --num-nodes=1 \ + --min-nodes=1 \ + --max-nodes=2 \ + --local-ssd-count 1 \ + --region "$PROJECT_REGION" \ + --tags=workers \ + --node-taints=workers=true:NoSchedule \ + --service-account=${CONCOURSE_SA}@${PROJECT_ID}.iam.gserviceaccount.com +``` + +## concourse hel chart configuration +add the following to ./build/concourse/values.yml +``` +windows_worker: + enabled: true + replicas: 1 + tolerations: + - key: "workers" + operator: "Equal" + value: "true" + effect: "NoSchedule" + - key: "node.kubernetes.io/os" + operator: "Equal" + value: "windows" + effect: "NoSchedule" + kind: Deployment + nodeSelector: + cloud.google.com/gke-local-ssd: "true" + cloud.google.com/gke-nodepool: "concourse-windows-workers" + resources: + requests: + cpu: "3000m" +``` + +add the following to ./build/concourse/scrub_default_creds.yml +``` +#@overlay/match by=overlay.subset({"kind": "Deployment", "metadata": {"name": "concourse-windows-worker"}}) +--- +spec: + template: + spec: + #@overlay/match by=overlay.subset(None),expects="0+" + #@overlay/remove + initContainers: +``` \ No newline at end of file diff --git a/windows-pipeline.yml b/windows-pipeline.yml new file mode 100644 index 0000000..663c993 --- /dev/null +++ b/windows-pipeline.yml @@ -0,0 +1,12 @@ +jobs: +- name: test-windows + serial: true + plan: + - task: get-help + config: + platform: windows + run: + path: powershell + args: + - -c + - Get-Help Get-Help -Full \ No newline at end of file