Set up Nexus Repository Manager as a private Docker registry integrated with Kubernetes clusters, configure secure authentication and authorization, and enable automated container image deployment with RBAC controls.
Prerequisites
- Kubernetes cluster with admin access
- Docker installed and configured
- Valid SSL certificates for domain names
- Minimum 8GB RAM available for Nexus deployment
What this solves
Integrating Nexus Repository Manager with Kubernetes enables centralized management of container images, artifacts, and dependencies in enterprise environments. This setup provides secure private registry capabilities with authentication controls, allowing Kubernetes clusters to pull images from Nexus while maintaining security policies and access controls.
Step-by-step configuration
Install Docker and Kubernetes prerequisites
Install Docker runtime and Kubernetes tools required for managing the cluster and container operations.
sudo apt update && sudo apt upgrade -y
sudo apt install -y docker.io kubectl
sudo systemctl enable --now docker
sudo usermod -aG docker $USERDeploy Nexus Repository Manager on Kubernetes
Create a dedicated namespace and deploy Nexus using a Deployment with persistent storage for repository data.
kubectl create namespace nexus-system
kubectl config set-context --current --namespace=nexus-systemapiVersion: apps/v1
kind: Deployment
metadata:
name: nexus-repository
namespace: nexus-system
spec:
replicas: 1
selector:
matchLabels:
app: nexus-repository
template:
metadata:
labels:
app: nexus-repository
spec:
containers:
- name: nexus
image: sonatype/nexus3:3.45.0
ports:
- containerPort: 8081
- containerPort: 8082
env:
- name: INSTALL4J_ADD_VM_PARAMS
value: "-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g"
volumeMounts:
- name: nexus-data
mountPath: /nexus-data
resources:
requests:
memory: "4Gi"
cpu: "1000m"
limits:
memory: "6Gi"
cpu: "2000m"
volumes:
- name: nexus-data
persistentVolumeClaim:
claimName: nexus-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nexus-pvc
namespace: nexus-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
---
apiVersion: v1
kind: Service
metadata:
name: nexus-service
namespace: nexus-system
spec:
selector:
app: nexus-repository
ports:
- name: web
port: 8081
targetPort: 8081
- name: docker
port: 8082
targetPort: 8082
type: ClusterIPkubectl apply -f nexus-deployment.yamlConfigure Ingress for Nexus access
Set up an Ingress resource to expose Nexus web interface and Docker registry endpoints with SSL termination.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nexus-ingress
namespace: nexus-system
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- nexus.example.com
- docker.example.com
secretName: nexus-tls
rules:
- host: nexus.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nexus-service
port:
number: 8081
- host: docker.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nexus-service
port:
number: 8082kubectl apply -f nexus-ingress.yamlWait for Nexus deployment and retrieve admin password
Monitor the deployment status and extract the initial admin password from the Nexus container.
kubectl get pods -n nexus-system -wkubectl exec -it deployment/nexus-repository -n nexus-system -- cat /nexus-data/admin.passwordConfigure Docker registry in Nexus
Access the Nexus web interface and create a Docker hosted repository for storing private images.
- Log in with username
adminand the password from the previous step - Navigate to Settings → Repositories → Create repository
- Select
docker (hosted)repository type - Configure the repository settings:
Name: docker-private
HTTP Port: 8082
Enable Docker V1 API: checked
Allow anonymous docker pull: unchecked
Enable Docker Bearer Token Realm: checkedConfigure authentication realm
Enable Docker Bearer Token Realm to support Docker registry authentication with Nexus users.
- Navigate to Settings → Security → Realms
- Move
Docker Bearer Token Realmfrom Available to Active - Click Save to apply the configuration
Create Nexus service account
Create a dedicated service account in Nexus for Kubernetes to authenticate with the Docker registry.
- Navigate to Settings → Security → Users → Create user
- Configure the service account:
ID: k8s-registry
First Name: Kubernetes
Last Name: Registry
Email: k8s-registry@example.com
Status: Active
Roles: nx-repository-view-docker-docker-private-*Create Kubernetes Docker registry secret
Generate a Kubernetes secret containing Docker registry credentials for authenticating with the Nexus repository.
kubectl create secret docker-registry nexus-registry-secret \
--docker-server=docker.example.com \
--docker-username=k8s-registry \
--docker-password=your-service-account-password \
--docker-email=k8s-registry@example.com \
-n defaultConfigure RBAC for service accounts
Create a dedicated service account and configure Role-Based Access Control for secure container operations.
apiVersion: v1
kind: ServiceAccount
metadata:
name: nexus-puller
namespace: default
imagePullSecrets:
- name: nexus-registry-secret
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: image-puller
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: nexus-puller-binding
namespace: default
subjects:
- kind: ServiceAccount
name: nexus-puller
namespace: default
roleRef:
kind: Role
name: image-puller
apiGroup: rbac.authorization.k8s.iokubectl apply -f rbac-config.yamlTest Docker registry authentication
Verify that Docker can authenticate with the Nexus registry and push/pull images successfully.
echo "your-service-account-password" | docker login docker.example.com -u k8s-registry --password-stdindocker pull nginx:alpine
docker tag nginx:alpine docker.example.com/nginx:alpine
docker push docker.example.com/nginx:alpineDeploy test application using private registry
Create a test deployment that pulls images from the Nexus private registry using the configured authentication.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-from-nexus
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx-from-nexus
template:
metadata:
labels:
app: nginx-from-nexus
spec:
serviceAccountName: nexus-puller
containers:
- name: nginx
image: docker.example.com/nginx:alpine
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
imagePullSecrets:
- name: nexus-registry-secret
---
apiVersion: v1
kind: Service
metadata:
name: nginx-from-nexus
namespace: default
spec:
selector:
app: nginx-from-nexus
ports:
- port: 80
targetPort: 80
type: ClusterIPkubectl apply -f test-deployment.yamlConfigure automatic secret propagation
Set up automatic propagation of Docker registry secrets across namespaces for streamlined deployment workflows.
apiVersion: v1
kind: ConfigMap
metadata:
name: registry-config
namespace: kube-system
data:
config.yaml: |
registries:
"docker.example.com":
username: k8s-registry
password: your-service-account-password
---
apiVersion: batch/v1
kind: Job
metadata:
name: propagate-registry-secret
namespace: kube-system
spec:
template:
spec:
serviceAccountName: secret-propagator
containers:
- name: kubectl
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
if [ "$ns" != "kube-system" ] && [ "$ns" != "kube-public" ]; then
kubectl create secret docker-registry nexus-registry-secret \
--docker-server=docker.example.com \
--docker-username=k8s-registry \
--docker-password=your-service-account-password \
--docker-email=k8s-registry@example.com \
-n "$ns" --dry-run=client -o yaml | kubectl apply -f -
fi
done
restartPolicy: OnFailure
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: secret-propagator
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-propagator
rules:
- apiGroups: [""]
resources: ["secrets", "namespaces"]
verbs: ["get", "list", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: secret-propagator
subjects:
- kind: ServiceAccount
name: secret-propagator
namespace: kube-system
roleRef:
kind: ClusterRole
name: secret-propagator
apiGroup: rbac.authorization.k8s.iokubectl apply -f secret-propagation.yamlVerify your setup
Confirm that all components are functioning correctly and images can be pulled from the private registry.
kubectl get pods -n nexus-system
kubectl get deployment nginx-from-nexus
kubectl get secrets nexus-registry-secret
kubectl describe pod -l app=nginx-from-nexuscurl -u k8s-registry:your-service-account-password https://docker.example.com/v2/_catalog
docker images | grep docker.example.comCommon issues
| Symptom | Cause | Fix |
|---|---|---|
| ImagePullBackOff error | Invalid registry credentials | Recreate secret with correct credentials: kubectl delete secret nexus-registry-secret && kubectl create secret docker-registry... |
| x509 certificate error | Self-signed certificate issues | Add certificate to Docker daemon config or use --insecure-registry flag for testing |
| Nexus pod fails to start | Insufficient resources | Increase memory limits in deployment: minimum 4Gi for production use |
| Cannot push to registry | Docker Bearer Token Realm disabled | Enable realm in Nexus: Settings → Security → Realms → Activate Docker Bearer Token Realm |
| Service account lacks permissions | Missing RBAC configuration | Apply RBAC manifests: kubectl apply -f rbac-config.yaml |
| Registry not accessible | Ingress configuration issues | Check ingress status: kubectl describe ingress nexus-ingress -n nexus-system |
Next steps
- Set up Nexus Repository Manager high availability clustering for production scale
- Implement Kubernetes network policies with Calico CNI and OPA Gatekeeper for security enforcement
- Configure Kubernetes persistent volumes with NFS storage for container data persistence
- Set up Kubernetes container image security scanning with Trivy and admission controllers
- Implement Kubernetes secrets management with HashiCorp Vault integration
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default values
DOMAIN="${1:-nexus.example.com}"
DOCKER_DOMAIN="${2:-docker.example.com}"
NAMESPACE="nexus-system"
# Usage message
usage() {
echo "Usage: $0 [nexus-domain] [docker-domain]"
echo "Example: $0 nexus.mycompany.com docker.mycompany.com"
exit 1
}
# Error handling
cleanup() {
echo -e "${RED}Error occurred. Cleaning up...${NC}"
kubectl delete namespace $NAMESPACE --ignore-not-found=true
rm -f /tmp/nexus-*.yaml
}
trap cleanup ERR
# Logging functions
log_info() { echo -e "${GREEN}$1${NC}"; }
log_warn() { echo -e "${YELLOW}$1${NC}"; }
log_error() { echo -e "${RED}$1${NC}"; }
# Check if running as root or with sudo
if [[ $EUID -ne 0 ]] && ! groups | grep -q sudo; then
log_error "This script requires root privileges or sudo access"
exit 1
fi
# Validate arguments
if [[ $# -gt 2 ]]; then
usage
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
log_info "[1/8] Updating system packages..."
if [[ $EUID -eq 0 ]]; then
$PKG_UPDATE
else
sudo $PKG_UPDATE
fi
log_info "[2/8] Installing Docker and prerequisites..."
if [[ "$PKG_MGR" == "apt" ]]; then
DOCKER_PKG="docker.io"
if [[ $EUID -eq 0 ]]; then
$PKG_INSTALL curl wget gnupg lsb-release ca-certificates $DOCKER_PKG
else
sudo $PKG_INSTALL curl wget gnupg lsb-release ca-certificates $DOCKER_PKG
fi
else
DOCKER_PKG="docker"
if [[ $EUID -eq 0 ]]; then
$PKG_INSTALL curl wget ca-certificates $DOCKER_PKG
else
sudo $PKG_INSTALL curl wget ca-certificates $DOCKER_PKG
fi
fi
log_info "[3/8] Configuring Docker service..."
if [[ $EUID -eq 0 ]]; then
systemctl enable --now docker
usermod -aG docker $SUDO_USER 2>/dev/null || usermod -aG docker $(whoami)
else
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
fi
log_info "[4/8] Installing kubectl..."
KUBECTL_VERSION=$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)
if [[ $EUID -eq 0 ]]; then
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl"
chmod 755 kubectl
mv kubectl /usr/local/bin/
else
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$KUBECTL_VERSION/bin/linux/amd64/kubectl"
chmod 755 kubectl
sudo mv kubectl /usr/local/bin/
fi
log_info "[5/8] Checking Kubernetes cluster connectivity..."
if ! kubectl cluster-info &>/dev/null; then
log_error "Cannot connect to Kubernetes cluster. Ensure kubectl is configured with valid context."
exit 1
fi
log_info "[6/8] Creating Nexus namespace..."
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
kubectl config set-context --current --namespace=$NAMESPACE
log_info "[7/8] Deploying Nexus Repository Manager..."
cat > /tmp/nexus-deployment.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nexus-repository
namespace: $NAMESPACE
spec:
replicas: 1
selector:
matchLabels:
app: nexus-repository
template:
metadata:
labels:
app: nexus-repository
spec:
securityContext:
fsGroup: 200
containers:
- name: nexus
image: sonatype/nexus3:3.45.0
ports:
- containerPort: 8081
- containerPort: 8082
env:
- name: INSTALL4J_ADD_VM_PARAMS
value: "-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g"
volumeMounts:
- name: nexus-data
mountPath: /nexus-data
resources:
requests:
memory: "4Gi"
cpu: "1000m"
limits:
memory: "6Gi"
cpu: "2000m"
securityContext:
runAsUser: 200
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
readinessProbe:
httpGet:
path: /service/rest/v1/status
port: 8081
initialDelaySeconds: 60
periodSeconds: 30
livenessProbe:
httpGet:
path: /service/rest/v1/status
port: 8081
initialDelaySeconds: 120
periodSeconds: 60
volumes:
- name: nexus-data
persistentVolumeClaim:
claimName: nexus-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nexus-pvc
namespace: $NAMESPACE
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
---
apiVersion: v1
kind: Service
metadata:
name: nexus-service
namespace: $NAMESPACE
spec:
selector:
app: nexus-repository
ports:
- name: web
port: 8081
targetPort: 8081
- name: docker
port: 8082
targetPort: 8082
type: ClusterIP
EOF
kubectl apply -f /tmp/nexus-deployment.yaml
cat > /tmp/nexus-ingress.yaml <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nexus-ingress
namespace: $NAMESPACE
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: $DOMAIN
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nexus-service
port:
number: 8081
- host: $DOCKER_DOMAIN
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nexus-service
port:
number: 8082
EOF
kubectl apply -f /tmp/nexus-ingress.yaml
log_info "[8/8] Waiting for Nexus deployment to be ready..."
kubectl wait --for=condition=available --timeout=600s deployment/nexus-repository -n $NAMESPACE
log_info "Deployment completed successfully!"
log_info "Nexus Repository Manager is accessible at: https://$DOMAIN"
log_info "Docker registry endpoint: https://$DOCKER_DOMAIN"
echo ""
log_warn "Next steps:"
echo "1. Retrieve admin password:"
echo " kubectl exec -it deployment/nexus-repository -n $NAMESPACE -- cat /nexus-data/admin.password"
echo "2. Access Nexus web interface and create Docker repositories"
echo "3. Configure authentication in Nexus for Docker registry access"
echo "4. Create Kubernetes secret for Docker registry authentication"
# Cleanup temporary files
rm -f /tmp/nexus-*.yaml
# Verification
log_info "Verifying deployment..."
if kubectl get pods -n $NAMESPACE | grep -q "Running"; then
log_info "✓ Nexus pod is running"
else
log_error "✗ Nexus pod is not running"
fi
if kubectl get svc -n $NAMESPACE nexus-service &>/dev/null; then
log_info "✓ Nexus service is created"
else
log_error "✗ Nexus service not found"
fi
if kubectl get ingress -n $NAMESPACE nexus-ingress &>/dev/null; then
log_info "✓ Nexus ingress is configured"
else
log_error "✗ Nexus ingress not found"
fi
log_info "Installation complete! Please configure DNS to point $DOMAIN and $DOCKER_DOMAIN to your ingress controller."
Review the script before running. Execute with: bash install.sh