Mark Ku's Blog

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, then docker pull
  • Kubernetes: Create a Secret of type docker-registry and reference it in your imagePullSecrets

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 ps and Windows with Get-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.

Suitable for SSH private keys, Kubeconfig files, JSON credentials, etc.

  1. When setting up the variable in GitLab, select the type File and paste the entire content directly (including newlines).
  2. 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 -x in 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: unset after 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.

Author

Mark Ku

擁有 10+ 年經驗的資深軟體工程師,現為 AI 應用 Builder,專注於大型平台架構與簡化複雜系統設計,從電商系統到訂閱與收費平台,結合 AI Agent、AI 整合與自動化開發,打造高效率且可持續演進的產品技術基礎。Read More

Found this useful?

The author's free tools, daily podcasts and newsletter are all here.

Mark Ku · This article is licensed under CC BY 4.0. Credit the author and link back to the original when reusing it.

Comments

Subscribe to Newsletter

Subscribe to get new posts delivered instantly — never miss a tech share.

By submitting, you agree to receive emails. You can anytime.

Popular Posts

View all
Mark Ku
··602

Oracle Cloud Always Free Tier: Linux Host and Static IP for a $0 Cloud Solution

Oracle Cloud Always Free Tier: Linux Host and Static IP for a $0 Cloud Solution
Mark Ku
··492

Say Goodbye to Postman's Fee Trap! A Hands-on Guide to Bruno, the Open-Source Git-Native API Testing Powerhouse.

Say Goodbye to Postman's Fee Trap! A Hands-on Guide to Bruno, the Open-Source Git-Native API Testing Powerhouse.
Mark Ku
··334

A Free, Open-Source, Notion-like Knowledge Base — A Complete Guide to Deploying and Backing Up Outline Wiki

A Free, Open-Source, Notion-like Knowledge Base — A Complete Guide to Deploying and Backing Up Outline Wiki
Mark Ku
··268

Training Your Own AI Voice: Hardware Requirements, Open-Source Model Comparison, and LoRA Fine-Tuning

Training Your Own AI Voice: Hardware Requirements, Open-Source Model Comparison, and LoRA Fine-Tuning
Mark Ku
··218

Building an Efficient API Management Platform: Deploying Kong Gateway from Scratch - Part 1

Building an Efficient API Management Platform: Deploying Kong Gateway from Scratch - Part 1
Mark Ku
··217

Setting Up Samba on Ubuntu to Share Folders with Windows 11

Setting Up Samba on Ubuntu to Share Folders with Windows 11
Docker 及 K8s 如何拉取映像檔 - Mark Ku's Tech Notes