Purpose: A focused guide for resolving issues where kubelet fails to pull images from Harbor in a Minikube environment. Rather than explaining complex network architecture, this guide covers only the problem scenarios and their solutions.
1. Symptoms
- Pods can successfully resolve service names like
harbor-core.harbor.svc.cluster.localvia CoreDNS and communicate normally. - However, kubelet (containerd/docker) fails when attempting to pull images from the Harbor registry:
x509: certificate signed by unknown authorityno such hostconnection refusedTemporary failure in name resolution
Root Cause
- The entity performing the image pull is kubelet/the runtime (= the Minikube VM) → outside the scope of CoreDNS.
- Therefore, the pull will only succeed if the Harbor FQDN is resolvable from the Minikube VM’s perspective and TLS is trusted.
2. Common Failure Types and Solutions
(1) no such host / Temporary failure in name resolution
Cause: The kubelet runtime cannot resolve the FQDN.
Solution:
# Minikube VM /etc/hosts 에 LB IP 또는 NodePort IP 매핑
minikube ssh -- "echo '<LB_IP> harbor.local.test' | sudo tee -a /etc/hosts"
- The LB IP is assigned via
minikube tunnel, or alternatively as aminikube ip+ NodePort combination. - When using nip.io, avoid
harbor.127.0.0.1.nip.io(it always short-circuits to 127.0.0.1).
(2) x509: certificate signed by unknown authority
Cause: The kubelet runtime (containerd/docker) does not trust the Harbor TLS certificate.
Solution:
# VM에 사설 CA 설치
minikube scp ./rootCA.crt minikube:/home/docker/rootCA.crt
minikube ssh -- "sudo mkdir -p /usr/local/share/ca-certificates && sudo mv /home/docker/rootCA.crt /usr/local/share/ca-certificates/harbor-rootCA.crt && (sudo update-ca-certificates || sudo update-ca-trust) && (sudo systemctl restart containerd || sudo systemctl restart docker)"
- The FQDN you are accessing must be included in the certificate’s SAN (Subject Alternative Name).
(3) denied: requested access to the resource is denied
Cause: Insufficient Harbor project access permissions or missing ImagePullSecret.
Solution:
kubectl -n <NAMESPACE> create secret docker-registry harbor-creds \
--docker-server=harbor.local.test \
--docker-username=<USER> \
--docker-password=<PASS> \
--docker-email=<EMAIL>
kubectl -n <NAMESPACE> patch serviceaccount default \
-p '{"imagePullSecrets": [{"name": "harbor-creds"}]}'
(4) connection refused / timeout
Cause: Wrong port (NodePort/LB IP not used), minikube tunnel not executed, or firewall blocking.
Solution:
kubectl -n harbor get svc,ingress -o wide
minikube tunnel # Ingress LB 사용 시 필수
3. Jenkins Build Container Issue (-add-host)
- The Jenkins build container internally uses only its own
/etc/hosts. - When using nip.io, it may incorrectly resolve to
127.0.0.1.
Solution (Pipeline Example):
sh """
docker build \
--add-host harbor.local.test:<LB_IP> \
--add-host nexus.local.test:<LB_IP> \
-t myimage:latest .
"""
<LB_IP>is the IP assigned byminikube tunnel.
4. Diagnostic Commands
# Minikube VM에서 이름 해석
minikube ssh -- "getent hosts harbor.local.test"
# Minikube 런타임에서 직접 Pull
minikube ssh -- "ctr -n k8s.io images pull harbor.local.test/library/alpine:3"
# TLS 확인
minikube ssh -- "echo | openssl s_client -connect harbor.local.test:443 -servername harbor.local.test"
5. Temporary Workaround (Jenkins Pipeline -add-host)
Before fundamentally resolving the network/CA configuration, you can apply a temporary fix in the Jenkins build pipeline by using the --add-host option to correct /etc/hosts inside the build container.
5.1 How It Works
- At
docker buildtime, pass-add-host FQDN:IPso that the build container resolves Harbor/Nexus FQDNs to the correct IP (LB IP or Minikube IP). - When using nip.io,
harbor.127.0.0.1.nip.ioalways short-circuits to loopback, so you must force a mapping like-add-host harbor.local.test:<LB_IP>to route traffic through the Ingress.
5.2 Jenkins Script Example
// Host IP 탐색 로직 (minikube ip, default gw 등)
def hostIP = sh(
script: '''
minikube ip 2>/dev/null || ip route | awk '/default/ {print $3; exit}' || echo 172.17.0.1
''',
returnStdout: true
).trim()
echo "Host IP: ${hostIP}"
sh """
docker build \
--build-arg NEXUS_URL=${env.NEXUS_URL} \
--build-arg NEXUS_PYPI_URL=${env.NEXUS_PYPI_URL} \
--add-host harbor.local.test:${hostIP} \
--add-host nexus.local.test:${hostIP} \
-t ${env.LOCAL_IMAGE} .
"""
5.3 Limitations
- Only effective inside the Jenkins build container → pull issues at the kubelet runtime level must still be resolved on the Minikube VM side.
- If the IP changes, the pipeline must be updated accordingly.
6. Summary Checklist
6. Recommended Approach (Best Practice)
Beyond quick troubleshooting — how to build a stable environment for the long term.
6.1 Ingress + Fixed FQDN + Single TLS Secret
- Expose Harbor via Ingress and use a fixed domain (
harbor.lab.local). - Avoid nip.io; always use a certificate that includes the relevant FQDN in its SAN.
- Assign a single TLS secret (wildcard or bundled SANs) to the Ingress Controller.
6.2 Standardize DNS / Name Resolution
- Configure macOS, the Minikube VM, and Jenkins build containers to all resolve the same FQDN.
- For personal environments: pin
<LB_IP> harbor.lab.localto a fixed entry in/etc/hosts. - For team environments: register in a private DNS server (dnsmasq, internal DNS).
6.3 Distribute Private CA Trust
- Install the Root CA on the Minikube VM so that containerd/docker trusts the Harbor certificate.
- Inject the CA into Jenkins build containers as needed (via base image or pipeline injection).
6.4 Consolidate ImagePullSecret
- Create a
docker-registrySecret using a Harbor user/Robot Token. - Attach it to the default ServiceAccount in each namespace so it applies automatically to all Pods.
6.5 Testing and Validation
# Minikube VM 런타임 관점에서 Pull
minikube ssh -- "ctr -n k8s.io images pull harbor.lab.local/library/alpine:3"
# Pod 관점에서 Pull
kubectl run test --image=harbor.lab.local/library/alpine:3 --rm -it --restart=Never
Conclusion
Troubleshooting measures like modifying hosts files or using add-host flags are temporary fixes.
The proper solution is to ensure all parties — kubelet, build containers, and local machines — reach Harbor through a consistent path by adopting Ingress + fixed FQDN + single TLS + centralized DNS/CA management.