Update build-test-deploy.yml #650
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build test and deploy DHCR | |
env: | |
DOCKER_TAG: ${{ secrets.DOCKER_TAG }} | |
on: | |
push: {} | |
repository_dispatch: | |
types: [run] | |
jobs: | |
build: | |
name: Build Docker image from the branch ${{ github.ref_name }} | |
runs-on: ubuntu-22.04 | |
environment: ${{ github.ref_name }} | |
permissions: | |
packages: write | |
contents: read | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 10 | |
submodules: "true" | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Create tags based on git data | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.DOCKER_TAG }}/${{ github.ref_name }} | |
tags: | | |
type=ref,event=branch | |
type=ref,event=pr | |
type=semver,pattern={{version}} | |
type=semver,pattern={{major}}.{{minor}} | |
type=raw,value=latest,enable={{is_default_branch}} | |
type=raw,value={{sha}} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Set up pack | |
uses: buildpacks/github-actions/[email protected] | |
- name: Build using heroku/buildpacks:22 CNB | |
env: | |
SECRETS_CONTEXT: ${{ toJson(secrets) }} | |
VARS_CONTEXT: ${{ toJson(vars) }} | |
run: | | |
echo -n "$SECRETS_CONTEXT" | jq -r '[to_entries[]|select(.key|startswith("K8S_SECRET_"))]|map("\(.key|sub("K8S_SECRET_"; ""))=\(.value|tostring)")|.[]' > secrets.env | |
echo -n "$VARS_CONTEXT" | jq -r '[to_entries[]|select(.key|startswith("K8S_SECRET_"))]|map("\(.key|sub("K8S_SECRET_"; ""))=\(.value|tostring)")|.[]' >> secrets.env | |
echo -n "$SECRETS_CONTEXT" | jq -r '[to_entries[]|select(.key|startswith("LC_K8S_SECRET_"))]|map("\(.key|sub("LC_K8S_SECRET_"; "")|ascii_downcase)=\(.value|tostring)")|.[]' >> secrets.env | |
echo -n "$VARS_CONTEXT" | jq -r '[to_entries[]|select(.key|startswith("LC_K8S_SECRET_"))]|map("\(.key|sub("LC_K8S_SECRET_"; "")|ascii_downcase)=\(.value|tostring)")|.[]' >> secrets.env | |
pack build ${{ env.DOCKER_TAG }}/${{ github.ref_name }}/source --env-file secrets.env --builder heroku/builder:22 \ | |
--cache-image ${{ env.DOCKER_TAG }}/${{ github.ref_name }}/source:cache --publish | |
rm secrets.env | |
cat > Dockerfile <<EOF | |
FROM ${{ env.DOCKER_TAG }}/${{ github.ref_name }}/source | |
ENV PORT=5000 | |
EXPOSE 5000 | |
EOF | |
- name: Build and push to ghcr.io | |
uses: docker/build-push-action@v5 | |
with: | |
context: . | |
build-args: | | |
default_port=5000 | |
source_image=${{ env.DOCKER_TAG }}/${{ github.ref_name }}/source | |
platforms: linux/amd64 | |
push: true | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
test: | |
name: Test code from the branch ${{ github.ref_name }} | |
runs-on: ubuntu-22.04 | |
environment: ${{ github.ref_name }} | |
steps: | |
- name: checkout | |
uses: actions/checkout@v4 | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Run tests using heroku buildpack | |
run: | | |
cat <<EOF > Dockerfile | |
FROM gliderlabs/herokuish | |
COPY . /tmp/app | |
ENV USER=herokuishuser | |
EOF | |
- name: Build | |
uses: docker/build-push-action@v5 | |
with: | |
context: . | |
platforms: linux/amd64 | |
push: false | |
tags: | | |
${{ env.DOCKER_TAG }}:${{ github.ref_name }}-${{ github.sha }}-test | |
- name: Create test services network | |
run: | | |
docker network create --internal test-services | |
- name: Set up a test database container | |
run: | | |
# The following service is isolated from the internet | |
docker run -d --network test-services -p 3306:3306 --name ${{ secrets.TEST_DB_HOST }} -e MARIADB_SKIP_TEST_DB=yes -e ALLOW_EMPTY_PASSWORD=yes -e MARIADB_USER=${{ secrets.TEST_DB_USER }} -e MARIADB_PASSWORD=${{ secrets.TEST_DB_PASS }} -e MARIADB_DATABASE=${{ secrets.TEST_DB_NAME }} bitnami/mariadb:latest | |
- name: Run tests using herokuish and heroku buildpack (DB credentials in multiple variables) | |
# This is a bit more elaborate so the container has access to the internet via the host | |
# and in addition to the test services network which is isolated from the internet | |
run: | | |
cid=$(docker create -t -e TEST_DB_HOST=${{ secrets.TEST_DB_HOST }} -e TEST_DB_NAME=${{ secrets.TEST_DB_NAME }} -e DB_USER=${{ secrets.TEST_DB_USER }} -e DB_PASS=${{ secrets.TEST_DB_PASS }} -e MAIL_SMTP_HOST=${{ secrets.TEST_MAIL_SMTP_HOST }} -e MAIL_SMTP_PORT=${{ secrets.TEST_MAIL_SMTP_PORT }} -e MAIL_SMTP_USER=${{ secrets.TEST_MAIL_SMTP_USER }} -e MAIL_SMTP_PASS=${{ secrets.TEST_MAIL_SMTP_PASS }} -e APP_MAIL_DEFAULT_FROM=${{ secrets.K8S_SECRET_APP_MAIL_DEFAULT_FROM }} -e APP_MAIL_DEFAULT_REPLY_TO=${{ secrets.K8S_SECRET_APP_MAIL_DEFAULT_REPLY_TO }} -e APP_MAIL_DEFAULT_CC=${{ secrets.K8S_SECRET_APP_MAIL_DEFAULT_CC }} -e DEBUG_MAIL_TO=${{ secrets.K8S_SECRET_DEBUG_MAIL_TO }} ${{ env.DOCKER_TAG }}:${{ github.ref_name }}-${{ github.sha }}-test /bin/herokuish buildpack test) | |
docker network connect test-services $cid | |
docker start -i $cid | |
deploy: | |
needs: [build, test] | |
name: Deploy Docker image from the branch ${{ github.ref_name }} | |
runs-on: 'ubuntu-latest' | |
environment: ${{ github.ref_name }} | |
env: | |
SECRETS_CONTEXT: ${{ toJson(secrets) }} | |
steps: | |
- uses: actions/checkout@v4 | |
name: Checkout | |
- name: Kubernetes credentials | |
run: | | |
mkdir ${HOME}/.kube | |
echo ${{ secrets.C2_KUBE_CONFIG }} | base64 --decode > ${HOME}/.kube/config | |
chmod 0600 ${HOME}/.kube/config | |
KUBE_NAMESPACE="${{ secrets.KUBE_NAMESPACE }}" | |
if [ "$KUBE_NAMESPACE"x == 'x' ] | |
then KUBE_NAMESPACE="${{ inputs.APP_NAME }}-${{ github.ref_name }}" | |
fi | |
echo "KUBE_NAMESPACE=$KUBE_NAMESPACE" >> $GITHUB_ENV | |
kubectl config set-context --current --namespace=${{ secrets.KUBE_NAMESPACE }} | |
kubectl get pod | |
- name: Create tags based on git data | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.DOCKER_TAG }}/${{ github.ref_name }} | |
tags: | | |
type=raw,value={{sha}} | |
- name: Create auto-deploy-app-values.yaml | |
run: | | |
docker_tag="${{ steps.meta.outputs.tags }}" | |
repository=${docker_tag/:*/} | |
tag=${docker_tag/*:/} | |
echo "repository: $repository" | |
echo "tag: $tag" | |
cat > auto-deploy-app-values.yaml <<EOF | |
replicaCount: 1 | |
image: | |
repository: $repository | |
tag: "latest" | |
pullPolicy: Always | |
extraLabels: | |
"ID": "${{ secrets.SERVICE_ID }}" | |
github: | |
app: ${{ secrets.APP_NAME }} | |
envURL: ${{ github.repositoryUrl }} | |
service: | |
enabled: true | |
name: ${{ secrets.APP_NAME }}-${{ github.ref_name }} | |
url: ${{ secrets.PUBLIC_URL }} | |
type: ClusterIP | |
externalPort: 5000 | |
internalPort: 5000 | |
ingress: | |
enabled: true | |
path: "/" | |
annotations: | |
cert-manager.io/cluster-issuer: letsencrypt-prod | |
nginx.ingress.kubernetes.io/proxy-connect-timeout: '600' | |
kubernetes.io/ingress.class: "nginx" | |
kubernetes.io/proxy-read-timeout: "3600" | |
EOF | |
if [ '${{ secrets.APP_ROOT }}x' != '/x' ] | |
then echo ' nginx.ingress.kubernetes.io/app-root: ${{ secrets.APP_ROOT }}' >> auto-deploy-app-values.yaml | |
fi | |
cat >> auto-deploy-app-values.yaml <<EOF | |
livenessProbe: | |
path: "${{ secrets.APP_ROOT }}" | |
initialDelaySeconds: 25 | |
timeoutSeconds: 30 | |
scheme: "HTTP" | |
probeType: "httpGet" | |
readinessProbe: | |
path: "${{ secrets.APP_ROOT }}" | |
initialDelaySeconds: 15 | |
timeoutSeconds: 30 | |
scheme: "HTTP" | |
probeType: "httpGet" | |
EOF | |
- name: 'Save config for debugging' | |
uses: actions/upload-artifact@v4 | |
with: | |
name: auto-deploy-yamls | |
path: | | |
auto-deploy-app-values.yaml | |
retention-days: 5 | |
- name: Set environment variables | |
env: | |
SECRETS_CONTEXT: ${{ toJson(secrets) }} | |
run: | | |
cat > secrets.yaml <<EOF | |
apiVersion: v1 | |
kind: Secret | |
metadata: | |
name: ${{ secrets.APP_NAME }}-${{ github.ref_name }} | |
type: Opaque | |
data: | |
EOF | |
k8s_secrets=$(echo -n "$SECRETS_CONTEXT" | jq -r '[to_entries[]|select(.key|startswith("K8S_SECRET_"))]|map(" \(.key|sub("K8S_SECRET_"; "")): \(.value|tostring|@base64)")|.[]') | |
if [ "$k8s_secrets"x == 'x' ] | |
then echo ' {}' >> secrets.yaml | |
else echo "$k8s_secrets" >> secrets.yaml | |
fi | |
kubectl replace -f secrets.yaml -n "${{ secrets.KUBE_NAMESPACE }}" --force | |
rm secrets.yaml | |
- name: Deploy using helm and the local helm chart | |
env: | |
SECRETS_CONTEXT: ${{ toJson(secrets) }} | |
run: | | |
helm upgrade "${{ secrets.APP_NAME }}-${{ github.ref_name }}" \ | |
--values auto-deploy-app-values.yaml --install --atomic --wait \ | |
--set application.secretName="${{ secrets.APP_NAME }}-${{ github.ref_name }}" ${{ secrets.HELM_UPGRADE_EXTRA_ARGS }} \ | |
.github/auto-deploy-app |