Skip to content

Commit 961355c

Browse files
authored
Gitlab CI experiment (#221)
* Example GitLab CI/CD pipeline --------- Signed-off-by: Federico Busetti <[email protected]>
1 parent 76002d3 commit 961355c

File tree

7 files changed

+229
-0
lines changed

7 files changed

+229
-0
lines changed

.gitlab-ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include:
2+
- local: .gitlab_ci/base.yml

.gitlab_ci/_templates.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
variables:
2+
DOCKER_IMAGE_TAG: $CI_COMMIT_SHA
3+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME
4+
DOCKER_IMAGE_FULL_TAG: $CI_REGISTRY_IMAGE/$DOCKER_IMAGE_NAME:$DOCKER_IMAGE_TAG
5+
DOCKER_VERSION: 27.4
6+
7+
.docker-gitlab-login: &docker-gitlab-login
8+
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
9+
10+
# Build Docker image for test
11+
# TODO: Sign image using Cosign
12+
.build-and-push-gitlab:
13+
image: docker:$DOCKER_VERSION
14+
services:
15+
- docker:$DOCKER_VERSION-dind
16+
variables:
17+
DOCKER_BUILDKIT: 1
18+
DOCKER_PLATFORM: ""
19+
DOCKER_TARGET: ""
20+
DOCKER_CACHE_FULL_TAG: $CI_REGISTRY_IMAGE/$DOCKER_IMAGE_NAME:cache
21+
before_script:
22+
- apk add --no-cache bash git
23+
script:
24+
- docker buildx create --use
25+
- docker buildx inspect --bootstrap
26+
- *docker-gitlab-login
27+
- echo "Building $DOCKER_IMAGE_FULL_TAG - Cache from $DOCKER_CACHE_FULL_TAG"
28+
- if [[ -n "$DOCKER_TARGET" ]]; then export TARGET_ARG="--target $DOCKER_TARGET"; fi;
29+
- if [[ -n "$DOCKER_PLATFORM" ]]; then export PLATFORM_ARG="--platform $DOCKER_PLATFORM"; fi;
30+
- if [[ -n "$DOCKER_PLATFORM" ]]; then export PLATFORM_SUFFIX="-$(echo $DOCKER_PLATFORM | sed 's/\///')"; fi;
31+
# remove \ from platform variable
32+
- export SUFFIX=$(echo $DOCKER_PLATFORM | sed 's/\///')
33+
- docker buildx build --push
34+
$TARGET_ARG
35+
--tag $DOCKER_IMAGE_FULL_TAG$PLATFORM_SUFFIX
36+
$PLATFORM_ARG
37+
--cache-from type=registry,ref=$DOCKER_CACHE_FULL_TAG
38+
--cache-to type=registry,ref=$DOCKER_CACHE_FULL_TAG
39+
.
40+
41+
# Architectures are hardcoded for multiarch, need to make this better
42+
.multiarch-manifest-gitlab:
43+
image: docker:$DOCKER_VERSION
44+
services:
45+
- docker:$DOCKER_VERSION-dind
46+
script:
47+
- *docker-gitlab-login
48+
- echo "Building $DOCKER_IMAGE_FULL_TAG multiarch manifest"
49+
- docker buildx imagetools create
50+
--tag $DOCKER_IMAGE_FULL_TAG
51+
$DOCKER_IMAGE_FULL_TAG-linuxamd64
52+
$DOCKER_IMAGE_FULL_TAG-linuxarm64
53+
54+
.promote-image:
55+
image: docker:$DOCKER_VERSION
56+
variables:
57+
PROMOTED_ENVIRONMENT: "dev"
58+
DOCKER_BUILDKIT: 1
59+
services:
60+
- docker:$DOCKER_VERSION-dind
61+
script:
62+
- *docker-gitlab-login
63+
# Remove the UTC offset, not supported by `date` in docker image (busybox)
64+
- export CLEAN_DATETIME=$(echo "$CI_JOB_STARTED_AT" | sed 's/+00:00//' | sed 's/Z//')
65+
# Transform in unix timestamp
66+
- export UNIX_TIMESTAMP=$(date -d "$CLEAN_DATETIME" -D "%Y-%m-%dT%H:%M:%S" +%s)
67+
- echo "Unix timestamp - $UNIX_TIMESTAMP"
68+
- echo "Tagging $CI_REGISTRY_IMAGE/$DOCKER_IMAGE_NAME:$PROMOTED_ENVIRONMENT-$UNIX_TIMESTAMP from $DOCKER_IMAGE_FULL_TAG"
69+
- docker buildx imagetools create
70+
--annotation index:org.opencontainers.image.version=$CI_COMMIT_SHORT_SHA
71+
--annotation index:org.opencontainers.image.revision=$CI_COMMIT_SHA
72+
--annotation index:org.opencontainers.image.source=$CI_PROJECT_URL
73+
--annotation index:org.opencontainers.image.created=$CI_JOB_STARTED_AT
74+
--tag $CI_REGISTRY_IMAGE/$DOCKER_IMAGE_NAME:$PROMOTED_ENVIRONMENT-$UNIX_TIMESTAMP
75+
$DOCKER_IMAGE_FULL_TAG
76+
77+
.python-typing:
78+
image: $DOCKER_IMAGE_FULL_TAG
79+
script:
80+
- make typing
81+
82+
.python-lint:
83+
image: $DOCKER_IMAGE_FULL_TAG
84+
script:
85+
- make lint
86+
87+
.python-format:
88+
image: $DOCKER_IMAGE_FULL_TAG
89+
script:
90+
- make format
91+
92+
.python-tests:
93+
image: $DOCKER_IMAGE_FULL_TAG
94+
script:
95+
- make test
96+

.gitlab_ci/base.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
variables:
2+
# Use docker.io for Docker Hub if empty
3+
REGISTRY: registry.gitlab.com
4+
# IMAGE_NAME is defined as <account>/<repo> in GitLab CI/CD
5+
IMAGE_NAME: $CI_REGISTRY_IMAGE
6+
TEST_TAG: $REGISTRY/$CI_PROJECT_PATH:test
7+
8+
stages:
9+
- build
10+
- test
11+
- deploy
12+
13+
include:
14+
- local: /.gitlab_ci/_templates.yml
15+
- local: /.gitlab_ci/build.yml
16+
- local: /.gitlab_ci/test.yml
17+
- local: /.gitlab_ci/deploy.yml

.gitlab_ci/build.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Build Docker image for test
2+
build-test:
3+
stage: build
4+
variables:
5+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-test
6+
DOCKER_TARGET: dev
7+
rules:
8+
# We run the pipeline only on merge requests or the `main` branch
9+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
10+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
11+
extends:
12+
- .build-and-push-gitlab
13+
14+
# TODO: Make the multi-arch build in a single job (perhaps with a nested workflow)
15+
build-http-app-amd64:
16+
stage: build
17+
variables:
18+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-http
19+
DOCKER_PLATFORM: "linux/amd64"
20+
DOCKER_TARGET: http_app
21+
tags:
22+
- saas-linux-small-amd64
23+
rules:
24+
# We run the pipeline only on merge requests or the `main` branch
25+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
26+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
27+
extends:
28+
- .build-and-push-gitlab
29+
30+
build-http-app-arm64:
31+
stage: build
32+
variables:
33+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-http
34+
DOCKER_PLATFORM: "linux/arm64"
35+
DOCKER_TARGET: http_app
36+
tags:
37+
- saas-linux-small-arm64
38+
rules:
39+
# We run the pipeline only on merge requests or the `main` branch
40+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
41+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
42+
extends:
43+
- .build-and-push-gitlab
44+
45+
aggregate-http-manifests:
46+
stage: build
47+
needs:
48+
- build-http-app-amd64
49+
- build-http-app-arm64
50+
variables:
51+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-http
52+
rules:
53+
# We run the pipeline only on merge requests or the `main` branch
54+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
55+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
56+
extends:
57+
- .multiarch-manifest-gitlab
58+

.gitlab_ci/deploy.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
promote-dev:
2+
stage: deploy
3+
variables:
4+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-http
5+
rules:
6+
# We run the pipeline only on merge requests or the `main` branch
7+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
8+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
9+
extends:
10+
- .promote-image
11+
when: manual

.gitlab_ci/test.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Test Docker image
2+
typing:
3+
stage: test
4+
variables:
5+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-test
6+
rules:
7+
# We run the pipeline only on merge requests or the `main` branch
8+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
9+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
10+
extends:
11+
- .python-typing
12+
13+
lint:
14+
stage: test
15+
variables:
16+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-test
17+
rules:
18+
# We run the pipeline only on merge requests or the `main` branch
19+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
20+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
21+
extends:
22+
- .python-lint
23+
24+
format:
25+
stage: test
26+
variables:
27+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-test
28+
rules:
29+
# We run the pipeline only on merge requests or the `main` branch
30+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
31+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
32+
extends:
33+
- .python-format
34+
35+
tests:
36+
stage: test
37+
variables:
38+
DOCKER_IMAGE_NAME: $CI_PROJECT_NAME-test
39+
rules:
40+
# We run the pipeline only on merge requests or the `main` branch
41+
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
42+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
43+
extends:
44+
- .python-tests

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This template provides out of the box some commonly used functionalities:
2525
* Repository pattern for databases using [SQLAlchemy](https://www.sqlalchemy.org/) and [SQLAlchemy bind manager](https://febus982.github.io/sqlalchemy-bind-manager/stable/)
2626
* Database migrations using [Alembic](https://alembic.sqlalchemy.org/en/latest/) (configured supporting both sync and async SQLAlchemy engines)
2727
* Authentication and Identity Provider using [ORY Zero Trust architecture](https://www.ory.sh/docs/kratos/guides/zero-trust-iap-proxy-identity-access-proxy)
28+
* Example CI/CD deployment pipeline for GitLab (The focus for this repository is still GitHub but, in case you want to use GitLab 🤷)
2829
* [TODO] Producer and consumer to emit and consume events using [CloudEvents](https://cloudevents.io/) format on [Confluent Kafka](https://docs.confluent.io/kafka-clients/python/current/overview.html)
2930

3031
## Documentation

0 commit comments

Comments
 (0)