g1t/apps/docs/src/content/docs/guides/containers.md

151 lines6,006 bytesCodeBlame
1---
2title: Container images
3description: Push and pull container images on g1t.sh with docker, in workflows with G1T_TOKEN, and what to do about large layers.
4---
5
6g1t.sh is a container registry. Images are named after their workspace,
7pushed and pulled with `docker` or any client of the OCI Distribution
8protocol, and have the access of the repository they are linked to (see
9[who can see and publish a package](/guides/packages/#who-can-see-and-publish-a-package)).
10
11```text
12g1t.sh/<workspace>/<name>[:<tag>]
13```
14
15## Sign in
16
17Use your username, and an [access token](https://g1t.sh/settings/tokens) as
18the password: one with full access, or with `packages:write` (to push) or
19`packages:read` (to pull private images).
20
21```sh
22echo "$G1T_TOKEN" | docker login g1t.sh -u <you> --password-stdin
23```
24
25Public images pull without signing in.
26
27## Push
28
29Tag the image with its address and push it:
30
31```sh
32docker build -t g1t.sh/acme/web:1.4.0 .
33docker push g1t.sh/acme/web:1.4.0
34```
35
36The first push makes the package. When its name starts with a repository
37of the workspace, here `acme/web`, it is linked to that repository and
38follows its visibility and roles; pushing needs Write on it. Otherwise it is
39the workspace's, private, and needs the workspace's Write base permission.
40
41Pushing a tag again moves it to the new image. Layers already on g1t are
42not uploaded again, and images in the same workspace share them.
43
44Multi-platform images (`docker buildx build --platform linux/amd64,linux/arm64 --push`),
45OCI image indexes, and artifacts attached to an image with a `subject`
46(signatures, SBOMs, attestations) are all kept; the registry lists an image's
47attached artifacts at `/v2/<name>/referrers/<digest>`.
48
49## Pull
50
51```sh
52docker pull g1t.sh/acme/web:1.4.0
53docker pull g1t.sh/acme/web@sha256:…
54```
55
56## In workflows
57
58A workflow's `G1T_TOKEN` is the workspace's own token for the run, and can
59push and pull the workspace's images:
60
61```yaml
62jobs:
63 image:
64 runs-on: ubuntu-latest
65 steps:
66 - uses: actions/checkout@v4
67 - name: Sign in to g1t.sh
68 run: echo "${{ secrets.G1T_TOKEN }}" | docker login g1t.sh -u g1t --password-stdin
69 - name: Build and push
70 run: |
71 docker build -t g1t.sh/${{ github.repository }}:${{ github.sha }} .
72 docker push g1t.sh/${{ github.repository }}:${{ github.sha }}
73```
74
75Runs that get no secrets (a pull request from someone without Write) get an
76empty token, and cannot push. See
77[secrets and variables](/guides/actions/#secrets-and-variables).
78
79## The 100 MB limit
80
81A single request to g1t.sh may carry at most 100 MB. `docker push` sends
82each layer whole, in one request, and so do the other common clients
83(`crane push` and `oras push` included), so a layer over 100 MB, as
84compressed for the push, is refused.
85
86What you see depends on where it is refused. Usually it is before the
87request reaches g1t, and `docker push` stops with a bare status:
88
89```text
90unknown: failed commit on ref "layer-sha256:…": unexpected status from PUT request to https://g1t.sh/v2/acme/web/blobs/uploads/…?digest=sha256%3A…: 413 Request Entity Too Large
91```
92
93(the request may be a `PATCH` instead of a `PUT`, and some versions of
94Docker show the HTML page that came with the 413 instead). When g1t sees
95the request itself, the error is `SIZE_INVALID`, with a message naming the
96limit and this page.
97
98A client that uploads a layer in chunks, each its own request under
99100 MB, is not limited: the layer can then be any size.
100
101To stay under the limit, keep each layer under 100 MB:
102
103- build in stages, and copy only what the image needs into the last one;
104- split a large `RUN` or `COPY` into several, so each makes its own layer;
105- leave caches, build tools and test data out of the image (`.dockerignore`).
106
107An installation you [run yourself](/guides/self-hosting/) has no such
108limit.
109
110## Storage and pull limits
111
112Without the [g1t plan](/guides/usage-and-billing/#the-g1t-plan), a
113workspace's public packages may hold 10 GB and its private ones 500 MB,
114each file counted once. A push that would go past either is refused with
115`DENIED` and a message saying how much is used; layers the workspace
116already holds add nothing. On the plan nothing is refused: storage past
117the free amounts is charged.
118
119Anonymous pulls are limited to 300 requests a minute from each address, and
120signed-in ones to 5,000 a minute for each person, workspace or agent.
121Past the limit, requests are answered `429` with `TOOMANYREQUESTS` and a
122`Retry-After`; docker waits and tries again. Signing in raises the limit.
123
124## Delete
125
126Deleting needs Admin on the linked repository, or for an unlinked image, an
127owner of the workspace; a token needs `packages:delete`.
128
129The registry protocol's `DELETE` removes a tag, or a whole version by its
130digest (with every tag that points to it):
131
132```sh
133TOKEN=$(curl -s -u <you>:<token> "https://g1t.sh/v2/token?scope=repository:acme/web:delete" | jq -r .token)
134curl -X DELETE -H "Authorization: Bearer $TOKEN" https://g1t.sh/v2/acme/web/manifests/1.4.0
135curl -X DELETE -H "Authorization: Bearer $TOKEN" https://g1t.sh/v2/acme/web/manifests/sha256:…
136```
137
138Layers no version uses any more are deleted from storage a day later.
139
140## Errors
141
142| Error | Means |
143| --- | --- |
144| `UNAUTHORIZED` | Not signed in, or the token is wrong or expired. `docker login g1t.sh` again. |
145| `DENIED` | Signed in, but your role or your token's scopes do not allow it. The message says which. |
146| `NAME_UNKNOWN` | No such image, or one you cannot see. |
147| `MANIFEST_UNKNOWN`, `BLOB_UNKNOWN` | No such tag, digest or layer in that image. |
148| `NAME_INVALID` | Names are lowercase letters and digits, separated by `.`, `_`, `__`, `-` or `/`, and start with a workspace. |
149| `SIZE_INVALID`, or a bare `413` | A request over [the 100 MB limit](#the-100-mb-limit). |
150| `TOOMANYREQUESTS` | Too many requests in a minute; see [the limits](#storage-and-pull-limits). |
151| `DIGEST_INVALID` | What was uploaded does not have the digest the client said. Push again. |