1. Overview
In containerized deployments, securely and reliably pulling private images is a common requirement. This article will concisely explain two things:
- How to pull an image from a GitLab Registry with Docker on a local machine or VM
- How to pull the same image within a Kubernetes cluster using an ImagePullSecret
TL;DR
- Docker: First, use a Deploy Token to
docker login, thendocker pull- Kubernetes: Create a Secret of type
docker-registryand reference it in yourimagePullSecrets
2. How Docker Pulls a GitLab Image
2.1 Obtain a GitLab Deploy Token
Go to your project → Settings → Repository → Deploy tokens
Select the required permissions:
- read_registry → To pull an image
- write_registry → To push an image
P.S. If you have Group permissions, you can also create a Group Access Token, which allows you to pull images across multiple projects.
Take note of the username and password provided by GitLab.
2.2 Docker Authentication and Pulling (Local/VM)
# 清除舊認證(可選)
docker logout registry.abc.com
# 使用 Deploy Token 登入(建議用 --password-stdin)
echo "<deploy_token_password>" | docker login registry.abc.com -u <deploy_token_username> --password-stdin
# 拉取測試
docker pull registry.abc.com/kong/kong-api-gateway/main:70368
Why is it recommended to use --password-stdin?
- Prevents the password from appearing in your command-line history (e.g.,
~/.bash_history, PowerShell history). - Prevents the password from being exposed in the system process list (parameters are visible in Linux with
psand Windows withGet-CimInstance Win32_Process). - Ideal for non-interactive CI/CD environments, and is more secure when paired with masked environment variables (masked secrets).
- The official recommendation is to avoid using plaintext parameters with
--password; using standard input is more secure and auditable.
Example (a more secure, one-time input):
# Bash / Linux / macOS:建議用 printf 避免 echo 行為差異
printf "%s" "$DEPLOY_TOKEN" | docker login registry.abc.com -u "$DEPLOY_USER" --password-stdin
# Windows PowerShell
$Env:DEPLOY_TOKEN | docker login registry.abc.com -u $Env:DEPLOY_USER --password-stdin
2.3 For Registries Without HTTPS (Insecure Registry)
If your registry does not use HTTPS, you need to configure insecure-registries in the Docker Daemon settings:
# 編輯 Docker daemon 配置
sudo nano /etc/docker/daemon.json
# 加入以下內容
{
"insecure-registries": ["registry.abc.com:5000", "192.168.1.100:5000"]
}
# 重啟 Docker 服務
sudo systemctl restart docker
# 或者重啟 Docker Desktop (Windows/Mac)
Notes:
- Using an HTTP registry is not recommended for production environments.
- If you are using a self-hosted GitLab registry, it's recommended to configure an SSL certificate.
- You can use HTTP in development environments, but be mindful of the security implications.
3. How to Pull Images in Kubernetes
3.1 Create an ImagePullSecret
Create a Secret of type docker-registry in the namespace where you plan to deploy:
# 建立 Docker Registry Secret
kubectl create secret docker-registry kong-api-gateway-secret \
--docker-server=registry.abc.com \
--docker-username=<deploy_token_username> \
--docker-password=<deploy_token_password> \
--docker-email=none \
-n <your-namespace>
3.2 Reference it in a Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: kong-api-gateway
spec:
replicas: 1
selector:
matchLabels:
app: kong-api-gateway
template:
metadata:
labels:
app: kong-api-gateway
spec:
containers:
- name: kong
image: registry.abc.com/kong/kong-api-gateway/main:70368
ports:
- containerPort: 8000
imagePullSecrets:
- name: kong-api-gateway-secret
3.3 Verify the Functionality
# 檢查 Secret 是否建立成功(命名空間必須正確)
kubectl get secret kong-api-gateway-secret -n <your-namespace> -o yaml
# 重新建立 Secret
kubectl delete secret kong-api-gateway-secret -n <your-namespace>
kubectl create secret docker-registry kong-api-gateway-secret \
--docker-server=registry.abc.com \
--docker-username=<deploy_token_username> \
--docker-password=<deploy_token_password> \
--docker-email=none \
-n <your-namespace>
Additional Notes
- Secrets are namespace-scoped and must be in the same namespace as the workload.
- To allow all Pods in a namespace to automatically pull private images, you can add the Secret to the default ServiceAccount for that namespace.
- Secrets cannot be shared across namespaces. If needed, create or sync them in each target namespace individually.
# 檢查 Secret 是否存在於指定命名空間
kubectl get secret kong-api-gateway-secret -n <your-namespace>
# 將 Secret 掛到該命名空間的 default ServiceAccount
kubectl patch serviceaccount default -n <your-namespace> -p '{"imagePullSecrets":[{"name":"kong-api-gateway-secret"}]}'
4. Addendum: GitLab Key Security
When using keys or passwords in GitLab, keep the following points in mind to prevent leaks:
4.1 Masked Variables
- Functionality: When enabled, the variable's value will be replaced with
[MASKED]in CI logs, hiding its actual content. - Limitations: Must conform to GitLab's rules (at least 8 characters, alphanumeric + some symbols). It does not support spaces or newlines.
- Recommendation: If your secret contains newlines or special characters, use a File variable or Base64 encode it first.
- More Secure: Also set it as Protected to restrict its use to protected branches/tags only.
4.2 File-Type Variables (Recommended for Multi-line Keys)
Suitable for SSH private keys, Kubeconfig files, JSON credentials, etc.
- When setting up the variable in GitLab, select the type File and paste the entire content directly (including newlines).
- In the pipeline, the variable will resolve to a file path, not a string.
Example:
chmod 600 "$SSH_PRIVATE_KEY"
GIT_SSH_COMMAND="ssh -i $SSH_PRIVATE_KEY -o StrictHostKeyChecking=no" \
git ls-remote [email protected]:group/project.git
4.3 Avoid Printing Secrets
- Use standard input to pass passwords to avoid them appearing in command-line or shell history.
- Turn off
set -xin sections where secrets are handled.
Example:
printf "%s" "$DEPLOY_TOKEN" | docker login registry.abc.com -u "$DEPLOY_USER" --password-stdin
4.4 Principle of Least Privilege
- Grant only the necessary permissions (e.g., a Deploy Token only needs
read_registry). - Scope variables to specific branches or environments.
- Tokens should have an expiration date and be rotated regularly.
4.5 Password Security Best Practices
--password-stdin: Prevents passwords from appearing in the command line.- File/Masked/Protected variables: Prevent leaks in CI logs.
- K8s ImagePullSecret: Avoid hardcoding credentials in YAML files.
- Additional Recommendations:
unsetafter use, delete temporary files, enable cleanup on the Runner, and enable Secret encryption in Kubernetes.
4.6 Common Mistakes (What Not to Do)
- Hardcoding passwords in
docker login -p, Dockerfiles, YAML, or .env files. - Pasting full error messages or logs containing secrets into MRs, issues, or chat.
- Reusing the same secret for different purposes across namespaces.





























Comments