Skip to content

Instantly share code, notes, and snippets.

@voboshi
Forked from dragon788/gitlab-local.sh
Created May 25, 2021 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voboshi/f3a322200cc6df4f913ce101b9f1dc6d to your computer and use it in GitHub Desktop.
Save voboshi/f3a322200cc6df4f913ce101b9f1dc6d to your computer and use it in GitHub Desktop.
Updated gitlab-runner supporting docker in docker
#!/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