Table of Contents
Integration patterns and architecture
External CI tools (Jenkins, GitHub Actions, GitLab CI, Azure DevOps, etc.) typically integrate with OpenShift through a small set of patterns:
- Push-based deployments
CI runs builds/tests and then pushes a new image or triggers a rollout in OpenShift: - Push image to a registry OpenShift can access.
- Call OpenShift APIs (
oc/REST) to update deployments or trigger rollouts. - Optionally update Git (GitOps) instead of talking directly to the cluster.
- Pull-based (GitOps) deployments
CI updates a Git repository containing Kubernetes/OpenShift manifests; a GitOps tool (e.g., Argo CD) running in OpenShift reconciles changes: - External CI only manages tests/builds and Git.
- OpenShift deployment is indirectly driven by repo changes.
- Hybrid
CI might: - Build and push images.
- Update application configuration in Git.
- Optionally trigger a
PipelineRunfor OpenShift Pipelines or a GitOps sync.
When choosing a pattern consider:
- Who “owns” deployments (platform team vs app team).
- Network/connectivity (can the CI reach the cluster API?).
- Security and compliance (API tokens, RBAC, auditability).
- Desired level of Git-centric workflow.
Accessing OpenShift from external CI
Authentication options
External CI needs credentials to call the OpenShift API or run oc:
- User tokens
- Use personal access tokens (not ideal for automation).
- Rotating and revoking is harder for shared automation.
- Service accounts (recommended)
- Create a service account in the target project/namespace:
oc create sa ci-deployer -n my-app- Assign appropriate roles (e.g.,
edit, or a custom role with minimal permissions):
oc adm policy add-role-to-user edit -z ci-deployer -n my-app- Get the token (or use OAuth tokens in modern clusters where secret-based tokens are disabled; for CI use
oc login --token=...):
oc sa get-token ci-deployer -n my-app- Store the token and API URL in CI secrets.
- OIDC / SSO integration
- Some CI platforms can authenticate via OpenShift’s OAuth/OIDC provider directly.
- Useful in tightly integrated enterprise setups; usually requires cluster and IdP configuration by platform admins.
Network and security considerations
- Ensure CI runners can reach:
- The OpenShift API endpoint.
- The image registry (internal or external) used by the cluster.
- Enforce least privilege:
- Use namespace-scoped service accounts.
- Avoid
cluster-adminand broad roles for CI. - Manage secrets:
- Use CI’s secret store for tokens and registry credentials.
- Use short-lived tokens or automated rotation where possible.
Using `oc` in external CI pipelines
Many integrations rely on oc rather than direct REST calls.
Installing and configuring `oc` in CI
- Containerized approach (preferred)
- Use an
oc-based image as the CI job executor, e.g.: - Red Hat
openshift-cliimage - Custom image:
FROM registry.redhat.io/openshift4/ose-cli - Example GitLab CI job:
deploy:
image: registry.redhat.io/openshift4/ose-cli
stage: deploy
script:
- oc login "$OCP_API_URL" --token="$OCP_TOKEN" --insecure-skip-tls-verify=false
- oc project my-app
- oc rollout restart deployment/my-app- Binary install
- Download
ocin the job script:
curl -L "$OC_DOWNLOAD_URL" | tar -xz
sudo mv oc /usr/local/bin- Less reproducible than containerized approach.
Common deployment actions from CI
Once authenticated, typical CI actions include:
- Switch project:
oc project my-app- Update image of a deployment:
oc set image deployment/my-app \
my-app-container=quay.io/myorg/my-app:${CI_COMMIT_SHA}- Apply a manifest bundle:
oc apply -f k8s/- Trigger a rollout:
oc rollout restart deployment/my-app- Wait for rollout:
oc rollout status deployment/my-app --timeout=120sImage registry integration patterns
External CI builds, OpenShift only deploys
Typical for GitHub Actions, GitLab CI, Jenkins:
- CI builds image (Docker/Buildah/kaniko).
- CI pushes to registry (Quay.io, Docker Hub, GitLab registry, etc.).
- OpenShift pulls the image for deployment.
Key points:
- Configure
ImagePullSecretsin OpenShift to pull from the external registry:
oc create secret docker-registry external-regcred \
--docker-server=registry.example.com \
--docker-username="$REG_USER" \
--docker-password="$REG_PASS" \
--docker-email=dev@example.com \
-n my-app
oc secrets link default external-regcred --for=pull -n my-app- CI must tag images with a stable tag or digest used by deployments:
- e.g.
my-app:main,my-app:${CI_COMMIT_SHA}.
Using OpenShift internal registry from external CI
- External CI can push directly to the in-cluster registry:
- Get registry route/URL (varies by OpenShift version).
- Create a service account with
registry-editoror appropriate role. - Generate a token and configure it as registry credentials in CI.
- Useful when images must remain internal to the cluster/network.
Jenkins and OpenShift
Jenkins is a common external CI tool in OpenShift environments.
Integration models
- Jenkins outside OpenShift, deploying into OpenShift
- Jenkins agents or controllers run outside the cluster.
- Use
ocCLI and service account tokens. - Jenkins credentials store holds:
- OpenShift API URL
- Service account token
- Registry credentials (if needed)
- Jenkins inside OpenShift (Jenkins as a deployment)
- Jenkins runs as a pod in the cluster (closer to “internal” than truly external, but often managed as separate CI).
- Automatically has access to the internal registry and API (via service accounts).
- Build agents can be ephemeral pods.
Example Jenkins pipeline snippet
pipeline {
agent any
environment {
OCP_API_URL = 'https://api.my-cluster.example.com:6443'
OCP_TOKEN = credentials('ocp-ci-token') // Jenkins credential ID
OCP_PROJECT = 'my-app'
}
stages {
stage('Login to OpenShift') {
steps {
sh """
oc login ${OCP_API_URL} \
--token=${OCP_TOKEN} \
--insecure-skip-tls-verify=false
oc project ${OCP_PROJECT}
"""
}
}
stage('Deploy') {
steps {
sh """
oc set image deployment/my-app \
my-app-container=quay.io/myorg/my-app:${GIT_COMMIT}
oc rollout status deployment/my-app --timeout=120s
"""
}
}
}
}GitHub Actions and OpenShift
GitHub Actions commonly integrates using oc plus an external registry.
Typical workflow
- Build and push the image:
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: quay.io/myorg/my-app:${{ github.sha }}- Deploy to OpenShift using
oc:
- name: Install oc
run: |
curl -L "$OC_DOWNLOAD_URL" | tar -xz
sudo mv oc /usr/local/bin
- name: Login to OpenShift
run: |
oc login ${{ secrets.OCP_API_URL }} \
--token=${{ secrets.OCP_TOKEN }} \
--insecure-skip-tls-verify=false
oc project my-app
- name: Update deployment
run: |
oc set image deployment/my-app \
my-app-container=quay.io/myorg/my-app:${{ github.sha }}
oc rollout status deployment/my-app --timeout=120sGitHub Environments and approvals
- Use GitHub Environments (e.g.
dev,staging,prod) to: - Store environment-specific OpenShift credentials.
- Require manual approvals before deploying to sensitive clusters.
- Each environment can point to different OpenShift clusters or namespaces.
GitLab CI and OpenShift
GitLab CI integrates similarly, often with GitLab’s container registry.
Example `.gitlab-ci.yml` snippet
stages:
- build
- deploy
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
- docker build -t "$IMAGE_TAG" .
- docker push "$IMAGE_TAG"
deploy:
stage: deploy
image: registry.redhat.io/openshift4/ose-cli
environment:
name: production
script:
- oc login "$OCP_API_URL" --token="$OCP_TOKEN" --insecure-skip-tls-verify=false
- oc project my-app
- oc set image deployment/my-app my-app-container="$IMAGE_TAG"
- oc rollout status deployment/my-app --timeout=120s
only:
- main- Credentials:
OCP_API_URLandOCP_TOKENstored as GitLab CI variables (protected/masked).- Registry credentials provided automatically when using GitLab Container Registry.
Azure DevOps, CircleCI, and other CI systems
The same building blocks apply across CI vendors:
- Install or use an image with
oc. - Authenticate with a service account token.
- Apply manifests or update images.
Example Azure DevOps outline
- Use a container job:
container: registry.redhat.io/openshift4/ose-cli- Steps:
bash: oc login $(OCP_API_URL) --token=$(OCP_TOKEN)bash: oc apply -f k8s/
Example CircleCI snippet
version: 2.1
jobs:
deploy:
docker:
- image: registry.redhat.io/openshift4/ose-cli
steps:
- checkout
- run:
name: Login to OpenShift
command: |
oc login "$OCP_API_URL" --token="$OCP_TOKEN"
- run:
name: Deploy
command: |
oc apply -f k8s/
oc rollout status deployment/my-app --timeout=120s
workflows:
deploy_workflow:
jobs:
- deployIntegrating external CI with OpenShift Pipelines and GitOps
External CI doesn’t have to drive deployments directly; it can instead trigger OpenShift-native deployment mechanisms.
Triggering OpenShift Pipelines (Tekton) from external CI
Possible patterns:
- CI sends a
PipelineRunto OpenShift:
oc apply -f pipelinerun.yaml- CI calls the Kubernetes API directly with a Tekton
PipelineRunmanifest. - CI stores artifacts or build results; Tekton pipelines handle deployment and cluster-side tasks.
Advantages:
- Keeps cluster-specific logic inside the cluster.
- External CI focuses on SCM integration and testing.
- Aligns with platform team ownership of deployment pipelines.
External CI with GitOps (Argo CD, etc.)
Typical GitOps integration pattern:
- External CI:
- Builds and pushes image.
- Updates image tag or manifest in a Git repo (e.g., update
kustomization.yamlor Helmvalues.yaml). - Commits and pushes changes.
- Argo CD (running in OpenShift):
- Detects Git changes.
- Syncs manifests to the cluster.
Example: update image tag in a GitOps repo from CI:
- name: Update image tag
run: |
sed -i "s|image: .*$|image: quay.io/myorg/my-app:${GIT_COMMIT}|" k8s/deployment.yaml
git config user.email "ci@example.com"
git config user.name "CI Bot"
git commit -am "Update image to ${GIT_COMMIT}"
git push origin mainThis pattern:
- Avoids direct
ocaccess from CI to production. - Centralizes deployments and drift management in Argo CD.
Designing robust OpenShift–CI workflows
When stitching external CI to OpenShift, consider:
- Environments and promotion
- Separate namespaces or clusters for dev/stage/prod.
- CI jobs per environment, or GitOps-based promotion.
- Rollback strategies
- Keep previous image tags.
- Use
oc rollout undofor Kubernetes-style deployments. - Git-based rollback (GitOps) for configuration.
- Validation gates
- Health checks and smoke tests executed from CI after deployment:
curl -f https://my-app.example.com/healthz- Policy checks (image scanning, manifest validation) before applying changes.
- Observability hooks
- CI can annotate deployments with build metadata:
oc annotate deployment/my-app \
ci.build-url="$CI_JOB_URL" \
ci.commit="$CI_COMMIT_SHA" \
--overwrite- Helps trace from cluster objects back to CI runs.
Common pitfalls and mitigation
- Over-privileged CI service accounts
- Mitigation: create dedicated namespace-scoped SAs, minimal RBAC.
- Long-lived tokens without rotation
- Mitigation: use credential management, shorter-lived tokens, regular rotation.
- CI unable to reach OpenShift API
- Mitigation: adjust network/firewall rules, private runners in same network/VPN, or prefer GitOps where only Git is needed.
- Non-reproducible deployment scripts
- Mitigation: version deployment manifests and scripts in Git; avoid ad-hoc
occommands scattered across jobs. - Tight coupling between CI and cluster details
- Mitigation: encapsulate cluster-specific logic in templates, Tekton pipelines, or GitOps repos; CI passes parameters, not raw cluster commands.
By combining these patterns, you can integrate nearly any external CI system with OpenShift in a secure, maintainable, and auditable way, while still leveraging OpenShift’s native deployment and platform capabilities.