I have three jobs:
job a: cache things in directory a/
job b: needs things from directory a/ and cache things in directory b/
job c: needs things from both directories
According to the GitLab CI caching documentation, we can have a maximum of 4 caches, so I tried this:
a:
cache:
key:
files:
- a.txt
paths:
- a/
policy: pull-push
script:
- mkdir a/
- echo "A" > a/a.txt
b:
needs: [a]
cache:
- key:
files:
- b.txt
paths:
- b/
policy: pull-push
- key:
files:
- a.txt
paths:
- a/
policy: pull
script:
- mkdir b/
- echo "B" > b/b.txt
- cat a/a.txt >> b/b.txt
c:
needs: [b]
cache:
- key:
files:
- b.txt
paths:
- b/
policy: pull
- key:
files:
- a.txt
paths:
- a/
policy: pull
script:
- cat a/*.txt
- cat b/*.txt
It doesn't work because when job b is finished, only the b/ directory is in the cache.
Indeed, on the server there is only one archive.zip file which contains only the directory b/. So, what's the aim of multiple caches if only the last pull is left? I thought the cache policy will get specified paths from the archive when pulling and add specified paths when pushing, not replace all the content.
The real directories are vendor/ from composer for job A and node_modules/ from yarn for job B, that's why I want to split them in order to only pull what I need without pushing to save time, but maybe I'm missing something.
I think I misunderstand the aim of key.files. I solved my problem by simply using different key names for my caches.
.a-cache: &a-cache
key: a-cache-$CI_COMMIT_REF_SLUG
paths:
- a/
policy: pull
.b-cache: &b-cache
key: b-cache-$CI_COMMIT_REF_SLUG
paths:
- b/
policy: pull
a:
cache:
- <<: *a-cache
policy: pull-push
script:
- mkdir a/
- echo "A" > a/a.txt
b:
needs: [a]
cache:
- <<: *a-cache
- <<: *b-cache
policy: pull-push
script:
- mkdir b/
- echo "B" > b/b.txt
- cat a/a.txt >> b/b.txt
c:
needs: [b]
cache:
- <<: *a-cache
- <<: *b-cache
script:
- cat a/*.txt
- cat b/*.txt
Related
I want to build a Docker image (tarball) in my GitLab CI pipeline using kaniko, then scan it with trivy and push it to an AWS ECR using kaniko.
Step 1: kaniko build (tarball)
Step 2: trivy scan
Step 3: kaniko push (to AWS ECR!)
Unfortunately I can't find a way to push an existing tarball image with kaniko without rebuilding it.
I also tried crane for the push, but can't get a login due to the non-existent credHelper.
I don't actually want to do big installations, nor do I want to create a custom image for this.
Is this possible? What would be potential solutions?
Coincidentally, I did exactly this a while ago. Here is how I did it:
docker:build:
stage: build
image:
name: Kaniko image
entrypoint: [""]
script:
- mkdir tar_images
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context ${CI_PROJECT_DIR} --no-push --destination $CI_REGISTRY/<image_name>:<image_tag> --tarPath tar_images/$file_name.tar
artifacts:
paths:
- tar_images
when: on_success
# scan all built images
# currently bug with grype as docker registry is not public!
docker:scan:
stage: scan
image:
name: trivy
entrypoint: [""]
script:
- mkdir scan_result
- cd tar_images
- |
for tar_image in *.tar;
do
[ -e "$tar_image" ] || continue;
file_name=${tar_image%.*};
echo $file_name;
if [ "$vulnerability_scanner" = "trivy" ]; then
trivy image --timeout 15m --offline-scan --input $tar_image -f json -o ../scan_result/$file_name.json --severity CRITICAL;
fi
done
artifacts:
paths:
- scan_result
expire_in: 1 month
# push all images without detected security issues
docker:push:
stage: push
image:
name: gcr.io/go-containerregistry/crane:debug
entrypoint: [""]
rules:
- if: $UPDATE
script:
- cd tar_images
- |
for tar_image in *.tar;
do
file_name=${tar_image%.*};
vulnerabilities=`awk -F '[:,]' '/"Vulnerabilities"/ {gsub("[[:blank:]]+", "", $2); print $2}' ../scan_result/$file_name.json`; # find vulnerabilities in json file
if ! [ -z "$vulnerabilities" ]; then # if vulnerabilities found in image
echo "There are security issues with the image $img.Dockerfile. Image is not pushed to registry!";
else # push image
crane auth login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY;
crane push $tar_image $CI_REGISTRY_IMAGE/<image_name>:<image_tag>;
fi
done
What happens here is that in the first job the images are built using kaniko. They are stored as tar files and made accessible to the next job via artifacts. In the next job they are scanned using trivy and the scan results are stored as artifacts. Then the scan reports are analyzed and if no vulnerabilities had been detected the image is pushed using crane.
The code above probably does not work out of the box as I copied it out of a bigger yaml file.
I don't get it. I have two repos. One for infrastructure, and the other for project code. Inside project code, I have .gitlab-ci.yml file that will include one job for creating env variables, another include file that will include other stages inside the job. Every other stage is triggered, but the first include is not triggered no matter what I do. What am I doing wrong?
Project gitlab-ci
# Stages
stages:
- pre-build test
- build
- post-build test
- deploy
- environment
- e2e
# Main Variables
variables:
GIT_SUBMODULE_STRATEGY: normal
IMAGE_VERSION: "latest"
CARGO_HOME: $CI_PROJECT_DIR/.cargo
FF_USE_FASTZIP: "true"
ARTIFACT_COMPRESSION_LEVEL: "fast"
CACHE_COMPRESSION_LEVEL: "fastest"
STAGING_BRANCH: "master"
VARIABLES_FILE: variables.txt
# Include main CI files from infrastructure repository
include:
- project: 'project/repo-one'
ref: master
file: '/gitlab-ci/env/ci-app-env.yml'
- project: 'project/repo-one'
ref: master
file: '/gitlab-ci/app/ci-merge-request.yml'
env ci file
env mr:
stage: .pre
before_script:
- TEST_VAR="TEST"
- IMAGE_PATH="/var/www"
script:
- echo "export TEST_VAR=$TEST_VAR" > $VARIABLES_FILE
- echo "export IMAGE_PATH=$IMAGE_PATH" > $VARIABLES_FILE
- cat $VARIABLES_FILE
artifacts:
paths:
- $VARIABLES_FILE
I am running a local gitlab server with self-signed certificate, My pipline builds my application and create a release but I have x509 I tried the workaround mentionned on gitlab documenation but it doesn't work. Everything works fine when tested in gitlab.com
To summerize first I build my application to generate a war file as an artifact, then the artifact is uploaded using gitlab API to generate URL and file path after that release job add tags and generate the release page
my gitlab-ci.yaml
---
variables:
PACKAGE_VERSION: "V7"
GENERIC_WAR: "mypackage-${PACKAGE_VERSION}.war"
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${CI_PROJECT_NAME}/${PACKAGE_VERSION}"
workflow:
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: always
variables:
SERVER: "${PROD_SERVER}"
- if: $CI_COMMIT_BRANCH == "test"
when: always
variables:
SERVER: "${TEST_SERVER}"
- if: $CI_COMMIT_BRANCH == "feature/release"
when: always
variables:
SERVER: "${TEST_SERVER}"
stages:
- build
- upload
- prepare
- release
- deploy
build-application:
stage: build
image: maven:3.8.4-jdk-8
script:
- mvn clean package -U -DskipTests=true
- echo $CI_COMMIT_TAG
artifacts:
expire_in: 2h
when: always
paths:
- target/*.war
upload:
stage: upload
image: curlimages/curl:latest
needs:
- job: build-application
artifacts: true
# rules:
# - if: $CI_COMMIT_TAG
script:
- |
curl -k --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file target/*.war "${PACKAGE_REGISTRY_URL}/${GENERIC_WAR}"
prepare_job:
stage: prepare
rules:
- if: $CI_COMMIT_TAG
when: never
- if: $CI_COMMIT_BRANCH == "feature/release"
script:
- echo "EXTRA_DESCRIPTION=some message" >> variables.env # Generate the EXTRA_DESCRIPTION and TAG environment variables
- echo "TAG=v$(cat VERSION)" >> variables.env
artifacts:
reports:
dotenv: variables.env
release_job:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
needs:
- job: prepare_job
artifacts: true
rules:
- if: $CI_COMMIT_TAG
when: never
- if: $CI_COMMIT_BRANCH == "feature/release"
before_script:
- apk --no-cache add openssl ca-certificates
- mkdir -p /usr/local/share/ca-certificates/extra
- openssl s_client -connect ${CI_SERVER_HOST}:${CI_SERVER_PORT} -servername ${CI_SERVER_HOST} -showcerts </dev/null 2>/dev/null | sed -e '/-----BEGIN/,/-----END/!d' | tee "/usr/local/share/ca-certificates/${CI_SERVER_HOST}.crt" >/dev/null
- update-ca-certificates
script:
- echo 'running release_job for $TAG'
release:
name: "Release $TAG"
description: "Created using the release-cli $EXTRA_DESCRIPTION"
tag_name: "$TAG"
ref: "$CI_COMMIT_SHA"
assets:
links:
- name: "{$GENERIC_WAR}"
url: "${PACKAGE_REGISTRY_URL}"
filepath: "/${GENERIC_WAR}"
Release job execution
Running with gitlab-runner 14.5.2 (e91107dd)
on Shared-Docker mdaS6_cA
Preparing the "docker" executor
00:03
Using Docker executor with image registry.gitlab.com/gitlab-org/release-cli:latest ...
Pulling docker image registry.gitlab.com/gitlab-org/release-cli:latest ...
Using docker image sha256:c2d3a3c3b9ad5ef63478b6a6b757632dd7994d50e603ec69999de6b541e1dca8 for registry.gitlab.com/gitlab-org/release-cli:latest with digest registry.gitlab.com/gitlab-org/release-cli#sha256:68e201226e1e76cb7edd327c89eb2d5d1a1d2b0fd4a6ea5126e24184d9aa4ffc ...
Preparing environment
00:01
Running on runner-mdas6ca-project-32-concurrent-0 via Docker-Server1...
Getting source from Git repository
00:01
Fetching changes with git depth set to 50...
Reinitialized existing Git repository in /builds/Saiida/backend-endarh/.git/
Checking out 7735e9ea as feature/release...
Removing target/
Removing variables.env
Skipping Git submodules setup
Executing "step_script" stage of the job script
00:02
Using docker image sha256:c2d3a3c3b9ad5ef63478b6a6b757632dd7994d50e603ec69999de6b541e1dca8 for registry.gitlab.com/gitlab-org/release-cli:latest with digest registry.gitlab.com/gitlab-org/release-cli#sha256:68e201226e1e76cb7edd327c89eb2d5d1a1d2b0fd4a6ea5126e24184d9aa4ffc ...
$ apk --no-cache add openssl ca-certificates
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.13/community/x86_64/APKINDEX.tar.gz
(1/2) Installing ca-certificates (20191127-r5)
(2/2) Installing openssl (1.1.1l-r0)
Executing busybox-1.32.1-r6.trigger
Executing ca-certificates-20191127-r5.trigger
OK: 7 MiB in 16 packages
$ mkdir -p /usr/local/share/ca-certificates/extra
$ openssl s_client -connect ${CI_SERVER_HOST}:${CI_SERVER_PORT} -servername ${CI_SERVER_HOST} -showcerts </dev/null 2>/dev/null | sed -e '/-----BEGIN/,/-----END/!d' | tee "/usr/local/share/ca-certificates/${CI_SERVER_HOST}.crt" >/dev/null
$ update-ca-certificates
Warning! Cannot copy to bundle: /usr/local/share/ca-certificates/extra
WARNING: ca-certificates.crt does not contain exactly one certificate or CRL: skipping
WARNING: ca-cert-extra.pem does not contain exactly one certificate or CRL: skipping
$ echo 'running release_job for $TAG'
running release_job for $TAG
Executing "step_release" stage of the job script
00:01
$ release-cli create --name "Release $TAG" --description "Created using the release-cli $EXTRA_DESCRIPTION" --tag-name "$TAG" --ref "$CI_COMMIT_SHA" --assets-link "{\"url\":\"${PACKAGE_REGISTRY_URL}\",\"name\":\"{$GENERIC_WAR}\",\"filepath\":\"/${GENERIC_WAR}\"}"
time="2021-12-23T08:47:48Z" level=info msg="Creating Release..." cli=release-cli command=create name="Release v" project-id=32 ref=7735e9ea9422e20b09cae2072c692843b118423a server-url="https://gitlab.endatamweel.tn" tag-name=v version=0.10.0
time="2021-12-23T08:47:48Z" level=fatal msg="run app" cli=release-cli error="failed to create release: failed to do request: Post \"https://gitlab.endatamweel.tn/api/v4/projects/32/releases\": x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0" version=0.10.0
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit code 1
I managed to get it work by replacing the yaml format of the release job with the release-cli command and arguments and set --insecure-https option not optimised for production of course
release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
needs:
- job: prepare_job
artifacts: true
rules:
- if: $CI_COMMIT_TAG
when: never # Do not run this job when a tag is created manually
- if: $CI_COMMIT_BRANCH == "feature/release" # Run this job when commits are pushed or merged to the default branch
script:
- |
release-cli --insecure-https=true create --name "Release $TAG" --tag-name $TAG --ref $CI_COMMIT_SHA \
--assets-link "{\"name\":\"${GENERIC_WAR}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${GENERIC_WAR}\", \"link_type\":\"package\"}"
This Gitlab pipeline job builds Gitbook documentation and copies it to some place:
build_gitbook:
variables:
DOC_DIR: '/var/www/doc'
script:
- gitbook build help _book
- 'rm -rf $DOC_DIR/help'
- 'mkdir -p $DOC_DIR/help'
- 'cp -r _book/* $DOC_DIR/help'
artifacts:
paths:
- _book
expire_in: 10 mins
How do I change this job so that the documentation gets copied to /var/www/doc when the branch is master, but gets copied to to /var/www/dev-doc on all other branches?
If you are able to add to your CI jobs and not limited in number of the jobs, you can use only/except syntax to change your .gitlab-ci.yml:
⋮
build_gitbook_master:
variables:
DOC_DIR: '/var/www/doc'
only:
- master
script:
⋮
<Your Scripts>
⋮
artifacts:
⋮
build_gitbook_others:
variables:
DOC_DIR: '/var/www/dev-doc'
except:
- master
script:
⋮
<Your Scripts>
⋮
artifacts:
⋮
⋮
Also you can check GitLab's rules as an alternative way.
This can be done like this. The main script is in the template part.
# The template part that contains the build script it self.
.build_gitbook: &gitbook_build_script
script:
- gitbook build common_operations_infos _book
- 'rm -rf $DOC_DIR/help'
- 'mkdir -p $DOC_DIR/help'
- 'cp -r _book/* $DOC_DIR/help'
artifacts:
paths:
- _book
expire_in: 10 mins
# Builds gitbook on the master branch
build_gitbook_master:
<<: *gitbook_build_script
variables:
DOC_DIR: '/var/www/doc'
only:
- master
# Builds gitbook on other branch
build_gitbook_others:
<<: *gitbook_build_script
variables:
DOC_DIR: '/var/www/dev-doc'
except:
- master
This is still not the perfect solution since this requires two jobs. If they are run in manual mode (when: manual) then the developer must choice the right job depending on branch.
Hi I have a yml as below but i want to run specific stage for only specific branch names like release candidate. The name of the release branch can change like cis-rel1.0 the next time cis-rel2.0 and so on.
image: java:8
stages:
- build
- deploy
build:
stage: build
script: ./mvnw package
artifacts:
paths:
- target/demo-0.0.1-SNAPSHOT.jar
production:
stage: deploy
script:
- curl --location "https://cli.run.pivotal.io/stable?release=linux64-binary&source=github" | tar zx
- ./cf login -u $CF_USERNAME -p $CF_PASSWORD -a api.run.pivotal.io
- ./cf push
only:
- cis-rel1.0
Yes you can achieve that using the regex pattern in .gitlab-ci.yml as shown below . This regex will filter for your project name /^cis-rel.*$/
image: java:8
stages:
- build
- deploy
build:
stage: build
script: ./mvnw package
artifacts:
paths:
- target/demo-0.0.1-SNAPSHOT.jar
production:
stage: deploy
script:
- curl --location "https://cli.run.pivotal.io/stable?release=linux64-binary&source=github" | tar zx
- ./cf login -u $CF_USERNAME -p $CF_PASSWORD -a api.run.pivotal.io
- ./cf push
only:
- /^cis-rel.*$/