This repo contains a series of templates that is used inside the CI/CD pipeline of Jobtome.
The syntax here is valid for a Gitlab CI setup. Our current version of Gitlab is 14.0.0
At Jobtome, we use GCP as our Cloud provider, hence you can imagine a lot of pipelines are related/applicable to GCP. Also, we use three main regions for our services, so you will see a lot of references about that distinction.
We manage our GCP infrastructure through Terraform, thus you can find also terraform-related pipeline files. Have a look at our tf GCP modules, too, if you also manage GCP through Terraform!
With Kubernetes:
lint -> build -> test -> push -> manifest -> deploy -> rollback -> notify
With Helm:
lint -> build -> test -> push -> deploy -> verify -> notify
Our workflow:
- A commit on master goes to quality
- A tag on master promotes to production
For kubernetes regional projects:
my-project
|_ src
|_ kube
|_production
\_hpa.yaml
|_quality
\_hpa.yaml
\_deployment.yaml
\_other-files-common-to-prod-and-qa.yaml
.gitlab.ci.yml
...other files
For kubernetes multiregional projects:
my-project
|_ src
|_ kube
|_production
|_production_asia
\_hpa.yaml
|_production_america
\_hpa.yaml
|_production_europe
\_hpa.yaml
|_quality
\_hpa.yaml
\_deployment.yaml
\_other-files-common-to-prod-and-qa.yaml
.gitlab.ci.yml
...other files
For terraform projects:
my-project
|_ platform
\_main.tf
\_output.tf
...
.gitlab.ci.yml
...
Docker:
20.10for tags >v3.x.x;19.03for tags <=v2.39.x
Terraform:
1for tags >v2.39.x;0.12.29for tags <=v2.38.x
According to the operation / the type of pipeline you have to perform, you can pick here different stages, and put the snippet as indicated in your .gitlab-ci.yml:
- Linting
- Tests
- Docker pipeline
- Build
- Test for image vulnerabilities
- Push to registry
- Kubernetes deployment
- Helm deployment
- Helm chart publishing
- SSH command
- Publishing on calendar
- Google bucket upload
- Serverless functions deployment
- Google endpoint
- Google cloud run
- Google dataflow
- Terraform pipeline
- Terraform security check
- Notify sentry of release
Finally some advice on how to try the pipeline (for development).
If you're an operations team, a devops, or if you know very well what you're doing, copy the relevant part from this readme to your .gitlab-ci.yml file. You can also override some operations by overriding the stages or the operation itself.
A note on gitlab-ci syntax:
include: - project: 'group/reponame' ref: v1.0.2 file: 'test-unit.yml'
will import the code from another Gitlab project
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/test-unit.yml'
will import the code from an external repository; notice ref and filename are embedded into the URL.
Throughout the readme, the tag section will be a placeholder.
The stage lint will perform at least 2 checks:
- lint:docker (checks the Dockerfile(s) against good practices)
- lint:yaml (checks the yaml format of the manifests against good practices)
Additionally it will perform the linting of the selected languages. All is needed to do is to specify the file to import as lint-go.yml or lint-php.yml.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/lint-go.yml' stages: - lint variables: # optional, used by docker-lint IGNORE_DOCKER_LINT: "DL3012" # optional, used to enable reviewdog ENABLE_REVIEWDOG: 1 REVIEWDOG_GITLAB_API_TOKEN: <personal gitlab token used to call v4 api endpoints> REVIEWDOG_LEVEL: warning # optional, values: info, warning, error
The Review Dog feature provides a way to post review comments automatically by integrating with any linter tools with ease. It uses an output of lint tools and posts them as a comment if findings are in diff of patches to review.
The default skipped test for lint-docker is Provide an email address or URL as maintainer. See skippable tests here.
If one wants to check the kube manifests (through lint and security practices), then the import becomes test-kubernetes-score.yaml, and it will perform the following:
- lint:kubernetes (checks the object's manifests against their schema)
- test:kubernetes-score (checks the manifests against good practices)
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/test-kubernetes-score.yml' stages: - lint variables: #optional, used by kube-score IGNORE_TESTS: "container-security-context pod-networkpolicy label-values"
Notice by default three kube-score tests are excluded (the ones indicated above). If you want to run it 'strict', do declare IGNORE_TESTS as empty string; otherwise you can avoid declaring it.
See here for skippable tests.
NB: The test label_values needs to be skipped because of the values ${CI_COMMIT_TAG} (which will be replaced by envsubst later in the pipeline) causing validation fail.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/lint-shell.yml' stages: - lint variables: # optional, used to enable reviewdog ENABLE_REVIEWDOG: 1 REVIEWDOG_GITLAB_API_TOKEN: <personal gitlab token used to call v4 api endpoints> REVIEWDOG_LEVEL: warning # optional, values: info, warning, error
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/lint-python.yml' stages: - lint variables: IGNORE_PYTHON_LINT: "E10,D11,I12" #@see https://flake8.pycqa.org/en/latest/user/violations.html
The docker image allows use with reviewdog, like above, but the code has not been added yet. Contributions are welcome
include: remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/test-unit.yml' stages: - test variables: TEST_CONTAINER_NAME: "app" #Default value COMPOSER_FILE_NAME: "docker-compose.test.yml" #Default value
This assumes testing to be done on the containerised application.
This will spin up a docker-compose.test.yml and check the exit code of the container app. If the file is not named docker-compose.test.yml, or the test container is not named app, the variables are there to correct the names.
include: remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/test-api.yml' stages: - test variables: TEST_FOLDER: "tests" #Default value THREADS: "3" #Default value
This will run all the test definitions defined with BDD-syntax into karate
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/docker.yml' stages: - build - test - push variables: IMAGES: "app nginx" STAGES: "build assets" DOCKERFILES_DIR: "docker" SKIP_DOCKER_CACHE: "false" DOCKER_NAME_CONTAINS_BRANCH: "true" #optional
All stages in Docker file should be named (e.g. AS buildes, AS prod...). These need to be added to STAGES variable. IMAGES variable defines the images that will be built, just delete the variable if a single image will be created. In this case the image will be named as CI_REGISTRY_IMAGE, othewise CI_REGISTRY_IMAGE will be a folder containing IMAGES.
DOCKERFILES_DIR is used to specify a different folder containing Dockerfiles instead of the default root directory.
This will spawn a job build and a job build:cache. NOTE: The cache created at pipeline N is used for the pipeline N+1
By enabling the flag DOCKER_NAME_CONTAINS_BRANCH, every branch built (so, by default, a branch which is undergoing MR) will have its own registry image in the following format:
registry.example.com/repo-path/repo-name/branch:tag or registry.example.com/repo-path/repo-name/branch/image:tag (master branch is excluded from this).
This is opposed to the 'usual'
registry.example.com/repo-path/repo-name:tag or
registry.example.com/repo-path/repo-name/image:tag (where classically, image:={app|nginx})
NB: when using this flag, remember that the gitlab's registry cleanup policy happens per-directory and not globally inside a project's registry.
.docker:build:multi template allows building a particular stage of a multi-stage Dockerfile with an optional cache facility. Unlike the other pipeline template, this cache is used within the same pipeline
One can add the following to the .gitlab-ci:
stages:
...
- build-cache # new!
- build
...
# this step should be run before running any other steps so that it results in a cached image that can be re-used in the next build stage
build-cache:
extends: .docker:build:multi
stage: build-cache
variables:
# target stage name
BUILD_TARGET: base
# tag suffix to produce
IMAGE_TAG_SUFFIX: base
build-prod:
extends: .docker:build:multi
stage: build
variables:
# defines the suffix of the cache image
CACHE_FROM: base
BUILD_TARGET: prod
# note, no IMAGE_TAG_SUFFIX defined - this will be the main image in the repo
build-debug:
extends: .docker:build:multi
stage: build
variables:
CACHE_FROM: base
BUILD_TARGET: debug
IMAGE_TAG_SUFFIX: debug
build-nginx:
extends: .docker:build:multi
stage: build
variables:
# note, no CACHE_FROM defined - this will be built without cache
BUILD_TARGET: nginx
IMAGE_TAG_SUFFIX: nginx
In natural language: there's a pipeline stage build-cache where the docker stage is built, and the following build pipeline stage has 3 jobs using the pre-built docker stage.
.docker:build:multi:
extends: .docker
stage: build
#variables:
#### Supported vars
#CACHE_FROM: base
#IMAGE_TAG_SUFFIX: debug
#BUILD_TARGET: prod
NOTE: this job assumes that the Dockerfile is ONE, and in the root of the project.
This job does not override the jobs described above: to remove jobs build and build:cache, add to the .gitlab.ci.yml an override to never run them.
Additionally, this job by default creates a docker image for every branch (see end of previous section)
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/kubernetes-quality.yml' stages: - build - push - manifest - deploy - rollback variables: IMAGES: "app nginx" ROLLOUT_RESOURCES: "deployment/app deployment/worker" # QUALITY VARIABLES GOOGLE_KEY_QUALITY: <google json key> NAMESPACE_QUALITY: "my-namespace" CLUSTER_NAME_QUALITY: quality CLUSTER_ZONE_QUALITY: europe-west6-a SECRET_YAML_QUALITY: <secret base64 encoded> DOMAIN_QUALITY: quality.example.com
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/kubernetes-regional.yml' stages: - build - push - manifest - deploy - rollback variables: IMAGES: "app nginx" ROLLOUT_RESOURCES: "deployment/app" # QUALITY VARIABLES GOOGLE_KEY_QUALITY: <google json key> NAMESPACE_QUALITY: "my-namespace" CLUSTER_NAME_QUALITY: quality CLUSTER_ZONE_QUALITY: europe-west6-a SECRET_YAML_QUALITY: <secret base64 encoded> DOMAIN_QUALITY: quality.example.com # PRODUCTION VARIABLES GOOGLE_KEY_PRODUCTION: <google json key> NAMESPACE_PRODUCTION: "my-namespace" CLUSTER_NAME_PRODUCTION: production-europe-west1 CLUSTER_ZONE_PRODUCTION: europe-west1-b SECRET_YAML_PRODUCTION: <secret base64 encoded> DOMAIN_PRODUCTION: production.example.com
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/kubernetes-multiregion.yml' stages: - build - push - manifest - deploy - rollback variables: IMAGES: "app nginx" ROLLOUT_RESOURCES: "deployment/app" # QUALITY VARIABLES GOOGLE_KEY_QUALITY: <google json key> NAMESPACE_QUALITY: "my-namespace" CLUSTER_NAME_QUALITY: quality CLUSTER_ZONE_QUALITY: europe-west6-a SECRET_YAML_QUALITY: <secret base64 encoded> DOMAIN_QUALITY: quality.example.com # PRODUCTION EUROPE VARIABLES GOOGLE_KEY_PRODUCTION_EUROPE: <google json key> NAMESPACE_PRODUCTION_EUROPE: "my-namespace" CLUSTER_NAME_PRODUCTION_EUROPE: production-europe-west1 CLUSTER_ZONE_PRODUCTION_EUROPE: europe-west1-b SECRET_YAML_PRODUCTION_EUROPE: <secret base64 encoded> DOMAIN_PRODUCTION_EUROPE: eu.production.example.com # PRODUCTION AMERICA VARIABLES GOOGLE_KEY_PRODUCTION_AMERICA: <google json key> NAMESPACE_PRODUCTION_AMERICA: "my-namespace" CLUSTER_NAME_PRODUCTION_AMERICA: production-us-central1 CLUSTER_ZONE_PRODUCTION_AMERICA: us-central1-a SECRET_YAML_PRODUCTION_AMERICA: <secret base64 encoded> DOMAIN_PRODUCTION_AMERICA: am.production.example.com # PRODUCTION ASIA VARIABLES GOOGLE_KEY_PRODUCTION_ASIA: <google json key> NAMESPACE_PRODUCTION_ASIA: "my-namespace" CLUSTER_NAME_PRODUCTION_ASIA: production-asia-east1 CLUSTER_ZONE_PRODUCTION_ASIA: asia-east1-a SECRET_YAML_PRODUCTION_ASIA: <secret base64 encoded> DOMAIN_PRODUCTION_ASIA: as.production.example.com
In order to deploy configmaps at every run (not just after the manual stage of "manifest") one can use this code:
- Remember to add among the
variables:theBEFORE_CUSTOM_APPLY_FILE_PATH: "/tmp/before-manifest.yaml" - Use the following snippet for regional deployments
deploy:quality:image: before_script: - &deployconfig | # DEPLOY CONFIGMAP PHASE if [ -z "${ENVIRONMENT}" ]; then ENVIRONMENT=production fi if [ -z "${KUBERNETES_DIR}" ]; then KUBERNETES_DIR=kube fi envsubst < "${KUBERNETES_DIR}"/"${ENVIRONMENT}"/configmap.yaml >> "${BEFORE_CUSTOM_APPLY_FILE_PATH}" deploy:production:image: before_script: - *deployconfig
If the deployment is not regional but multiregional, use this [NB there are more variables to add in this case, such as ENVIRONMENT_PATH_ASIA; ENVIRONMENT_PATH_EUROPE; ENVIRONMENT_PATH_AMERICA]:
deploy:quality:image: before_script: - &deployconfig | # DEPLOY CONFIGMAP PHASE if [ -z "${ENVIRONMENT}" ]; then ENVIRONMENT=production fi if [ "${ENVIRONMENT}" != "quality" ]; then if [ "${ENVIRONMENT_NAME}" == "production-asia" ]; then ENVIRONMENT="${ENVIRONMENT_PATH_ASIA}" fi if [ "${ENVIRONMENT_NAME}" == "production-europe" ]; then ENVIRONMENT="${ENVIRONMENT_PATH_EUROPE}" fi if [ "${ENVIRONMENT_NAME}" == "production-america" ]; then ENVIRONMENT="${ENVIRONMENT_PATH_AMERICA}" fi fi if [ -z "${KUBERNETES_DIR}" ]; then KUBERNETES_DIR=kube fi envsubst < "${KUBERNETES_DIR}"/"${ENVIRONMENT}"/configmap.yaml >> "${BEFORE_CUSTOM_APPLY_FILE_PATH}" deploy:production:asia:image: before_script: - *deployconfig deploy:production:america:image: before_script: - *deployconfig deploy:production:europe:image: before_script: - *deployconfig
As of version v2.29.1 of the pipelines, Mozilla SOPS has been introduced to take care of secrets inside of repositories (encrypted).
On the human side, don't forget to put git hooks to avoid commit of plaintext secrets.
On the tech side, in order to use this new feature (which is optional), one needs to add in the gitlab variables a SOPS_KEY (a json of a service account with Cloud KMS CryptoKey Decrypter permission on the key), and a SOPS_CONF (containing the .sops.yaml configuration).
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/kubernetes-task-quality.yml' stages: - deploy variables: GOOGLE_PROJECT: my-project # QUALITY VARIABLES NAMESPACE_QUALITY: my-namespace GOOGLE_KEY_QUALITY: <google json key> CLUSTER_NAME_QUALITY: quality-europe-west1 CLUSTER_ZONE_QUALITY: europe-west1-b KUBERNETES_SCRIPT_QUALITY: kupdate statefulset resource-name
If there is only one argument, then the resource type "deployment" is intended. Explicitly give a different resource type e.g. "statefulset" in other cases.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/kubernetes-task-production.yml' stages: - deploy variables: GOOGLE_PROJECT: my-project # QUALITY VARIABLES NAMESPACE_QUALITY: my-namespace GOOGLE_KEY_QUALITY: <google json key> CLUSTER_NAME_QUALITY: quality-europe-west1 CLUSTER_ZONE_QUALITY: europe-west1-b KUBERNETES_SCRIPT_QUALITY: kupdate statefulset resource-name # QUALITY VARIABLES NAMESPACE_QUALITY: my-namespace GOOGLE_KEY_PRODUCTION: <google json key> CLUSTER_NAME_PRODUCTION: production-europe-west1 CLUSTER_ZONE_PRODUCTION: europe-west1-b KUBERNETES_SCRIPT_PRODUCTION: kupdate statefulset resource-name
If there is only one argument, then the resource type "deployment" is intended. Explicitly give a different resource type e.g. "statefulset" in other cases.
Just like k8s, but with some additional variables
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/helm-{quality|regional|multiregion}.yml' stages: - build - push - deploy - verify variables: IMAGES: "app nginx" APP_NAME: "myapp" GOOGLE_PROJECT: "my-project" CHARTS_URL: "https://my-chart-bucket-name.cloudstorage.provider.com" CHART_NAME: "my-app-chart" CHART_VERSION: "1.2.3" #optional, defaults to latest in chart repo # QUALITY VARIABLES CLUSTER_NAME_QUALITY: quality CLUSTER_ZONE_QUALITY: europe-west1-b DOMAIN_QUALITY: quality.example.com NAMESPACE_QUALITY: "my-namespace" # if needed: # PRODUCTION EUROPE VARIABLES ... # PRODUCTION AMERICA VARIABLES ... # PRODUCTION ASIA VARIABLES ...
In addition to these features, starting from v2.29.3 you can enable review app on merge requests by including in the remotes:
- remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/helm-branches.yaml'
and adding as the last stage - stop.
Doing so will create a new helm deployment in QA based on the commit slug when the branch name starts with "feat". Once you're done, the branch deployment will be automatically deleted. This requires also to set up a values.yaml in the helm/feature/ folder (you may juspy quality one as a starting point).
You need to place a helm/feature/values.yaml manifest to be used in helm deployment in feature branches. Initially you can copy/paste quality one, you can customize configmaps here to be review-app specific. You need to pay attention to the following keys:
backendconfig:
enabled: false
frontendconfig:
enabled: true
envFrom:
- envType: secret
envName: secret-environment
- envType: configmap
envName: ${APP_NAME}-environment
configmaps:
- name: ${APP_NAME}-environment
Also remember to add the ingress definition in case the service is normally behind API gateway:
ingress:
enabled: true #NO string
ignoreTest: false #optional, if false
annotations:
kubernetes.io/ingress.class: "gce"
external-dns.alpha.kubernetes.io/hostname: "${DOMAIN}"
external-dns.alpha.kubernetes.io/ttl: "200"
cert-manager.io/cluster-issuer: "production"
acme.cert-manager.io/http01-edit-in-place: "true"
# hosts:
# - host: chart-example.local
# paths: []
tls:
- secretName: "${APP_NAME}-tls"
hosts:
- "${DOMAIN}"
This feature can clone DBs (only MySQL at the moment) provided that:
- You provide DB_USERNAME, DB_PASSWORDd DB_HOSTd DB_NAME or DATABASE_URL (in the format mysql://user:pass@dbhost/dbname) inside the proper GITLAB CI/CD SECRET or SOPS secret
- The quality database user has CRUD and CREATE/DROP permissions
You can also create a feature branch specific secret as a Gitlab CI/CD variable called SECRET_YAML_FEATURE, or an even more specific secret defined in gitlab-ci.yml as SECRET_BRANCH=whateverspecificsecretyouwant. Just please, use a a different "name:" for the configmap and the secrets, in order to avoid overwriting quality ones when appropriate.
Branch domain and app name can be overriden in gitlab-ci.yml using these variables:
DOMAIN_BRANCH: "mydomain.tld" APP_NAME_BRANCH: "myapp"
This is for a repository which holds a Helm chart. It is triggered at every tag.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/helm-publish.yml' stages: - push variables: GOOGLE_PROJECT: "my-project" BUCKET_NAME: "my-charts" BUCKET_HEADERS: "Cache-Control:no-cache, max-age=0" BUCKET_PATH: ""
This is for a repository which need to deploy through ssh.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/ssh-production.yml' stages: - deploy variables: SSH_PRIVATE_KEY_QUALITY: <ssh key base64 encoded> SSH_USER_QUALITY: admin SSH_HOST_QUALITY: quality.example.com SSH_COMMAND_QUALITY: ansible-playbook -i quality app.yml' SSH_KNOWN_HOSTS_QUALITY: <known hosts file base64 encoded> DOMAIN_QUALITY: quality.example.com SSH_PRIVATE_KEY_PRODUCTION: <ssh key base64 encoded> SSH_USER_PRODUCTION: admin SSH_HOST_PRODUCTION: production.example.com SSH_COMMAND_PRODUCTION: ansible-playbook -i production app.yml' SSH_KNOWN_HOSTS_PRODUCTION: <known hosts file base64 encoded> DOMAIN_PRODUCTION: production.example.com
We have an internal calendar where we track deployments (and maintenances and incidents through another tool). At the end of the pipeline, this stage is triggered only on success.
We use a 3rd-party tool called GAM for this.
For slack, we use a simple webhook.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/notify.yml' stages: - notify variables: GOOGLE_CALENDAR_ID: <calendar ID> OAUTH2SERVICE: <see gam help> OAUTH2TXT: <see gam help> CLIENTSECRETS: <see gam help> SLACK_WEBHOOK_URL: <url>
Optional customisations:
SLACK_USERNAME
SLACK_NOTIFICATION_FOOTER
SLACK_NOTIFICATION_ICON
SLACK_ICON
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/bucket-production.yml' stages: - deploy variables: GOOGLE_PROJECT: my-project SYNC_MODE: copy DIR_TO_SYNC: public BUCKET_PATH: data GOOGLE_KEY_QUALITY: <google json key> GOOGLE_KEY_PRODUCTION: <google json key> BUCKET_NAME_QUALITY: test.website.com BUCKET_NAME_PRODUCTION: website.com BUCKET_HEADERS_QUALITY: "Cache-Control:no-cache,max-age=0" BUCKET_HEADERS_PRODUCTION: "Cache-Control:public,max-age=3600"
If unset, GOOGLE_PROJECT defaults to my-project
If unset, SYNC_MODE defaults to rsync
If unset, DIR_TO_SYNC defaults to .
If unset, BUCKET_PATH defaults to data
NOTE: if you set "BUCKET_PATH" variable to '' and the "SYNC_MODE" variable is set to rsync you'll lose all bucket data
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/serverless-quality.yml' stages: - deploy variables: RUNTIME: go111 TRIGGER_HTTP: 1 TIMEOUT: 30 ENTRYPOINT: main EXTRA_FLAGS: "--vpc-connector serverless" # In case there are specific flags/features to use # QUALITY VARIABLES SERVICE_ACCOUNT_QUALITY: default FUNCTION_NAME_QUALITY: my-function GOOGLE_KEY_QUALITY: <google json key> REGION_QUALITY: europe-west1 TRIGGER_TOPIC_QUALITY: topic-qa DOMAIN_QUALITY: https://us-central1.cloudfunctions.net/http_function SECRET_YAML_QUALITY: <secret base64 encoded> SECRET_ENV_LIST_QUALITY: "SUPERSECRET=env"
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/serverless-regional.yml' stages: - deploy variables: RUNTIME: go111 TRIGGER_HTTP: 1 TIMEOUT: 30 ENTRYPOINT: main EXTRA_FLAGS: "--vpc-connector serverless" # In case there are specific flags/features to use # QUALITY VARIABLES SERVICE_ACCOUNT_QUALITY: default FUNCTION_NAME_QUALITY: my-function GOOGLE_KEY_QUALITY: <google json key> REGION_QUALITY: europe-west1 TRIGGER_TOPIC_QUALITY: topic-qa DOMAIN_QUALITY: https://us-central1.cloudfunctions.net/http_function SECRET_YAML_QUALITY: <secret base64 encoded> SECRET_ENV_LIST_QUALITY: "SUPERSECRET=env" # PRODUCTION VARIABLES SERVICE_ACCOUNT_PRODUCTION: default FUNCTION_NAME_PRODUCTION: my-function REGION_PRODUCTION: europe-west1 TRIGGER_TOPIC_PRODUCTION: topic GOOGLE_KEY_PRODUCTION: <google json key> DOMAIN_PRODUCTION: https://us-central1.cloudfunctions.net/http_function SECRET_YAML_PRODUCTION: <secret base64 encoded> SECRET_ENV_LIST_PRODUCTION: "SUPERSECRET=env"
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/serverless-multiregional.yml' stages: - deploy variables: RUNTIME: go111 TRIGGER_HTTP: 1 TIMEOUT: 30 ENTRYPOINT: main EXTRA_FLAGS: "--vpc-connector serverless" # In case there are specific flags/features to use # QUALITY VARIABLES SERVICE_ACCOUNT_QUALITY: default FUNCTION_NAME_QUALITY: my-function GOOGLE_KEY_QUALITY: <google json key> REGION_QUALITY: europe-west1 TRIGGER_TOPIC_QUALITY: topic-qa DOMAIN_QUALITY: https://us-central1.cloudfunctions.net/http_function SECRET_YAML_QUALITY: <secret base64 encoded> SECRET_ENV_LIST_QUALITY: "SUPERSECRET=env" # PRODUCTION EUROPE VARIABLES SERVICE_ACCOUNT_PRODUCTION_EUROPE: default FUNCTION_NAME_PRODUCTION_EUROPE: my-function GOOGLE_KEY_PRODUCTION_EUROPE: <google json key> REGION_PRODUCTION_EUROPE: europe-west1 TRIGGER_TOPIC_PRODUCTION_EUROPE: topic-eu DOMAIN_PRODUCTION_EUROPE: https://europe-west1.cloudfunctions.net/http_function SECRET_YAML_PRODUCTION_EUROPE: <secret base64 encoded> SECRET_ENV_LIST_PRODUCTION_EUROPE: "SUPERSECRET=env" # PRODUCTION AMERICA VARIABLES SERVICE_ACCOUNT_PRODUCTION_AMERICA: default FUNCTION_NAME_PRODUCTION_AMERICA: my-function GOOGLE_KEY_PRODUCTION_AMERICA: <google json key> REGION_PRODUCTION_AMERICA: us-central1 TRIGGER_TOPIC_PRODUCTION_AMERICA: topic-am DOMAIN_PRODUCTION_AMERICA: https://us-central1.cloudfunctions.net/http_function SECRET_YAML_PRODUCTION_AMERICA: <secret base64 encoded> SECRET_ENV_LIST_PRODUCTION_AMERICA: "SUPERSECRET=env" # PRODUCTION ASIA VARIABLES SERVICE_ACCOUNT_PRODUCTION_ASIA: default FUNCTION_NAME_PRODUCTION_ASIA: my-function GOOGLE_KEY_PRODUCTION_ASIA: <google json key> REGION_PRODUCTION_ASIA: asia-east2 TRIGGER_TOPIC_PRODUCTION_ASIA: topic-as DOMAIN_PRODUCTION_ASIA: https://asia-east2.cloudfunctions.net/http_function SECRET_YAML_PRODUCTION_ASIA: <secret base64 encoded> SECRET_ENV_LIST_PRODUCTION_ASIA: "SUPERSECRET=env"
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/endpoint.yml' stages: - test - deploy variables: ENDPOINT_FILE: endpoint.yaml GOOGLE_KEY: <google json key>
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/cloudrun-quality.yml' stages: - deploy variables: GOOGLE_KEY_QUALITY: <google json key> GOOGLE_PROJECT: my-project CLUSTER_NAME_QUALITY: "quality" CLUSTER_ZONE_QUALITY: "europe-west1-b" NAMESPACE: my-k8s-namespace-where-cloudrun-is SERVICE_NAME: awesome-service CONNECTIVITY: "external" TIMEOUT: "60s" CONCURRENCY: "80" CPU: "1000m" MEMORY: "128M" MAX_INSTANCES: "3" ENV_QUALITY: "KEY1=value1,KEY2=value2" SECRET_YAML_QUALITY: <some b64 of a secret called myapp-serviceaccounts> SECRET_MOUNTS: "/secrets=myapp-serviceaccounts" CONFIGMAP_PATH_QUALITY: <a path in this repo containing the definition of a configmap called myapp-configmap> CONFIGMAP_MOUNTS: "/configs=myapp-configmap"
Read more detail about how to mount secrets/configmaps here
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/cloudrun-production.yml' stages: - deploy variables: GOOGLE_KEY_QUALITY: <google json key> GOOGLE_KEY_PRODUCTION: <google json key> GOOGLE_PROJECT: my-project CLUSTER_NAME_QUALITY: "quality" CLUSTER_ZONE_QUALITY: "europe-west1-b" CLUSTER_NAME_PRODUCTION: "production" CLUSTER_ZONE_PRODUCTION: "europe-west1-b" NAMESPACE: my-k8s-namespace-where-cloudrun-is SERVICE_NAME: awesome-service CONNECTIVITY: "external" TIMEOUT: "60s" CONCURRENCY: "80" CPU: "1000m" MEMORY: "128M" MAX_INSTANCES: "3" ENV_QUALITY: "KEY1=value1,KEY2=value2" ENV_PRODUCTION: "KEY1=valueProd1,KEY2=valueProd2" SECRET_YAML_QUALITY: <some b64 of a secret called myapp-serviceaccounts> SECRET_YAML_PRODUCTION: <some b64 of a secret called myapp-serviceaccounts> SECRET_MOUNTS: "/secrets=myapp-serviceaccounts" CONFIGMAP_PATH_QUALITY: <a path in this repo containing the definition of a configmap called myapp-configmap> CONFIGMAP_PATH_PRODUCTION: <a path in this repo containing the definition of a configmap called myapp-configmap> CONFIGMAP_MOUNTS: "/configs=myapp-configmap"
Read more detail about how to mount secrets/configmaps here
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/dataflow-production.yml' stages: - deploy variables: GOOGLE_PROJECT: my-project GOOGLE_KEY_QUALITY: <google json key> TEMPLATE_NAME_QUALITY: my-template STAGING_LOCATION_QUALITY: gs://bucket TEMPORARY_LOCATION_QUALITY: gs://bucket TEMPLATE_LOCATION_QUALITY: gs://bucket EXTRA_ARGUMENTS_QUALITY: "--args1=value1 --args2=value2" GOOGLE_KEY_PRODUCTION: <google json key> TEMPLATE_NAME_PRODUCTION: my-template STAGING_LOCATION_PRODUCTION: gs://bucket TEMPORARY_LOCATION_PRODUCTION: gs://bucket TEMPLATE_LOCATION_PRODUCTION: gs://bucket EXTRA_ARGUMENTS_PRODUCTION: "--args1=value1 --args2=value2"
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/terraform.yml' cache: paths: - "${TF_FOLDER_PATH}/.terraform" variables: TF_FOLDER_PATH: platform stages: - validate - test - build - deploy
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/test-terraform-security.yml' stages: - test
It could be useful to have a script executed through a pipeline. This enables code reviews, programmatic execution (of the script, and of checks beforehands), and avoids 'works on my machine' cases. Our most prominent use-case is when we have to work on the terraform state.
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/shell-job.yml' stages: - lint - deploy
NOTE:
- the file does not need to be executable, the pipeline will do
chmod +x - the script name to be launched (e.g.
test-script.sh) MUST be passed as variable with nameSCRIPT_NAMEin the 'manual' deploy phase (see picture). If the script needs it, a variableARGUMENTScan also be passed. The receiving script must know how to use them!
include: - remote: 'https://raw.githubusercontent.com/jobtome-labs/ci-templates/<REF>/sentry.yml' stages: - notify variables: SENTRY_AUTH_TOKEN: my-sentry-user-token SENTRY_URL: my-sentry.example.net SENTRY_PROJECT: my-sentry-project SENTRY_ORG: my-sentry-org
This stage uses getsentry/sentry-cli:1.52.3, in order to announce a new release as per the docs.
To test stuff in local, try to follow this guide.
In short:
brew install gitlab-runner
Before running the following command, go to your project's settings -> CI/CD, select "runners" and get the info (URL and token) specified at "Set up a specific Runner manually"
gitlab-runner register -> follow the wizard, select docker as your preferred executor type. When asked for a default docker image, pick a random one because it doesn't matter which one.
Now you can go in a project folder on your laptop, and run
gitlab-runner exec docker JOBNAME
This command will look for the .gitlab-ci.yml file and look for the job with the specified name.
It is not possible to run a whole stage. Jobs must be specifed manually
As a consequence, the classic .gitlab-ci.yml file that imports from other yml files (the whole point of this repo) will not work
Notice there is also this guide who doesn't register the runner... ¯\_(ツ)_/¯
