Documentation
¶
Overview ¶
Package registry implements an OCI Distribution Specification v1.1 compliant registry.
The registry supports the full OCI Distribution Spec including:
- Pull workflow (required)
- Push workflow
- Content management
- Manifest and blob storage
- OCI-compliant error responses
- HTTP compression for data transfer (zstd, gzip, deflate)
Compression Support ¶
The registry supports bidirectional compression for both requests and responses.
## Response Compression (Downloads)
The registry automatically compresses blob and manifest responses when clients include an Accept-Encoding header. Supported compression algorithms:
- zstd (Zstandard) - preferred for best compression ratio
- gzip - widely supported, good compression
- deflate - basic compression support
The registry negotiates compression based on client preferences expressed via quality values in the Accept-Encoding header. When multiple encodings are acceptable, the registry prefers zstd > gzip > deflate.
Examples:
Accept-Encoding: gzip Accept-Encoding: zstd, gzip;q=0.9, deflate;q=0.8 Accept-Encoding: *
Compression is applied transparently to GET requests for:
- Manifests (/v2/<repo>/manifests/<reference>)
- Blobs (/v2/<repo>/blobs/<digest>)
When compression is used, the response includes:
- Content-Encoding header indicating the algorithm
- Vary: Accept-Encoding header for cache control
- Content-Length header is removed (chunked transfer encoding used)
## Request Decompression (Uploads)
The registry automatically decompresses incoming request bodies when clients send a Content-Encoding header. This is useful for reducing upload bandwidth.
Supported encodings for uploads:
- zstd, gzip, deflate
Example:
Content-Encoding: gzip
Request decompression is supported for:
- Manifest uploads (PUT /v2/<repo>/manifests/<reference>)
- Blob chunk uploads (PATCH /v2/<repo>/blobs/uploads/<uuid>)
- Blob upload completion (PUT /v2/<repo>/blobs/uploads/<uuid>)
Spec: https://github.com/opencontainers/distribution-spec/blob/main/spec.md
Index ¶
- Constants
- Variables
- func BasePath() string
- func BlobPath(repo, digest string) string
- func ListenAndServe(addr string, storage Storage) error
- func ManifestPath(repo, reference string) string
- func NewHandler(storage Storage) http.Handler
- func ParseRepositoryName(repo string) (domain, path string)
- func WriteError(w http.ResponseWriter, statusCode int, code, message string, detail any)
- type ContainerdCacheStorage
- func (s *ContainerdCacheStorage) AbortUpload(ctx context.Context, uuid string) error
- func (s *ContainerdCacheStorage) BlobExists(ctx context.Context, dg string) bool
- func (s *ContainerdCacheStorage) BlobSize(ctx context.Context, dg string) (int64, error)
- func (s *ContainerdCacheStorage) Close() error
- func (s *ContainerdCacheStorage) CompleteUpload(ctx context.Context, uuid, expectedDigest string) (dg string, err error)
- func (s *ContainerdCacheStorage) CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)
- func (s *ContainerdCacheStorage) DeleteBlob(ctx context.Context, dg string) error
- func (s *ContainerdCacheStorage) DeleteManifest(ctx context.Context, repo, reference string) error
- func (s *ContainerdCacheStorage) GetBlob(ctx context.Context, dg string) (io.ReadCloser, error)
- func (s *ContainerdCacheStorage) GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)
- func (s *ContainerdCacheStorage) GetUpload(_ context.Context, uuid string) (*UploadSession, error)
- func (s *ContainerdCacheStorage) ManifestExists(ctx context.Context, repo, reference string) bool
- func (s *ContainerdCacheStorage) NewUpload(_ context.Context) (*UploadSession, error)
- func (s *ContainerdCacheStorage) PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (_ string, err error)
- type ErrorDescriptor
- type ErrorResponse
- type FilesystemStorage
- func (s *FilesystemStorage) AbortUpload(ctx context.Context, uuid string) error
- func (s *FilesystemStorage) BlobExists(ctx context.Context, digest string) bool
- func (s *FilesystemStorage) BlobSize(ctx context.Context, digest string) (int64, error)
- func (s *FilesystemStorage) CompleteUpload(ctx context.Context, uuid, expectedDigest string) (string, error)
- func (s *FilesystemStorage) CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)
- func (s *FilesystemStorage) DeleteBlob(ctx context.Context, digest string) error
- func (s *FilesystemStorage) DeleteManifest(ctx context.Context, repo, reference string) error
- func (s *FilesystemStorage) GetBlob(ctx context.Context, digest string) (io.ReadCloser, error)
- func (s *FilesystemStorage) GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)
- func (s *FilesystemStorage) GetUpload(ctx context.Context, uuid string) (*UploadSession, error)
- func (s *FilesystemStorage) ManifestExists(ctx context.Context, repo, reference string) bool
- func (s *FilesystemStorage) NewUpload(ctx context.Context) (*UploadSession, error)
- func (s *FilesystemStorage) PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (string, error)
- type ManifestMetadata
- type PathType
- type Registry
- type RegistryPath
- type Storage
- type UploadSession
Constants ¶
const ( // ErrCodeBlobUnknown indicates blob is unknown to the registry ErrCodeBlobUnknown = "BLOB_UNKNOWN" // ErrCodeBlobUploadInvalid indicates blob upload is invalid ErrCodeBlobUploadInvalid = "BLOB_UPLOAD_INVALID" // ErrCodeBlobUploadUnknown indicates blob upload session is unknown ErrCodeBlobUploadUnknown = "BLOB_UPLOAD_UNKNOWN" // ErrCodeDigestInvalid indicates provided digest did not match uploaded content ErrCodeDigestInvalid = "DIGEST_INVALID" // ErrCodeManifestBlobUnknown indicates blob unknown to registry ErrCodeManifestBlobUnknown = "MANIFEST_BLOB_UNKNOWN" // ErrCodeManifestInvalid indicates manifest is invalid ErrCodeManifestInvalid = "MANIFEST_INVALID" // ErrCodeManifestUnknown indicates manifest is unknown ErrCodeManifestUnknown = "MANIFEST_UNKNOWN" // ErrCodeNameInvalid indicates invalid repository name ErrCodeNameInvalid = "NAME_INVALID" // ErrCodeNameUnknown indicates repository name not known ErrCodeNameUnknown = "NAME_UNKNOWN" // ErrCodeSizeInvalid indicates provided length did not match content length ErrCodeSizeInvalid = "SIZE_INVALID" ErrCodeUnauthorized = "UNAUTHORIZED" // ErrCodeDenied indicates requested access denied ErrCodeDenied = "DENIED" // ErrCodeUnsupported indicates operation is unsupported ErrCodeUnsupported = "UNSUPPORTED" // ErrCodeTooManyRequests indicates too many requests ErrCodeTooManyRequests = "TOOMANYREQUESTS" )
Error codes defined by OCI Distribution Specification
Variables ¶
var ( // ErrBlobNotFound indicates the blob was not found in storage ErrBlobNotFound = errors.New("blob not found") // ErrManifestNotFound indicates the manifest was not found ErrManifestNotFound = errors.New("manifest not found") // ErrDigestMismatch indicates the digest does not match the content ErrDigestMismatch = errors.New("digest mismatch") )
Functions ¶
func ListenAndServe ¶
ListenAndServe starts the registry HTTP server.
func ManifestPath ¶
ManifestPath returns the path for a manifest.
func NewHandler ¶
NewHandler creates a new HTTP handler for the registry.
func ParseRepositoryName ¶
ParseRepositoryName parses a repository name and returns the normalized domain and path. It handles Docker Hub conventions and various repository name formats.
Examples:
- "nginx" -> "docker.io", "library/nginx"
- "user/app" -> "docker.io", "user/app"
- "registry.example.com/user/app" -> "registry.example.com", "user/app"
- "registry.example.com/app" -> "registry.example.com", "app"
func WriteError ¶
func WriteError(w http.ResponseWriter, statusCode int, code, message string, detail any)
WriteError writes an OCI-compliant error response.
Types ¶
type ContainerdCacheStorage ¶
type ContainerdCacheStorage struct {
// contains filtered or unexported fields
}
ContainerdCacheStorage implements Storage using containerd's content and metadata stores. It works with Docker daemons configured with the containerd snapshotter. All blobs (layers, configs, manifests) are stored in containerd's content store, and images are registered in containerd's metadata store so they appear in `docker images` and `ctr images list`.
This storage backend requires a running containerd daemon and registers all pushed images in the "moby" namespace (Docker's default namespace).
func NewContainerdCacheStorage ¶
func NewContainerdCacheStorage(containerdSocket string) (*ContainerdCacheStorage, error)
NewContainerdCacheStorage creates a new Docker cache-based storage. containerdSocket is the path to containerd's socket (e.g., /run/containerd/containerd.sock).
This requires a running containerd daemon. Images pushed to the registry will be automatically registered in containerd's metadata and will appear in `docker images` and `ctr -n moby images list`.
func (*ContainerdCacheStorage) AbortUpload ¶
func (s *ContainerdCacheStorage) AbortUpload(ctx context.Context, uuid string) error
AbortUpload removes an upload session.
func (*ContainerdCacheStorage) BlobExists ¶
func (s *ContainerdCacheStorage) BlobExists(ctx context.Context, dg string) bool
BlobExists checks if a blob exists in Docker's cache.
func (*ContainerdCacheStorage) Close ¶
func (s *ContainerdCacheStorage) Close() error
Close closes the containerd client connection.
func (*ContainerdCacheStorage) CompleteUpload ¶
func (s *ContainerdCacheStorage) CompleteUpload(ctx context.Context, uuid, expectedDigest string) (dg string, err error)
CompleteUpload saves an upload session.
func (*ContainerdCacheStorage) CopyChunk ¶
func (s *ContainerdCacheStorage) CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)
CopyChunk copies a chunk to an upload session.
func (*ContainerdCacheStorage) DeleteBlob ¶
func (s *ContainerdCacheStorage) DeleteBlob(ctx context.Context, dg string) error
DeleteBlob removes a blob from Docker's image cache.
func (*ContainerdCacheStorage) DeleteManifest ¶
func (s *ContainerdCacheStorage) DeleteManifest(ctx context.Context, repo, reference string) error
DeleteManifest removes a manifest from containerd.
func (*ContainerdCacheStorage) GetBlob ¶
func (s *ContainerdCacheStorage) GetBlob(ctx context.Context, dg string) (io.ReadCloser, error)
GetBlob retrieves a blob by digest from Docker's image cache as a stream.
func (*ContainerdCacheStorage) GetManifest ¶
func (s *ContainerdCacheStorage) GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)
GetManifest retrieves a manifest from containerd's metadata store.
func (*ContainerdCacheStorage) GetUpload ¶
func (s *ContainerdCacheStorage) GetUpload(_ context.Context, uuid string) (*UploadSession, error)
GetUpload retrieves an upload session.
func (*ContainerdCacheStorage) ManifestExists ¶
func (s *ContainerdCacheStorage) ManifestExists(ctx context.Context, repo, reference string) bool
ManifestExists checks if a manifest exists in containerd's metadata.
func (*ContainerdCacheStorage) NewUpload ¶
func (s *ContainerdCacheStorage) NewUpload(_ context.Context) (*UploadSession, error)
NewUpload creates a new upload session.
func (*ContainerdCacheStorage) PutManifest ¶
func (s *ContainerdCacheStorage) PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (_ string, err error)
PutManifest stores a manifest in containerd's content store and registers the image.
type ErrorDescriptor ¶
type ErrorDescriptor struct {
Code string `json:"code"`
Message string `json:"message"`
Detail any `json:"detail,omitempty"`
}
ErrorDescriptor represents an OCI registry error.
func NewError ¶
func NewError(code, message string) ErrorDescriptor
NewError creates a new error descriptor.
func (ErrorDescriptor) Error ¶
func (e ErrorDescriptor) Error() string
Error implements the error interface.
type ErrorResponse ¶
type ErrorResponse struct {
Errors []ErrorDescriptor `json:"errors"`
}
ErrorResponse represents the OCI-compliant error response format.
type FilesystemStorage ¶
type FilesystemStorage struct {
// contains filtered or unexported fields
}
FilesystemStorage implements Storage using the filesystem.
func NewFilesystemStorage ¶
func NewFilesystemStorage(rootDir string) (*FilesystemStorage, error)
NewFilesystemStorage creates a new filesystem-based storage.
func (*FilesystemStorage) AbortUpload ¶
func (s *FilesystemStorage) AbortUpload(ctx context.Context, uuid string) error
AbortUpload removes an upload session.
func (*FilesystemStorage) BlobExists ¶
func (s *FilesystemStorage) BlobExists(ctx context.Context, digest string) bool
BlobExists checks if a blob exists.
func (*FilesystemStorage) CompleteUpload ¶
func (*FilesystemStorage) CopyChunk ¶
func (s *FilesystemStorage) CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)
func (*FilesystemStorage) DeleteBlob ¶
func (s *FilesystemStorage) DeleteBlob(ctx context.Context, digest string) error
DeleteBlob removes a blob.
func (*FilesystemStorage) DeleteManifest ¶
func (s *FilesystemStorage) DeleteManifest(ctx context.Context, repo, reference string) error
DeleteManifest removes a manifest.
func (*FilesystemStorage) GetBlob ¶
func (s *FilesystemStorage) GetBlob(ctx context.Context, digest string) (io.ReadCloser, error)
GetBlob retrieves a blob by digest as a stream.
func (*FilesystemStorage) GetManifest ¶
func (s *FilesystemStorage) GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)
GetManifest retrieves a manifest for a repository and reference.
func (*FilesystemStorage) GetUpload ¶
func (s *FilesystemStorage) GetUpload(ctx context.Context, uuid string) (*UploadSession, error)
GetUpload retrieves an upload session.
func (*FilesystemStorage) ManifestExists ¶
func (s *FilesystemStorage) ManifestExists(ctx context.Context, repo, reference string) bool
ManifestExists checks if a manifest exists.
func (*FilesystemStorage) NewUpload ¶
func (s *FilesystemStorage) NewUpload(ctx context.Context) (*UploadSession, error)
func (*FilesystemStorage) PutManifest ¶
func (s *FilesystemStorage) PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (string, error)
PutManifest stores a manifest for a repository and reference.
type ManifestMetadata ¶
type ManifestMetadata struct {
MediaType string
Digest string
Size int64
Data io.ReadCloser
}
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry implements an OCI Distribution Specification v1.1 compliant registry.
type RegistryPath ¶
type RegistryPath struct {
Type PathType
Repo string
Reference string // For manifests: tag or digest; for blobs: digest; for uploads: uuid
}
RegistryPath holds the parsed components of a registry path
func ParseRegistryPath ¶
func ParseRegistryPath(path string) (*RegistryPath, error)
ParseRegistryPath parses a Docker Registry V2 API path
type Storage ¶
type Storage interface {
// GetBlob retrieves a blob by digest as a stream
GetBlob(ctx context.Context, digest string) (io.ReadCloser, error)
// BlobSize returns the size of a blob by digest.
BlobSize(ctx context.Context, digest string) (int64, error)
// BlobExists checks if a blob exists
BlobExists(ctx context.Context, digest string) bool
// DeleteBlob removes a blob
DeleteBlob(ctx context.Context, digest string) error
// GetManifest retrieves a manifest for a repository and reference as a stream
GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)
// PutManifest stores a manifest for a repository and reference
PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (digest string, err error)
// ManifestExists checks if a manifest exists
ManifestExists(ctx context.Context, repo, reference string) bool
// DeleteManifest removes a manifest
DeleteManifest(ctx context.Context, repo, reference string) error
// NewUpload creates a new upload session
NewUpload(ctx context.Context) (*UploadSession, error)
// GetUpload retrieves an upload session
GetUpload(ctx context.Context, uuid string) (*UploadSession, error)
// CopyChunk copies a chunk to an upload session
CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)
// CompleteUpload saves an upload session
CompleteUpload(ctx context.Context, uuid, expectedDigest string) (string, error)
// AbortUpload removes an upload session
AbortUpload(ctx context.Context, uuid string) error
}
Storage provides content-addressable storage for registry blobs and manifests.
type UploadSession ¶
UploadSession represents an ongoing blob upload.