Container Registry, Package Registry, Generic Packages, Dependency Proxy, and Artifact Promotion: Concepts, Architecture, and Mental Model
Model GitLab registries as versioned distribution systems where producer SHA, authentication identity, immutable version or digest, consumer pull, promotion, and retention remain independently provable.
Learning objectives
- Distinguish CI artifacts from package/container registries and explain when a durable distribution coordinate is required.
- Trace source SHA → producer job → authenticated publication → version/tag/digest → consumer pull → promotion → retention.
- Explain why a container tag is a convenient label but a manifest digest is the immutable distribution identity.
- Explain why a Dependency Proxy reduces upstream pulls but does not establish provenance.
- Inspect registry/package identity and authorization without printing credentials or mutating unrelated objects.
1. The practical problem: a green build does not make an artifact safely distributable
Chapter 22 bound a release record to an exact tag, source SHA, and verified artifact digest. Chapter 23 asks where those bytes should live so downstream pipelines and environments can retrieve them repeatedly without rebuilding. A CI artifact is excellent pipeline evidence, but it may expire. A registry or package repository gives the object a durable coordinate, authentication boundary, metadata, and lifecycle policy.
The failure mode is subtle: teams often publish only
latest, rebuild separately for staging and production,
or trust a proxy cache as if it proves origin. Those patterns break
the chain from tested bytes to deployed bytes.
2. Terms before commands
| Term | Meaning in this chapter | Important boundary |
|---|---|---|
| Package Registry | GitLab-hosted package distribution for npm, Maven, PyPI, NuGet, Generic Packages, and other supported formats. | It stores distribution objects; it is not the runner workspace or CI artifact store. |
| Generic Package | A named/versioned collection of arbitrary files published through the package API. | Generic duplicate files are allowed by default unless group duplicate settings restrict them. |
| Container Registry | OCI/Docker image distribution attached to a GitLab project. | A tag can move; a manifest digest identifies immutable registry content. |
| Dependency Proxy | Group-level pull-through cache for Docker Hub images. | Caching improves reliability/rate-limit behavior but does not replace digest pinning or provenance. |
| Promotion | Making already-built bytes eligible for another consumer/environment. | Do not rebuild per environment. Reference or copy verified bytes and re-check digest. |
| Protected package/tag | Role-based restriction on publishing/deleting matching names/tags. | Protection controls actors; it is not the same as immutable content addressing. |
| Retention/cleanup | Rules that remove old assets/tags to manage storage. | Cleanup is lifecycle policy, not a provenance decision. |
3. State model: distribution adds a durable identity layer
| State layer | Evidence to capture | Why it matters |
|---|---|---|
| Source/revision |
CI_PIPELINE_SOURCE, ref,
CI_COMMIT_SHA, producer pipeline/job IDs
|
Connects distributed bytes to the source and execution that produced them. |
| Compiled configuration | Merged YAML, rules result, image/tool versions | Proves which publication/pull jobs GitLab actually created. |
| Identity/trust | Token class, source project, target allowlist/role result; never token value | Explains why a push/pull was authorized or denied. |
| Registry/package | Package path/version/file checksum or image repository/tag/manifest digest | Names the durable distribution object. |
| Consumer/promotion |
Exact URL or @sha256 reference, download/pull
digest, target manifest
|
Proves consumers and promoted environments use the same bytes. |
| Retention/governance | Protection rule, duplicate policy, cleanup rule, exact cleanup target | Prevents retention from silently destroying release evidence. |
| External state | Runtime/deployment reference to exact package version or image digest | Separates registry success from deployment and health. |
4. Mental model: build once, publish once, consume by immutable identity
A producer job starts from an exact source SHA and creates bytes. Before publication it computes a checksum. Authentication authorizes publication to one package path or image repository. The registry assigns durable metadata: package name/version/file checksum or image manifest digest. Downstream consumers retrieve that exact identity and verify it. Promotion changes which environment or policy points at the object; it should not invoke a second build.
flowchart LR
A[Source SHA + producer pipeline] --> B[Build bytes once]
B --> C[Authenticate to registry]
C --> D[Publish version/tag]
D --> E[Record checksum or manifest digest]
E --> F[Consumer pulls immutable identity]
F --> G[Promotion reference]
G --> H[Retention / protected cleanup]
H --> I[Deployment and health verified separately]
5. Generic Packages: explicit coordinates and stored checksums
A Generic Package file is addressed by project, package name,
package version, and file name. GitLab accepts
CI_JOB_TOKEN for CI automation and stores checksums for
uploaded files. That makes Generic Packages a useful mandatory lab
path because it needs no privileged container daemon.
PACKAGE_NAME="glci-ch23-demo"
PACKAGE_VERSION="0.0.0-${CI_PIPELINE_ID}"
FILE="dist/payload.txt"
sha256sum "$FILE" | tee evidence/payload.sha256
curl --fail --location \
--header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
--upload-file "$FILE" \
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${PACKAGE_NAME}/${PACKAGE_VERSION}/payload.txt"
6. Container images: tag for humans, digest for machines
A container tag such as 1.4.0 or main is a
mutable reference unless stronger controls prevent updates. After
push, capture the registry manifest digest and use
repository@sha256:… for deployment/promotion evidence.
Do not confuse a local Docker image ID with the registry manifest
digest.
| Identity | Can move? | Use |
|---|---|---|
image:latest |
Yes | Human convenience only; never sole release evidence. |
image:v1.4.0 |
Potentially, unless policy prevents overwrite | Readable release label; verify what digest it resolves to. |
image@sha256:… |
Content-addressed | Preferred machine identity for reproducible pull/deploy. |
7. Authentication is part of provenance
Within the same project, CI provides
CI_REGISTRY_USER/CI_REGISTRY_PASSWORD for
container-registry push/pull and CI_JOB_TOKEN for
package APIs. For external systems, deploy tokens can use narrow
read_registry, write_registry,
read_package_registry, or
write_package_registry scopes. Cross-project job-token
access adds two gates: the target project allowlist and the
permissions of the user who started the job.
--password-stdin; do not place credentials in image
names, URLs, command-line arguments, or captured logs.
8. Dependency Proxy: availability optimization, not provenance
The Dependency Proxy is group-level and acts as a pull-through cache for Docker Hub images. In CI, GitLab supplies dependency-proxy variables and can authenticate automatically. If a Docker Hub tag moves, the proxy still does not transform that tag into trusted provenance. Reproducible consumption needs a verified upstream digest and appropriate source trust.
| Question | Dependency Proxy helps? | Still required |
|---|---|---|
| Reduce repeated upstream pulls | Yes | Monitor cache/storage and upstream behavior. |
| Mitigate Docker Hub rate pressure | Yes | Authenticate and respect upstream terms. |
| Prove image source integrity | No | Pin/verify digest and provenance separately. |
| Store your project image | No | Use the project Container Registry. |
9. Read-only inspection first
printf 'source=%s ref=%s sha=%s pipeline=%s job=%s\n' \
"$CI_PIPELINE_SOURCE" "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA" \
"$CI_PIPELINE_ID" "$CI_JOB_ID"
printf 'registry=%s image=%s project=%s\n' \
"$CI_REGISTRY" "$CI_REGISTRY_IMAGE" "$CI_PROJECT_PATH"
# Inspect package/download coordinates; never dump the token itself.
printf 'package=%s version=%s\n' "$PACKAGE_NAME" "$PACKAGE_VERSION"
10. Common mistakes and safer patterns
| Mistake | Causal problem | Safer pattern |
|---|---|---|
Publish only latest |
Consumers cannot prove which bytes were used. | Publish a unique version and capture digest/checksum. |
| Rebuild for production | Promotion changes bytes instead of authorization/reference. | Promote the exact object already tested. |
| Assume proxy cache = provenance | Cache says where bytes were fetched through, not whether they are trusted. | Pin digest and verify source/provenance. |
| Use deploy token everywhere | Longer-lived credential expands blast radius. | Prefer ephemeral job identity in CI; use deploy token for non-CI integration only. |
| Apply broad cleanup regex immediately | Can erase release evidence or rollback targets. | Start narrow, dry-run/inspect, protect important tags/packages, then expand cautiously. |
Knowledge check
Why is a container manifest digest stronger evidence than a tag?
A digest is content-addressed. A tag is a mutable name unless policy prevents changes.
What does a Generic Package coordinate need besides the project?
Package name, package version, and file name. The downloaded bytes should also be verified by checksum.
Does a CI job-token allowlist grant project membership?
No. The source project must be allowlisted when required, and the triggering user must already have the permissions needed for the target resource.
What problem does the Dependency Proxy solve?
It is a group-level pull-through cache that reduces repeated Docker Hub pulls and can improve availability/rate-limit behavior; it does not prove provenance.
What should promotion change?
A policy, environment reference, or distribution tag/pointer that resolves to the same verified bytes—not the bytes themselves.
Version and compatibility note
GitLab and GitLab Runner evolve continuously. Treat version-sensitive YAML, runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations as assumptions to verify against the current official GitLab documentation before production use. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for any reproducible lab or incident record.
Official references and version notes
Documentation verification date: 2026-09-12. Generic Packages, Package Registry, Container Registry, Dependency Proxy, protected packages, and protected container tags are documented for Free/Premium/Ultimate unless noted otherwise. Current immutable container-tag rules are Ultimate-only. Dependency Proxy is group-level and supports Docker Hub images. Current protected-container-tag rules are Free and protected tags are excluded from container cleanup policies. Container tag immutability is an Ultimate feature, so the chapter teaches digest pinning as the mandatory portable path.
- Package registry — official reference.
- Generic packages — official reference.
- Supported package functionality — official reference.
- Protected packages — official reference.
- Reduce package registry storage — official reference.
- Container registry — official reference.
- Container registry authentication — official reference.
- Protected container tags — official reference.
- Immutable container tags — official reference.
- Reduce container registry storage — official reference.
- Dependency Proxy — official reference.
- CI job token — official reference.
Current assumptions used in this chapter: Version-sensitive YAML, Runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations must be verified against the exact GitLab, GitLab Runner, tool, and external-system versions used in production. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for reproducible work.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.