-
-
Save voboshi/f3a322200cc6df4f913ce101b9f1dc6d to your computer and use it in GitHub Desktop.
Updated gitlab-runner supporting docker in docker
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
#!/usr/bin/env bash | |
set -euo pipefail | |
usage () { | |
echo "Usage: $(basename $0) {up|down|[job stage]}" | |
echo "[job stage] - defaults to "build" and supports multiple comma delimited jobs" | |
echo "$(basename $0) test,build" | |
} | |
PWD_RESOLVED="$(pwd -P)" | |
# .gitlab-ci.yml has to live in the root of a project/git repo, so if we aren't in that folder, cd to it | |
GIT_ROOT=$(git rev-parse --show-toplevel) | |
if [ "$PWD_RESOLVED" != "$GIT_ROOT" ]; then cd $GIT_ROOT; PWD_RESOLVED="$(pwd -P)"; fi | |
# If we are in a Git(lab) repo the .gitlab-ci.yml should be in the root of it | |
[ -f "./.gitlab-ci.yml" ] || { echo "No .gitlab-ci.yml found"; exit 3; } | |
DEFAULT_STAGE="build" | |
# This could also apply to Google Cloud or Microsoft Azure or other providers if you define the correct paths/variables | |
declare -a ENVVARS | |
if [ -f $HOME/.aws/credentials ]; then | |
# Need this to get secrets from the host, but don't pass in AWS_PROFILE itself to runner because it shouldn't have ~/.aws/credentials where it looks up profiles | |
awsProfile=${AWS_PROFILE:-default} | |
# echo "AWS_PROFILE=$awsProfile" | |
AWS_ACCESS_KEY_ID=$(aws --profile $awsProfile configure get aws_access_key_id) | |
AWS_SECRET_ACCESS_KEY=$(aws --profile $awsProfile configure get aws_secret_access_key) | |
AWS_SESSION_TOKEN=$(aws --profile $awsProfile configure get aws_session_token) | |
ENVVARS=("AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" "AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" "AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN") | |
CREDVARS=$(printf " --env %s" "${ENVVARS[@]}") | |
fi | |
committedCodeCheck() { | |
# Gitlab-runner already checks this but we wanted to give a message about how to abort and rectify | |
set +e | |
git update-index --refresh | |
set -e | |
if ! git diff-index --quiet HEAD -- ; then | |
echo "WARNING: Git has some uncommitted changes which will not run!" | |
git status | |
echo | |
echo "gitlab-runner local builds require you commit changes before they take effect (anything outside the .gitlab-ci.yml)" | |
echo "press Ctrl+C now to abort in the next 10 seconds and commit your changes, unless you want to run old code" | |
sleep 10 | |
fi | |
} | |
gitlabLoop() { | |
stages=($(echo "$1" | tr ',' '\n')) | |
if [ -z "$stages" ]; then | |
echo "Running $DEFAULT_STAGE stage only" | |
gitlabExec "$DEFAULT_STAGE" | |
else | |
echo "Running stage(s): ${stages[*]}" | |
for stage in ${stages[*]}; do | |
gitlabExec $stage | |
done | |
fi | |
} | |
gitlabExec() { | |
docker exec -w $PWD_RESOLVED -it gitlab-runner \ | |
gitlab-runner exec docker $1 \ | |
--docker-privileged \ | |
--custom_build_dir-enabled \ | |
--docker-volumes="/certs" \ | |
--docker-disable-cache=false \ | |
--env ROOT_PWD=$PWD_RESOLVED \ | |
${CREDVARS:-} | |
# --cache-dir=/tmp/gitlabrunner \ | |
# --docker-pull-policy="if-not-present" \ | |
# The custom_build_dir requires a workaround in local scripts because not all CI_ variables present on a Gitlab instance show up in the local runner | |
# https://docs.gitlab.com/ee/ci/variables/where_variables_can_be_used.html | |
# The /tmp/gitlabrunner is inside the outer gitlab-runner container so isn't the volume from host_runner | |
# https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section | |
# Don't disable cache as it behaves poorly with our /certs volume | |
# https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4596 | |
# why disable cache? | |
#--docker-disable-cache \ | |
} | |
host_runner () { | |
committedCodeCheck | |
# Checks if gitlab-runner is already running and ensures it is using the current repo otherwise restarts it | |
{ [ -n "$(docker ps -q -f 'name=gitlab-runner')" ] && \ | |
docker inspect gitlab-runner | jq -r .[].Mounts[].Source | grep -q "$PWD_RESOLVED"; } || { | |
gitlab_down | |
# Use --mount type=bind to avoid creating root owned paths on host | |
# Use --rm to cleanup 'anonymous volumes' | |
docker run -d --rm --name gitlab-runner \ | |
--env DOCKER_DRIVER=overlay2 \ | |
--mount type=bind,source=$PWD_RESOLVED,target=$PWD_RESOLVED \ | |
--mount type=volume,target=/certs \ | |
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ | |
--workdir $PWD_RESOLVED \ | |
--mount type=volume,target=/etc/gitlab-runner \ | |
gitlab/gitlab-runner:latest | |
} | |
} | |
gitlab_down () { | |
set +e | |
docker stop gitlab-runner | |
docker rm gitlab-runner | |
for container in $(docker ps -q -f 'name=runner*'); do docker stop $container; docker rm $container; done | |
docker volume rm gitlab-runner-config | |
set -e | |
} | |
case "${1:-}" in | |
up) ## ONLY CREATE/START DOCKER CONTAINER FOR GITLAB | |
host_runner | |
;; | |
job) ## TO RUN RUNNER AFTER GITLAB CONTAINER HAS STARTED | |
host_runner | |
gitlabLoop ${2} | |
;; | |
down) ## TO STOP AND CLEANUP GITLAB CONTAINER | |
gitlab_down | |
;; | |
-h) usage; exit 0 | |
;; | |
'') | |
usage | |
echo "User didn't pass job/stage to run, defaulting to 'build'" | |
sleep 2 | |
host_runner | |
gitlabLoop ${1:-build} | |
;; | |
*) ## RUN RUNNER with specific job/stages AFTER ensuring GITLAB CONTAINER HAS STARTED | |
usage | |
host_runner | |
gitlabLoop ${1:-build} | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment