GitOps and Value Sync
The gitops-update-values-and-sync job is used to update GitOps repositories with new image tags and commit information, then synchronize Argo CD applications. It follows GitOps principles by updating configuration in Git and triggering deployments.
Overview
This job:
- Updates Helm values files in a GitOps repository with new image tags and commit information
- Optionally converts
.envfiles toenv.yamlformat - Commits and pushes changes to the GitOps repository
- Synchronizes Argo CD applications to trigger deployments
- Supports both token-based and username/password authentication for Argo CD
Variables
The following variables can be configured:
| Variable | Description | Default | Required |
|---|---|---|---|
TARGET_REPO | GitOps repository URL | "" | Yes |
TARGET_BRANCH | Branch to update in GitOps repo | "main" | No |
VALUES_FILE | Path to values.yaml file in GitOps repo | "environments/dev/values.yaml" | Yes |
ENV_LOCAL_PATH | Path to local .env file | ".env" | No |
ENV_OUT_FILE | Output path for env.yaml in GitOps repo | "environments/dev/env.yaml" | No |
WRITE_ENV_FILE | Enable .env to env.yaml conversion | "true" | No |
COMMIT_MESSAGE | Git commit message | "chore(gitops): set image tag & commit info + env" | No |
GIT_USER_NAME | Git commit author name | "CI Bot" | No |
GIT_USER_EMAIL | Git commit author email | "[email protected]" | No |
GIT_HTTP_USERNAME | GitLab username or "oauth2" for PAT | "" | Yes |
GIT_HTTP_PASSWORD | GitLab token/password | "" | Yes |
ARGOCD_SERVER | Argo CD server URL | "" | Yes |
ARGOCD_APP | Argo CD application name | "" | Yes |
ARGOCD_GRPC_WEB | Use gRPC-Web for Argo CD | "true" | No |
ARGOCD_INSECURE | Skip TLS verification | "true" | No |
ARGOCD_SYNC_TIMEOUT | Argo CD sync timeout in seconds | "600" | No |
IMAGE_TAG | Image tag to set (auto-derived if not set) | Auto-derived | No |
COMMIT_SHA | Commit SHA (auto-derived if not set) | Auto-derived | No |
COMMIT_BRANCH | Commit branch (auto-derived if not set) | Auto-derived | No |
COMMIT_URL | Commit URL (auto-derived if not set) | Auto-derived | No |
ARGOCD_AUTH_TOKEN | Argo CD authentication token | - | No |
ARGOCD_USERNAME | Argo CD username (if no token) | - | No |
ARGOCD_PASSWORD | Argo CD password (if no token) | - | No |
Variable Details
Git Target Configuration
- TARGET_REPO: Full HTTPS URL to the GitOps repository (e.g.,
https://gitlab.com/welance/platform/gitops/app-configs.git) - TARGET_BRANCH: Branch name in the GitOps repository to update (default:
main) - VALUES_FILE: Path to the Helm values file within the GitOps repository (e.g.,
environments/dev/values.yaml)
Environment File Conversion
- ENV_LOCAL_PATH: Path to the local
.envfile to convert (default:.env) - ENV_OUT_FILE: Path where the converted
env.yamlfile will be written in the GitOps repository - WRITE_ENV_FILE: Set to
"true"to enable.envtoenv.yamlconversion,"false"to disable
Git Configuration
- COMMIT_MESSAGE: Custom commit message for GitOps repository updates
- GIT_USER_NAME: Name to use for Git commits
- GIT_USER_EMAIL: Email to use for Git commits
Git Authentication
- GIT_HTTP_USERNAME:
- Use
"oauth2"for Personal Access Tokens (PAT) - Use bot username for Project/Group Access Tokens
- Use
- GIT_HTTP_PASSWORD: The token value (should be stored as a masked CI/CD variable)
Argo CD Configuration
- ARGOCD_SERVER: Argo CD server URL (e.g.,
https://argocd.example.com) - ARGOCD_APP: Name of the Argo CD application to sync
- ARGOCD_GRPC_WEB: Set to
"true"to use gRPC-Web protocol (useful for browser-based connections) - ARGOCD_INSECURE: Set to
"true"to skip TLS certificate verification - ARGOCD_SYNC_TIMEOUT: Timeout in seconds for Argo CD sync operations (default: 600 seconds)
Auto-Derived Variables
If not explicitly set, these variables are automatically derived from GitLab CI/CD variables:
- IMAGE_TAG:
{CI_COMMIT_REF_SLUG}-{CI_PIPELINE_ID}(e.g.,main-12345) - COMMIT_SHA:
CI_COMMIT_SHA - COMMIT_BRANCH:
CI_COMMIT_REF_NAME - COMMIT_URL:
{CI_PROJECT_URL}/-/commit/{CI_COMMIT_SHA}
Argo CD Authentication
Either use:
- ARGOCD_AUTH_TOKEN: Authentication token (preferred)
- ARGOCD_USERNAME + ARGOCD_PASSWORD: Username and password authentication
Usage
Basic Usage
.gitops-update-values-and-sync:
image: alpine:3.20
variables:
TARGET_REPO: "https://gitlab.com/welance/platform/gitops/app-configs.git"
TARGET_BRANCH: "main"
VALUES_FILE: "environments/dev/values.yaml"
ENV_LOCAL_PATH: ".env"
ENV_OUT_FILE: "environments/dev/env.yaml"
WRITE_ENV_FILE: "true"
COMMIT_MESSAGE: "chore(gitops): set image tag & commit info + env"
GIT_USER_NAME: "CI Bot"
GIT_USER_EMAIL: "[email protected]"
GIT_HTTP_USERNAME: "oauth2"
GIT_HTTP_PASSWORD: "${CI_JOB_TOKEN}"
ARGOCD_SERVER: "https://argocd.example.com"
ARGOCD_APP: "my-app-dev"
ARGOCD_GRPC_WEB: "true"
ARGOCD_INSECURE: "true"
ARGOCD_SYNC_TIMEOUT: "600"
before_script:
- apk add --no-cache git curl bash yq
- git config --global user.name "$GIT_USER_NAME"
- git config --global user.email "$GIT_USER_EMAIL"
- git config --global credential.helper 'store --file ~/.git-credentials'
- printf "https://%s:%[email protected]\n" "$GIT_HTTP_USERNAME" "$GIT_HTTP_PASSWORD" > ~/.git-credentials
- git config --global url."https://gitlab.com/".insteadOf "[email protected]:"
- git config --global url."https://gitlab.com/".insteadOf "ssh://[email protected]/"
- curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
- chmod +x /usr/local/bin/argocd
script:
# ... (see full script in job definition)
rules:
- if: '$CI_PIPELINE_SOURCE == "pipeline" || $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web"'
when: on_success
Job Details
Before Script
The before_script section performs the following setup:
-
Install dependencies:
apk add --no-cache git curl bash yq- Installs Git, curl, bash, and yq (YAML processor)
-
Configure Git identity:
git config --global user.name "$GIT_USER_NAME"
git config --global user.email "$GIT_USER_EMAIL" -
Configure Git credentials:
git config --global credential.helper 'store --file ~/.git-credentials'
printf "https://%s:%[email protected]\n" "$GIT_HTTP_USERNAME" "$GIT_HTTP_PASSWORD" > ~/.git-credentials- Stores Git credentials for HTTPS authentication
-
Configure URL rewriting:
git config --global url."https://gitlab.com/".insteadOf "[email protected]:"
git config --global url."https://gitlab.com/".insteadOf "ssh://[email protected]/"- Automatically converts SSH URLs to HTTPS
-
Install Argo CD CLI:
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x /usr/local/bin/argocd
Script
The main script performs the following steps:
-
Validate required variables:
: "${TARGET_REPO:?TARGET_REPO is required}"
: "${TARGET_BRANCH:?TARGET_BRANCH is required}"
: "${VALUES_FILE:?VALUES_FILE is required}" -
Derive default values:
IMAGE_TAG="${IMAGE_TAG:-${CI_COMMIT_REF_SLUG:-latest}-${CI_PIPELINE_ID:-0}}"
COMMIT_SHA="${COMMIT_SHA:-${CI_COMMIT_SHA:-unknown}}"
COMMIT_BRANCH="${COMMIT_BRANCH:-${CI_COMMIT_REF_NAME:-unknown}}"
COMMIT_URL="${COMMIT_URL:-${CI_PROJECT_URL:-unknown}/-/commit/${CI_COMMIT_SHA:-unknown}}" -
Clone GitOps repository:
git clone --branch "$TARGET_BRANCH" "$TARGET_REPO" repo
cd repo
git config --global --add safe.directory "$(pwd)" -
Ensure values file exists:
mkdir -p "$(dirname "$VALUES_FILE")"
touch "$VALUES_FILE" -
Update image tag and commit info in values.yaml:
yq -i '
.image.tag = env(IMAGE_TAG) |
.image.commit.sha = env(COMMIT_SHA) |
.image.commit.url = env(COMMIT_URL) |
.image.commit.branch = env(COMMIT_BRANCH)
' "$VALUES_FILE"- Uses
yqto update only the image tag and commit information - Preserves the rest of the
image:section
- Uses
-
Optional: Convert .env to env.yaml:
if [ "${WRITE_ENV_FILE}" = "true" ] && [ -f "$WORKDIR/${ENV_LOCAL_PATH}" ]; then
mkdir -p "$(dirname "$ENV_OUT_FILE")"
{
echo "envFileContent: |-"
sed 's/^/ /' "$WORKDIR/${ENV_LOCAL_PATH}"
} > "$ENV_OUT_FILE"
fi- Converts
.envfile to YAML format with proper indentation - Creates
envFileContentkey with the .env content
- Converts
-
Commit and push changes:
if [ -z "$(git status --porcelain)" ]; then
echo "[INFO] No changes to commit."
else
git add -A
git commit -m "$COMMIT_MESSAGE"
git push origin "HEAD:$TARGET_BRANCH"
fi- Only commits if there are changes
-
Argo CD login and sync:
# Login with token or username/password
# Sync application
argocd app sync "$ARGOCD_APP" --timeout "$ARGOCD_SYNC_TIMEOUT" --server "$ARGOCD_SERVER" $ARGO_FLAGS
# Wait for sync to complete
argocd app wait "$ARGOCD_APP" --timeout "$ARGOCD_SYNC_TIMEOUT" --server "$ARGOCD_SERVER" $ARGO_FLAGS
Configuration Examples
Development Environment
variables:
TARGET_REPO: "https://gitlab.com/welance/platform/gitops/app-configs.git"
TARGET_BRANCH: "main"
VALUES_FILE: "environments/dev/values.yaml"
ENV_OUT_FILE: "environments/dev/env.yaml"
ARGOCD_SERVER: "https://argocd.example.com"
ARGOCD_APP: "my-app-dev"
GIT_HTTP_USERNAME: "oauth2"
GIT_HTTP_PASSWORD: "${CI_JOB_TOKEN}"
deploy-gitops-dev:
extends: .gitops-update-values-and-sync
stage: deploy
only:
- develop
Production Environment
variables:
TARGET_REPO: "https://gitlab.com/welance/platform/gitops/app-configs.git"
TARGET_BRANCH: "main"
VALUES_FILE: "environments/prod/values.yaml"
ENV_OUT_FILE: "environments/prod/env.yaml"
ARGOCD_SERVER: "https://argocd.example.com"
ARGOCD_APP: "my-app-prod"
ARGOCD_AUTH_TOKEN: "${ARGOCD_PROD_TOKEN}"
GIT_HTTP_USERNAME: "oauth2"
GIT_HTTP_PASSWORD: "${CI_JOB_TOKEN}"
deploy-gitops-prod:
extends: .gitops-update-values-and-sync
stage: deploy
only:
- main
- tags
Complete Pipeline Example
stages:
- build
- deploy
# Build job creates .env and .env.version
build:
stage: build
script:
- echo "VERSION=main-12345" > .env.version
- echo "DB_HOST=db.example.com" > .env
artifacts:
paths:
- .env
- .env.version
.gitops-update-values-and-sync:
image: alpine:3.20
variables:
TARGET_REPO: "https://gitlab.com/welance/platform/gitops/app-configs.git"
TARGET_BRANCH: "main"
VALUES_FILE: "environments/dev/values.yaml"
ENV_LOCAL_PATH: ".env"
ENV_OUT_FILE: "environments/dev/env.yaml"
WRITE_ENV_FILE: "true"
COMMIT_MESSAGE: "chore(gitops): set image tag & commit info + env"
GIT_USER_NAME: "CI Bot"
GIT_USER_EMAIL: "[email protected]"
GIT_HTTP_USERNAME: "oauth2"
GIT_HTTP_PASSWORD: "${CI_JOB_TOKEN}"
ARGOCD_SERVER: "https://argocd.example.com"
ARGOCD_APP: "my-app-dev"
ARGOCD_GRPC_WEB: "true"
ARGOCD_INSECURE: "true"
ARGOCD_SYNC_TIMEOUT: "600"
before_script:
- apk add --no-cache git curl bash yq
- git config --global user.name "$GIT_USER_NAME"
- git config --global user.email "$GIT_USER_EMAIL"
- git config --global credential.helper 'store --file ~/.git-credentials'
- printf "https://%s:%[email protected]\n" "$GIT_HTTP_USERNAME" "$GIT_HTTP_PASSWORD" > ~/.git-credentials
- git config --global url."https://gitlab.com/".insteadOf "[email protected]:"
- git config --global url."https://gitlab.com/".insteadOf "ssh://[email protected]/"
- curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
- chmod +x /usr/local/bin/argocd
script:
- set -euo pipefail
- |
: "${TARGET_REPO:?TARGET_REPO is required}"
: "${TARGET_BRANCH:?TARGET_BRANCH is required}"
: "${VALUES_FILE:?VALUES_FILE is required}"
- |
IMAGE_TAG="${IMAGE_TAG:-${CI_COMMIT_REF_SLUG:-latest}-${CI_PIPELINE_ID:-0}}"
COMMIT_SHA="${COMMIT_SHA:-${CI_COMMIT_SHA:-unknown}}"
COMMIT_BRANCH="${COMMIT_BRANCH:-${CI_COMMIT_REF_NAME:-unknown}}"
COMMIT_URL="${COMMIT_URL:-${CI_PROJECT_URL:-unknown}/-/commit/${CI_COMMIT_SHA:-unknown}}"
- git clone --branch "$TARGET_BRANCH" "$TARGET_REPO" repo
- WORKDIR="$(pwd)"
- cd repo
- git config --global --add safe.directory "$(pwd)"
- mkdir -p "$(dirname "$VALUES_FILE")"
- touch "$VALUES_FILE"
- |
echo "[INFO] Updating only .image.tag and .image.commit.* in $VALUES_FILE"
export IMAGE_TAG COMMIT_SHA COMMIT_URL COMMIT_BRANCH
yq -i '
.image.tag = env(IMAGE_TAG) |
.image.commit.sha = env(COMMIT_SHA) |
.image.commit.url = env(COMMIT_URL) |
.image.commit.branch = env(COMMIT_BRANCH)
' "$VALUES_FILE"
- |
if [ "${WRITE_ENV_FILE}" = "true" ] && [ -f "$WORKDIR/${ENV_LOCAL_PATH}" ]; then
echo "[INFO] Creating/overwriting ${ENV_OUT_FILE} from ${ENV_LOCAL_PATH}"
mkdir -p "$(dirname "$ENV_OUT_FILE")"
{
echo "envFileContent: |-"
sed 's/^/ /' "$WORKDIR/${ENV_LOCAL_PATH}"
} > "$ENV_OUT_FILE"
else
echo "[INFO] ${ENV_LOCAL_PATH} not found or WRITE_ENV_FILE disabled; skipping env.yaml generation."
fi
- |
if [ -z "$(git status --porcelain)" ]; then
echo "[INFO] No changes to commit."
else
git add -A
git commit -m "$COMMIT_MESSAGE"
git push origin "HEAD:$TARGET_BRANCH"
fi
- |
: "${ARGOCD_SERVER:?ARGOCD_SERVER is required}"
: "${ARGOCD_APP:?ARGOCD_APP is required}"
ARGO_FLAGS=""
[ "$ARGOCD_GRPC_WEB" = "true" ] && ARGO_FLAGS="$ARGO_FLAGS --grpc-web"
[ "$ARGOCD_INSECURE" = "true" ] && ARGO_FLAGS="$ARGO_FLAGS --insecure"
if [ -n "${ARGOCD_AUTH_TOKEN:-}" ]; then
argocd login "$ARGOCD_SERVER" --auth-token "$ARGOCD_AUTH_TOKEN" $ARGO_FLAGS
else
: "${ARGOCD_USERNAME:?Set ARGOCD_USERNAME or ARGOCD_AUTH_TOKEN}"
: "${ARGOCD_PASSWORD:?Set ARGOCD_PASSWORD or ARGOCD_AUTH_TOKEN}"
argocd login "$ARGOCD_SERVER" --username "$ARGOCD_USERNAME" --password "$ARGOCD_PASSWORD" $ARGO_FLAGS
fi
echo "[INFO] Syncing $ARGOCD_APP"
argocd app sync "$ARGOCD_APP" --timeout "$ARGOCD_SYNC_TIMEOUT" --server "$ARGOCD_SERVER" $ARGO_FLAGS
echo "[INFO] Waiting for Healthy/Synced..."
argocd app wait "$ARGOCD_APP" --timeout "$ARGOCD_SYNC_TIMEOUT" --server "$ARGOCD_SERVER" $ARGO_FLAGS
rules:
- if: '$CI_PIPELINE_SOURCE == "pipeline" || $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web"'
when: on_success
dependencies:
- build
deploy-gitops:
extends: .gitops-update-values-and-sync
stage: deploy
Prerequisites
- GitOps repository: A Git repository containing Helm values files
- GitLab access: Token with write access to the GitOps repository
- Argo CD: Argo CD server must be accessible and configured
- Argo CD application: An Argo CD application must exist and be configured
- Values file structure: The values file should have an
image:section withtagandcommitsubsections - .env file (optional): If
WRITE_ENV_FILEis enabled, a.envfile must exist
Values File Structure
The job expects the values file to have this structure:
image:
tag: "main-12345"
commit:
sha: "abc123def456"
url: "https://gitlab.com/group/project/-/commit/abc123def456"
branch: "main"
The job will update only these fields, preserving the rest of the image: section.
Security Considerations
- GitLab Token: Store
GIT_HTTP_PASSWORDas a masked CI/CD variable - Argo CD Credentials: Store
ARGOCD_AUTH_TOKENorARGOCD_PASSWORDas masked variables - Token Permissions: Ensure tokens have minimal required permissions
- Insecure Mode:
ARGOCD_INSECUREshould befalsein production if possible - Environment Files: Ensure
.envfiles don't contain sensitive data or are properly secured
Notes
- The job uses
yqto update YAML files, preserving the existing structure - Only commits if there are actual changes to the repository
- Automatically derives image tags and commit information from GitLab CI/CD variables
- Supports both token-based and username/password authentication for Argo CD
- The
.envtoenv.yamlconversion adds proper YAML indentation - Argo CD sync waits for the application to become healthy/synced
- The job runs only on pipeline, push, or web triggers (not on scheduled pipelines)
- SSH URLs are automatically converted to HTTPS for Git operations
- The job uses Alpine Linux for a minimal image size