Staging (#63)
* Add/preprod (#61) * Enable preprod and cd on pr * Replace bitnami psql with CNPG * Update env name * Fix build * fix CVE-2026-27135 * Fix main condition * add cleanup * purge old vars * Set vars for build * Add PG_PWD for CNPG * Fix CVE for caddy * Fix caddy build * Fix environment name * Fix namespace * fix domain * Add nonprod domain * Fix sharded buffer * Fix secret * Revert secret * grant creat db for fixture --------- Co-authored-by: ThomasSamson <thomas@samson-pro.fr> * Update storage bucket variables for production and nonprod * fix nonprod trusted host --------- Co-authored-by: ThomasSamson <thomas@samson-pro.fr>
This commit is contained in:
parent
a16da5a39a
commit
c2b3d30640
14 changed files with 214 additions and 61 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -5,7 +5,6 @@ on:
|
|||
|
||||
jobs:
|
||||
build-push-php:
|
||||
environment: PROD
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
|
|
@ -19,7 +18,6 @@ jobs:
|
|||
IMAGE_REPOSITORY: ${{ vars.IMAGE_REPO }}
|
||||
|
||||
build-push-caddy:
|
||||
environment: PROD
|
||||
# Same Dockerfile as php, with a build target which is after
|
||||
needs: [build-push-php]
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
17
.github/workflows/cd.yml
vendored
17
.github/workflows/cd.yml
vendored
|
|
@ -5,6 +5,9 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- main
|
||||
- staging
|
||||
pull_request:
|
||||
types: [ opened, reopened, synchronize, labeled ]
|
||||
workflow_dispatch: ~
|
||||
|
||||
permissions:
|
||||
|
|
@ -14,11 +17,23 @@ permissions:
|
|||
packages: write
|
||||
|
||||
jobs:
|
||||
remove-deploy-label:
|
||||
name: Remove deploy label
|
||||
if: github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: mondeja/remove-labels-gh-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
labels: |
|
||||
deploy
|
||||
build:
|
||||
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy'))
|
||||
name: Build
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
deploy:
|
||||
if: github.event_name != 'pull_request' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy'))
|
||||
name: Deploy
|
||||
needs: [ build ]
|
||||
uses: ./.github/workflows/deploy.yml
|
||||
|
|
@ -30,6 +45,6 @@ jobs:
|
|||
storage-secret-key: ${{ secrets.STORAGE_SECRET_KEY}}
|
||||
project-id: ${{ secrets.PROJECT_ID }}
|
||||
workload-identity-provider: ${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}
|
||||
database-url: ${{ secrets.DATABASE_URL }}
|
||||
pg-password: ${{ secrets.PG_PASSWORD }}
|
||||
mailer-dsn: ${{ secrets.MAILER_DSN }}
|
||||
sms-dsn: ${{ secrets.SMS_DSN }}
|
||||
|
|
|
|||
75
.github/workflows/cleanup.yml
vendored
Normal file
75
.github/workflows/cleanup.yml
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
name: Cleanup
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ closed ]
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
name: Meta
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
context: ${{ steps.meta.outputs.context }}
|
||||
environment: ${{ steps.meta.outputs.environment }}
|
||||
namespace: ${{ steps.meta.outputs.namespace }}
|
||||
|
||||
steps:
|
||||
- name: Generate metadata
|
||||
id: meta
|
||||
run: |
|
||||
set -xo pipefail
|
||||
PROJECT=plateforme-ebs
|
||||
CONTEXT=nonprod
|
||||
ENVIRONMENT=nonprod
|
||||
|
||||
echo "context=${CONTEXT}" >> $GITHUB_OUTPUT
|
||||
echo "environment=${ENVIRONMENT}" >> $GITHUB_OUTPUT
|
||||
echo "namespace=${CONTEXT}-${PROJECT}" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
cleanup:
|
||||
name: Cleanup
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: ${{ needs.meta.outputs.environment }}
|
||||
needs: ["meta"]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: GKE Auth
|
||||
uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
project_id: '${{ secrets.PROJECT_ID }}'
|
||||
workload_identity_provider: '${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}'
|
||||
|
||||
- name: Setup gcloud
|
||||
uses: google-github-actions/setup-gcloud@v1
|
||||
with:
|
||||
project_id: ${{ secrets.PROJECT_ID }}
|
||||
|
||||
- name: Connect cluster
|
||||
run: |
|
||||
gcloud components install gke-gcloud-auth-plugin
|
||||
gcloud auth login --cred-file=$CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE
|
||||
gcloud container clusters get-credentials ${{ vars.CLUSTER_NAME }} --region europe-west1 --project ${{ secrets.PROJECT_ID }}
|
||||
kubectl config view
|
||||
|
||||
- name: Uninstall helm release
|
||||
id: uninstall_helm_release
|
||||
run: |
|
||||
export RELEASE_NAME=pr-$(jq --raw-output .pull_request.number $GITHUB_EVENT_PATH)
|
||||
echo "Uninstalling release $RELEASE_NAME in namespace ${{ needs.meta.outputs.namespace }}..."
|
||||
if ! helm uninstall $RELEASE_NAME --namespace ${{ needs.meta.outputs.namespace }} --wait ; then
|
||||
echo "HELM Uninstall has failed !"
|
||||
echo "Please ask the SRE team to manually clean remaining objects"
|
||||
exit 1
|
||||
fi
|
||||
echo "HELM uninstall successfull"
|
||||
echo "Cleaning remaining PVC..."
|
||||
kubectl delete pvc -l app.kubernetes.io/instance=$RELEASE_NAME --namespace ${{ needs.meta.outputs.namespace }}
|
||||
44
.github/workflows/deploy.yml
vendored
44
.github/workflows/deploy.yml
vendored
|
|
@ -23,6 +23,9 @@ on:
|
|||
required: true
|
||||
database-url:
|
||||
description: Database URL
|
||||
required: false
|
||||
pg-password:
|
||||
description: PostgreSQL password for CNPG cluster
|
||||
required: true
|
||||
mailer-dsn:
|
||||
description: Mailer DSN
|
||||
|
|
@ -55,15 +58,32 @@ jobs:
|
|||
run: |
|
||||
set -xo pipefail
|
||||
PROJECT=${{ vars.PROJECT_NAME }}
|
||||
# Tags are deployed in prod
|
||||
CONTEXT=prod
|
||||
ENVIRONMENT=prod
|
||||
if [[ "${{ github.ref_name }}" == "main" ]]; then
|
||||
# Tags are deployed in prod
|
||||
CONTEXT=prod
|
||||
ENVIRONMENT=prod
|
||||
IMAGE_TAG=${{ github.ref_name }}
|
||||
RELEASE_NAME=prod
|
||||
TRUSTED_HOST=$(echo ${{ vars.DOMAIN }} | sed 's/\./\\\\\\\\./g')
|
||||
URL=${{ vars.DOMAIN }}
|
||||
STORAGE_NAME=${{ vars.PROD_STORAGE_BUCKET }}
|
||||
else
|
||||
CONTEXT=nonprod
|
||||
ENVIRONMENT=nonprod
|
||||
IMAGE_TAG=sha-${GITHUB_SHA::7}
|
||||
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
|
||||
RELEASE_NAME=pr-$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
|
||||
STORAGE_NAME=${{ vars.STORAGE_BUCKET }}-pr
|
||||
else
|
||||
RELEASE_NAME=${{ github.ref_name }}
|
||||
STORAGE_NAME=${{ vars.NONPROD_STORAGE_BUCKET }}-main
|
||||
fi
|
||||
URL=${RELEASE_NAME}.${{ vars.NONPROD_DOMAIN }}
|
||||
TRUSTED_HOST=$(echo ${URL} | sed 's/\./\\\\\\\\./g')
|
||||
fi
|
||||
PHP_IMAGE_REPO=${{ vars.IMAGE_REPO }}/${{ vars.IMAGE_NAME_PHP }}
|
||||
CADDY_IMAGE_REPO=${{ vars.IMAGE_REPO }}/${{ vars.IMAGE_NAME_CADDY }}
|
||||
IMAGE_TAG=sha-${GITHUB_SHA::7}
|
||||
RELEASE_NAME=prod
|
||||
TRUSTED_HOST=$(echo ${{ vars.DOMAIN }} | sed 's/\./\\\\\\\\./g')
|
||||
|
||||
echo "url=${URL}" >> $GITHUB_OUTPUT
|
||||
echo "trusted_host=${TRUSTED_HOST}" >> $GITHUB_OUTPUT
|
||||
echo "context=${CONTEXT}" >> $GITHUB_OUTPUT
|
||||
echo "environment=${ENVIRONMENT}" >> $GITHUB_OUTPUT
|
||||
|
|
@ -72,6 +92,7 @@ jobs:
|
|||
echo "caddy_image_repo=${CADDY_IMAGE_REPO}" >> $GITHUB_OUTPUT
|
||||
echo "release_name=${RELEASE_NAME}" >> $GITHUB_OUTPUT
|
||||
echo "namespace=${CONTEXT}-${PROJECT}" >> $GITHUB_OUTPUT
|
||||
echo "storage_name=${STORAGE_NAME}" >> $GITHUB_OUTPUT
|
||||
|
||||
deploy:
|
||||
name: Deploy
|
||||
|
|
@ -129,15 +150,14 @@ jobs:
|
|||
--set=php.image.tag=${{ needs.meta.outputs.image_tag }} \
|
||||
--set=caddy.image.repository=${{ needs.meta.outputs.caddy_image_repo }} \
|
||||
--set=caddy.image.tag=${{ needs.meta.outputs.image_tag }} \
|
||||
--set=ingress.hosts[0].host=${{ vars.DOMAIN }} \
|
||||
--set=ingress.hosts[0].host=${{ needs.meta.outputs.url }} \
|
||||
--set=ingress.tls[0].secretName=${{ needs.meta.outputs.release_name }}-tls \
|
||||
--set=ingress.tls[0].hosts[0]=${{ vars.DOMAIN }} \
|
||||
--set=postgresql.url="${{ secrets.database-url }}" \
|
||||
--set=postgresql.enabled='${{ github.event_name == 'pull_request' }}' \
|
||||
--set=ingress.tls[0].hosts[0]=${{ needs.meta.outputs.url }} \
|
||||
--set=payum.apikey="${{ secrets.payum-apikey }}" \
|
||||
--set=cnpg.credentials.password="${{ secrets.pg-password }}" \
|
||||
--set=mailer.dsn="${{ secrets.mailer-dsn }}" \
|
||||
--set=sms.dsn="${{ secrets.sms-dsn }}" \
|
||||
--set=php.storage.bucket="${{ vars.STORAGE_BUCKET }}" \
|
||||
--set=php.storage.bucket="${{ needs.meta.outputs.storage_name }}" \
|
||||
--set=php.storage.endpoint="https://storage.googleapis.com" \
|
||||
--set=php.storage.region="eu-west-1" \
|
||||
--set=php.storage.usePathStyleEndpoint=true \
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ RUN yarn build
|
|||
FROM php:${PHP_VERSION}-fpm-alpine AS app_php
|
||||
|
||||
# needed for security update until base image is updated
|
||||
#RUN apk upgrade libcurl curl openssl openssl-dev libressl libcrypto3 libssl3
|
||||
RUN apk upgrade --no-cache libcurl curl openssl openssl-dev libressl libcrypto3 libssl3 nghttp2-libs
|
||||
|
||||
# Allow to use development versions of Symfony
|
||||
ARG STABILITY="stable"
|
||||
|
|
@ -196,6 +196,6 @@ COPY --from=app_php /srv/app/public public/
|
|||
COPY docker/caddy/Caddyfile /etc/caddy/Caddyfile
|
||||
|
||||
# needed for security update until base image is updated
|
||||
#RUN apk upgrade libcurl curl openssl openssl-dev libressl libcrypto1.1 libssl1.1 libcrypto3 libssl3
|
||||
RUN apk upgrade --no-cache libcurl curl openssl openssl-dev libcrypto3 libssl3 nghttp2-libs
|
||||
|
||||
WORKDIR /srv/app
|
||||
|
|
|
|||
|
|
@ -25,11 +25,6 @@ version: 0.0.1
|
|||
appVersion: 0.0.1
|
||||
|
||||
dependencies:
|
||||
# bitnami chart are using the workaround from https://github.com/bitnami/charts/issues/10539
|
||||
- name: postgresql
|
||||
version: ~11.9.13
|
||||
repository: https://charts.bitnami.com/bitnami/
|
||||
condition: postgresql.enabled
|
||||
- name: external-dns
|
||||
version: ~5.4.15
|
||||
repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
{{- if .Values.cnpg.enabled }}
|
||||
IMPORTANT: This chart requires the CloudNativePG operator to be installed in your cluster.
|
||||
helm upgrade --install cnpg --namespace cnpg-system --create-namespace cloudnative-pg/cloudnative-pg
|
||||
See: https://cloudnative-pg.io/documentation/current/installation_upgrade/
|
||||
{{ end }}
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,13 @@ app.kubernetes.io/name: {{ include "plateforme-ebs.name" . }}-pwa
|
|||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
CNPG cluster name
|
||||
*/}}
|
||||
{{- define "plateforme-ebs.cnpgClusterName" -}}
|
||||
{{- printf "%s-postgresql" (include "plateforme-ebs" .) }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
|
|
|
|||
38
helm/chart/templates/cnpg-cluster.yaml
Normal file
38
helm/chart/templates/cnpg-cluster.yaml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{{- if .Values.cnpg.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "plateforme-ebs.cnpgClusterName" . }}-credentials
|
||||
labels:
|
||||
{{- include "plateforme-ebs.labels" . | nindent 4 }}
|
||||
type: kubernetes.io/basic-auth
|
||||
stringData:
|
||||
username: {{ .Values.cnpg.owner | quote }}
|
||||
password: {{ .Values.cnpg.credentials.password | quote }}
|
||||
---
|
||||
apiVersion: postgresql.cnpg.io/v1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: {{ include "plateforme-ebs.cnpgClusterName" . }}
|
||||
labels:
|
||||
{{- include "plateforme-ebs.labels" . | nindent 4 }}
|
||||
spec:
|
||||
instances: {{ .Values.cnpg.instances }}
|
||||
bootstrap:
|
||||
initdb:
|
||||
database: {{ .Values.cnpg.database | quote }}
|
||||
owner: {{ .Values.cnpg.owner | quote }}
|
||||
secret:
|
||||
name: {{ include "plateforme-ebs.cnpgClusterName" . }}-credentials
|
||||
postInitApplicationSQL:
|
||||
- ALTER ROLE {{ .Values.cnpg.owner }} CREATEDB;
|
||||
storage:
|
||||
size: {{ .Values.cnpg.storage.size | quote }}
|
||||
{{- if .Values.cnpg.storage.storageClass }}
|
||||
storageClass: {{ .Values.cnpg.storage.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.cnpg.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -6,8 +6,9 @@ metadata:
|
|||
{{- include "plateforme-ebs.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
database-url: {{ printf "pgsql://%s:%s@%s-postgresql/%s?serverVersion=14&charset=utf8" .Values.postgresql.global.postgresql.auth.username .Values.postgresql.global.postgresql.auth.password .Release.Name .Values.postgresql.global.postgresql.auth.database | b64enc | quote }}
|
||||
{{- if .Values.cnpg.enabled }}
|
||||
database-url: {{ printf "postgresql://%s:%s@%s-rw/%s?serverVersion=%s&charset=utf8" .Values.cnpg.owner .Values.cnpg.credentials.password (include "plateforme-ebs.cnpgClusterName" .) .Values.cnpg.database .Values.cnpg.postgresql.version | b64enc | quote }}
|
||||
cnpg-password: {{ .Values.cnpg.credentials.password | b64enc | quote }}
|
||||
{{- else }}
|
||||
database-url: {{ .Values.postgresql.url | b64enc | quote }}
|
||||
{{- end }}
|
||||
|
|
@ -23,5 +24,5 @@ data:
|
|||
{{- end }}
|
||||
sms-dsn: {{ .Values.sms.dsn | b64enc | quote }}
|
||||
payum-apikey: {{ .Values.payum.apikey | b64enc | quote }}
|
||||
php-storage-key: {{ .Values.php.storage.key | b64enc | quote }}
|
||||
php-storage-secret: {{ .Values.php.storage.secret | b64enc | quote }}
|
||||
php-storage-key: {{ .Values.php.storage.key | default "" | b64enc | quote }}
|
||||
php-storage-secret: {{ .Values.php.storage.secret | default "" | b64enc | quote }}
|
||||
|
|
@ -14,10 +14,9 @@ payum:
|
|||
gateway: 'mollie'
|
||||
apikey: 'test'
|
||||
|
||||
postgresql:
|
||||
auth:
|
||||
# PostgreSQL password is set only the first time chart in installed
|
||||
postgresPassword: change_me
|
||||
cnpg:
|
||||
credentials:
|
||||
password: change_me
|
||||
|
||||
maildev:
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ redis:
|
|||
storageClass: "standard"
|
||||
size: "1Gi"
|
||||
|
||||
postgresql:
|
||||
url: change_me
|
||||
cnpg:
|
||||
credentials:
|
||||
password: change_me
|
||||
|
||||
php:
|
||||
fixtureJob:
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ redis:
|
|||
storageClass: "standard"
|
||||
size: "1Gi"
|
||||
|
||||
postgresql:
|
||||
url: change_me
|
||||
cnpg:
|
||||
credentials:
|
||||
password: change_me
|
||||
|
||||
php:
|
||||
fixtureJob:
|
||||
|
|
|
|||
|
|
@ -69,34 +69,32 @@ mercure:
|
|||
jwtSecret: "!ChangeThisMercureHubJWTSecretKey!"
|
||||
extraDirectives: cors_origins http://ghcr.io https://ghcr.io
|
||||
|
||||
# Full configuration: https://github.com/bitnami/charts/tree/master/bitnami/postgresql
|
||||
postgresql:
|
||||
# CloudNativePG cluster configuration.
|
||||
# The CNPG operator must be pre-installed in the cluster.
|
||||
# See: https://cloudnative-pg.io/documentation/current/installation_upgrade/
|
||||
cnpg:
|
||||
enabled: true
|
||||
# If bringing your own PostgreSQL, the full uri to use
|
||||
# url: postgresql://plateforme-ebs:!ChangeMe!@database:5432/api?serverVersion=13&charset=utf8
|
||||
global:
|
||||
postgresql:
|
||||
auth:
|
||||
username: "example"
|
||||
password: "!ChangeMe!"
|
||||
database: "api"
|
||||
postgresPassword: "!ChangeMe!"
|
||||
# Persistent Volume Storage configuration.
|
||||
# ref: https://kubernetes.io/docs/user-guide/persistent-volumes
|
||||
pullPolicy: IfNotPresent
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: bitnamilegacy/postgresql
|
||||
tag: 14
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: standard
|
||||
size: 1Gi
|
||||
resources:
|
||||
requests:
|
||||
memory: 50Mi
|
||||
cpu: 1m
|
||||
instances: 1
|
||||
postgresql:
|
||||
version: "16"
|
||||
database: app
|
||||
owner: app
|
||||
credentials:
|
||||
# IMPORTANT: use only alphanumeric characters. Special characters (@, #, %, :)
|
||||
# will break the DATABASE_URL parsing by PHP's parse_url().
|
||||
password: "ChangeMe"
|
||||
storage:
|
||||
size: 1Gi
|
||||
storageClass: standard
|
||||
resources:
|
||||
requests:
|
||||
memory: 50Mi
|
||||
cpu: 1m
|
||||
|
||||
# External PostgreSQL URL, used when cnpg.enabled is false.
|
||||
# url: postgresql://app:!ChangeMe!@database:5432/app?serverVersion=16&charset=utf8
|
||||
postgresql:
|
||||
url: ""
|
||||
|
||||
payum:
|
||||
# @see https://my.mollie.com/dashboard/org_XXXXXXXX/developers/api-keys
|
||||
|
|
|
|||
Loading…
Reference in a new issue