# ----------------------------------------------------------------------------- # Original/Ref: https://git.price-hk.com/boilerplate-samples-projects/basic-docker-ci # ----------------------------------------------------------------------------- # Generic Gitlab CI for docker project for building and uploading img to Nexus and QCloud # # This file requires the following variables: # See Also: https://git.price-hk.com/admin/application_settings/ci_cd # (Requried:) # - NAMESPACE: [price|myprice] # It will be prepended to the DOCKER_IMAGE_NAME # - PRICE_DOCKER_REPO_HOST # Nexus Repo Host # - PRICE_DOCKER_REPO_USER # Nexus Repo User # - PRICE_DOCKER_REPO_PWD # Nexus Repo Password # - QCLOUD_TKE_TCR_HOST # QCloud TKE TCR (Registry) Host # - QCLOUD_TKE_TCR_USER # QCloud TKE TCR (Registry) User # - QCLOUD_TKE_TCR_PWD # QCloud TKE TCR (Registry) Password # # (Optional:) # - DOCKER_IMAGE_NAME # It can be overrided if specified # # Triggering the Pipeline: # The pipeline can be triggered by git tagging or running the pipeline manually with CI_COMMIT_TAG var. # # The pattern of Git tag or CI_COMMIT_TAG should be either: # - Image for release purpose => release-{Docker Image Tag} # - Docker Image Tag pattern: {semantic version style: x.y.z}[-{Optional text}] # - Image for Non-release/Development purpose => dev-{Docker Image Tag} # - Docker Image Tag pattern: any text follow docker tag requirements # stages: - trigger - docker-build-push-nexus - push-qcloud default: interruptible: false tags: # Note: There may be a performance issue while using dind # so that we switch to docker executor. - docker-executor artifacts: reports: dotenv: build.env # after_script: # # Only for debug propose, comment for production # - env variables: NAMESPACE: price DOCKER_IMAGE_NAME: "${NAMESPACE}/${CI_PROJECT_PATH_SLUG}" DOCKERFILE_NAME: "Dockerfile" .release_tag_rules: rules: # Force git-tag trigger only, run-pipeline not support (recommended) - if: '$CI_COMMIT_TAG =~ /^release-\d+(\.\d+){0,2}\.\d+(-([a-zA-Z0-9\.\-\_]+)*[a-zA-Z0-9])?$/ && $CI_PIPELINE_SOURCE == "push"' # Can use git-tag trigger and run-pipeline (for ci-development only) # - if: '$CI_COMMIT_TAG =~ /^release-\d+(\.\d+){0,2}\.\d+(-([a-zA-Z0-9\.\-\_]+)*[a-zA-Z0-9])?$/' when: on_success .dev_tag_rules: rules: # Force git-tag trigger only, run-pipeline not support (recommended) - if: '$CI_COMMIT_TAG =~ /^dev-[a-zA-Z0-9\.\-\_]+[a-zA-Z0-9]$/ && $CI_PIPELINE_SOURCE == "push"' # Can use git-tag trigger and run-pipeline (for ci-development only) # - if: '$CI_COMMIT_TAG =~ /^dev-[a-zA-Z0-9\.\-\_]+[a-zA-Z0-9]$/' when: on_success .tag_trigger_save_build_env: script: # Send to next stages - | echo "IS_RELEASE_IMAGE=${IS_RELEASE_IMAGE}" >> build.env echo "DOCKERFILE_NAME=${DOCKERFILE_NAME}" >> build.env echo "DOCKER_IMAGE_TAG=${DOCKER_IMAGE_TAG}" >> build.env .check_get_docker_image_tag: script: - | # Extract the docker image tag from commit tag if [ -z $CI_COMMIT_TAG ]; then echo "[!] ERROR, missing CI_COMMIT_TAG" exit 1 else DOCKER_IMAGE_TAG=$(echo "$CI_COMMIT_TAG" | sed -re 's/^[^-]+-(.*)$/\1/g') fi # ---------- JOB --------- Tag Trigger for Release: stage: trigger rules: - !reference [.release_tag_rules, rules] script: - IS_RELEASE_IMAGE=true - !reference [.check_get_docker_image_tag, script] - !reference [.tag_trigger_save_build_env, script] # ---------- JOB --------- Tag or Manual Trigger for Dev Build: stage: trigger rules: - !reference [.dev_tag_rules, rules] script: - IS_RELEASE_IMAGE=false - !reference [.check_get_docker_image_tag, script] # Append 'dev-' to the docekr tag for the non-release image - DOCKER_IMAGE_TAG="dev-${DOCKER_IMAGE_TAG}" # Check if Dockerfile.dev exist, then use it for docker build # TODO: consider to use filename suffix for other image tag like architecture suffix - | if [ -f "${DOCKERFILE_NAME}.dev" ]; then DOCKERFILE_NAME=${DOCKERFILE_NAME}.dev fi - !reference [.tag_trigger_save_build_env, script] # ---------- JOB --------- Docker Build and Push to Nexus: stage: docker-build-push-nexus rules: - !reference [.release_tag_rules, rules] - !reference [.dev_tag_rules, rules] # Not using 'needs' properly. The following settings cannot restrict only # running from below jobs. It can be triggered if the rule passes anyway. # Therefore, we still need to govern the trigger by rules. # The use of 'needs' is for better flow declaration, for DAG. needs: - job: Tag or Manual Trigger for Dev Build optional: true - job: Tag Trigger for Release optional: true before_script: # Login to Price Registry - Nexus - echo "${PRICE_DOCKER_REPO_PWD}" | docker login -u "${PRICE_DOCKER_REPO_USER}" --password-stdin ${PRICE_DOCKER_REPO_HOST} # pull latest image for cache-from, if any - docker pull ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest || true script: # ---------- PRE-BUILD ---------- # Modify the source code version string so that the VERSION_STRING will be added to the application # - | # sed -i -e "s/const BuildVersion string = .*$/const BuildVersion string = \"${VERSION_STRING}\"/g" cmd/priceuid2server/main.go - DOCKER_IMAGE_NAME_WITH_TAG=${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} # ---------- BUILD DOCKER IMAGE ---------- - | echo "Using Dockerfile: ${DOCKERFILE_NAME}" - > docker build -f "${DOCKERFILE_NAME}" --pull --tag ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} --cache-from ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest --build-arg org_label_schema_name="${DOCKER_IMAGE_NAME}" --build-arg org_label_schema_version="${DOCKER_IMAGE_TAG}" --build-arg org_label_schema_description="${CI_PROJECT_TITLE}" --build-arg org_label_schema_build_date="${CI_PIPELINE_CREATED_AT}" --build-arg org_label_schema_vcs_ref="${CI_COMMIT_SHA}" --build-arg org_label_schema_vcs_url="${CI_PROJECT_URL}" --build-arg maintainer="${GITLAB_USER_LOGIN}<${GITLAB_USER_EMAIL}>" --build-arg APP_VERSION="${DOCKER_IMAGE_TAG}" . # ---------- PUBLISH DOCKER IMAGE TO NEXUS REGISTRY ---------- # Push local image to Price's registry - docker push ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} # Tag latest image if it is an image for release - | if [ "$IS_RELEASE_IMAGE" = true ]; then docker tag \ ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} \ ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest docker push ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:latest fi # Artifacts to next stage - !reference [.tag_trigger_save_build_env, script] # ---------- JOB --------- Push Image to QCloud: stage: push-qcloud rules: - !reference [.release_tag_rules, rules] - !reference [.dev_tag_rules, rules] needs: - Docker Build and Push to Nexus before_script: # Login to Price Registry - Nexus - echo "${PRICE_DOCKER_REPO_PWD}" | docker login -u "${PRICE_DOCKER_REPO_USER}" --password-stdin ${PRICE_DOCKER_REPO_HOST} # Login to QCLOUD TCR (Registry) - echo "${QCLOUD_TKE_TCR_PWD}" | docker login -u "${QCLOUD_TKE_TCR_USER}" --password-stdin ${QCLOUD_TKE_TCR_HOST} # Because we have no guarantee that this job will be picked up by the same runner # that built the image in the previous step, we pull it again locally - docker pull ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} script: # ---------- PRE-PUBLISH ---------- - DOCKER_IMAGE_NAME_WITH_TAG=${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG} # ---------- PUBLISH DOCKER IMAGE TO QCLOUD REGISTRY ---------- - | docker tag \ ${PRICE_DOCKER_REPO_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} \ ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} docker push ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} # Tag latest image if it is an image for release - | if [ "$IS_RELEASE_IMAGE" = true ]; then docker tag \ ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} \ ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME}:latest docker push ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME}:latest docker rmi ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME}:latest fi # Clean up - docker rmi ${QCLOUD_TKE_TCR_HOST}/${DOCKER_IMAGE_NAME_WITH_TAG} # Artifacts to next stage - !reference [.tag_trigger_save_build_env, script]