Technical Documentation: docker/DISTRIBUTION
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
The toolset to pack, ship, store, and deliver content.
This repository's main product is the Open Source Registry implementation
for storing and distributing container images and other content using the
OCI Distribution Specification.
The goal of this project is to provide a simple, secure, and scalable base
for building a large scale registry solution or running a simple private registry.
It is a core library for many registry operators including Docker Hub, GitHub Container Registry,
GitLab Container Registry and DigitalOcean Container Registry, as well as the CNCF Harbor
Project, and VMware Harbor Registry.
This repository contains the following components:
| Component | Description |
|---|---|
| registry | An implementation of the OCI Distribution Specification. |
| libraries | A rich set of libraries for interacting with distribution components. Please see godoc for details. Note: The interfaces for these libraries are unstable. |
| documentation | Full documentation is available at https://distribution.github.io/distribution. |
How does this integrate with Docker, containerd, and other OCI client?
Clients implement against the OCI specification and communicate with the
registry using HTTP. This project contains a client implementation which
is currently in use by Docker, however, it is deprecated for the
implementation in containerd
and will not support new features.
What are the long term goals of the Distribution project?
The Distribution project has the further long term goal of providing a
secure tool chain for distributing content. The specifications, APIs and tools
should be as useful with Docker as they are without.
Our goal is to design a professional grade and extensible content distribution
system that allow users to:
- Enjoy an efficient, secured and reliable way to store, manage, package and
exchange content - Hack/roll their own on top of healthy open-source components
- Implement their own home made solution through good specs, and solid
extensions mechanism.
Contribution
Please see CONTRIBUTING.md for details on how to contribute
issues, fixes, and patches to this project. If you are contributing code, see
the instructions for building a development environment.
Communication
For async communication and long running discussions please use issues and pull requests on the github repo.
This will be the best place to discuss design and implementation.
For sync communication we have a #distribution channel in the CNCF Slack
that everyone is welcome to join and chat about development.
Licenses
The distribution codebase is released under the Apache 2.0 license.
The README.md file, and files in the "docs" folder are licensed under the
Creative Commons Attribution 4.0 International License. You may obtain a
copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.
Overview (`releases/README.md`)
Registry Release Checklist
- Compile release notes detailing features added since the last release.
Add release template file to releases/ directory. The template is defined
by containerd's release tool. Name the file using the version, for rc add
an -rc suffix.
See https://github.com/containerd/release-tool
Update the
.mailmapfiles.Update the version file:
https://github.com/distribution/distribution/blob/master/version/version.goCreate a signed tag.
Choose a tag for the next release, distribution uses semantic versioning
and expects tags to be formatted as vx.y.z[-rc.n]. Run the release tool using
the release template file and tag to generate the release notes for the tag
and Github release. To create the tag, you will need PGP installed and a PGP
key which has been added to your Github account. The comment for the tag will
be the generated release notes, always compare with previous tags to ensure
the output is expected and consistent.
Run git tag --cleanup=whitespace -s vx.y.z[-rc.n] -F release-notes to create
tag and git -v vx.y.z[-rc.n] to verify tag, check comment and correct commit
hash.
Push the signed tag
Create a new release.
In the case of a release candidate, tick thepre-releasecheckbox. Use
the generate release notes from the release toolUpdate the registry binary in the distribution library image repo by running the update script and opening a pull request.
Update the official image. Add the new version in the official images repo by appending a new version to the
registry/registryfile with the git hash pointed to by the signed tag. Update the major version to point to the latest version and the minor version to point to new patch release if necessary.
e.g. to release2.3.1
2.3.1 (new)
2.3.0 -> 2.3.0 can be removed
2 -> 2.3.1
2.3 -> 2.3.1
- Build a new distribution/registry image on Docker Hub by adding a new automated build with the new tag and re-building the images.
Overview (`project/hooks/README.md`)
Git Hooks
To enforce valid and properly-formatted code, there is CI in place which runs gofmt, golint, and go vet against code in the repository.
As an aid to prevent committing invalid code in the first place, a git pre-commit hook has been added to the repository, found in pre-commit. As it is impossible to automatically add linked hooks to a git repository, this hook should be linked into your .git/hooks/pre-commit, which can be done by running the configure-hooks.sh script in this directory. This script is the preferred method of configuring hooks, as it will be updated as more are added.
Overview (`docs/themes/hugo-geekdoc/README.md`)
Geekdoc
Geekdoc is a simple Hugo theme for documentations. It is intentionally designed as a fast and lean theme and may not fit the requirements of complex projects. If a more feature-complete theme is required there are a lot of good alternatives out there. You can find a demo and the full documentation at https://geekdocs.de.
Build and release process
This theme is subject to a CI driven build and release process common for software development. During the release build, all necessary assets are automatically built by webpack and bundled in a release tarball. You can download the latest release from the GitHub release page.
Due to the fact that webpack and npm scripts are used as pre-processors, the theme cannot be used from the main branch by default. If you want to use the theme from a cloned branch instead of a release tarball you'll need to install webpack locally and run the build script once to create all required assets.
# install required packages from package.json
npm install
# run the build script to build required assets
npm run build
# build release tarball
npm run packSee the Getting Started Guide for details about the different setup options.
Contributors
Special thanks to all contributors. If you would like to contribute, please see the instructions.
Geekdoc is inspired and partially based on the hugo-book theme, thanks Alex Shpak for your work.
License
This project is licensed under the MIT License - see the LICENSE file for details.
The used SVG icons and generated icon fonts are licensed under the license of the respective icon pack:
- Font Awesome: CC BY 4.0 License
- IcoMoon Free Pack: GPL/CC BY 4.0
- Material Icons: Apache License 2.0
Overview (`vendor/cel.dev/expr/README.md`)
Common Expression Language
The Common Expression Language (CEL) implements common semantics for expression
evaluation, enabling different applications to more easily interoperate.
Key Applications
- Security policy: organizations have complex infrastructure and need common
tooling to reason about the system as a whole - Protocols: expressions are a useful data type and require interoperability
across programming languages and platforms.
Guiding philosophy:
- Keep it small & fast.
- CEL evaluates in linear time, is mutation free, and not Turing-complete.
This limitation is a feature of the language design, which allows the
implementation to evaluate orders of magnitude faster than equivalently
sandboxed JavaScript.
- CEL evaluates in linear time, is mutation free, and not Turing-complete.
- Make it extensible.
- CEL is designed to be embedded in applications, and allows for
extensibility via its context which allows for functions and data to be
provided by the software that embeds it.
- CEL is designed to be embedded in applications, and allows for
- Developer-friendly.
- The language is approachable to developers. The initial spec was based
on the experience of developing Firebase Rules and usability testing
many prior iterations. - The library itself and accompanying toolings should be easy to adopt by
teams that seek to integrate CEL into their platforms.
- The language is approachable to developers. The initial spec was based
The required components of a system that supports CEL are:
- The textual representation of an expression as written by a developer. It is
of similar syntax to expressions in C/C++/Java/JavaScript - A representation of the program's abstract syntax tree (AST).
- A compiler library that converts the textual representation to the binary
representation. This can be done ahead of time (in the control plane) or
just before evaluation (in the data plane). - A context containing one or more typed variables, often protobuf messages.
Most use-cases will useattribute_context.proto - An evaluator library that takes the binary format in the context and
produces a result, usually a Boolean.
For use cases which require persistence or cross-process communcation, it is
highly recommended to serialize the type-checked expression as a protocol
buffer. The CEL team will maintains canonical protocol buffers for ASTs and
will keep these versions identical and wire-compatible in perpetuity:
Example of boolean conditions and object construction:
// Condition
account.balance >= transaction.withdrawal
|| (account.overdraftProtection
&& account.overdraftLimit >= transaction.withdrawal - account.balance)
// Object construction
common.GeoPoint{ latitude: 10.0, longitude: -5.5 }For more detail, see:
Released under the Apache License.
Overview (`vendor/go.opentelemetry.io/otel/README.md`)
OpenTelemetry-Go
OpenTelemetry-Go is the Go implementation of OpenTelemetry.
It provides a set of APIs to directly measure performance and behavior of your software and send this data to observability platforms.
Project Status
| Signal | Status |
|---|---|
| Traces | Stable |
| Metrics | Stable |
| Logs | Beta^1 |
Progress and status specific to this repository is tracked in our
project boards
and
milestones.
Project versioning information and stability guarantees can be found in the
versioning documentation.
Compatibility
OpenTelemetry-Go ensures compatibility with the current supported versions of
the Go language:
Each major Go release is supported until there are two newer major releases.
For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release.
For versions of Go that are no longer supported upstream, opentelemetry-go will
stop ensuring compatibility with these versions in the following manner:
- A minor release of opentelemetry-go will be made to add support for the new
supported release of Go. - The following minor release of opentelemetry-go will remove compatibility
testing for the oldest (now archived upstream) version of Go. This, and
future, releases of opentelemetry-go may include features only supported by
the currently supported versions of Go.
Currently, this project supports the following environments.
| OS | Go Version | Architecture |
|---|---|---|
| Ubuntu | 1.26 | amd64 |
| Ubuntu | 1.25 | amd64 |
| Ubuntu | 1.26 | 386 |
| Ubuntu | 1.25 | 386 |
| Ubuntu | 1.26 | arm64 |
| Ubuntu | 1.25 | arm64 |
| macOS | 1.26 | amd64 |
| macOS | 1.25 | amd64 |
| macOS | 1.26 | arm64 |
| macOS | 1.25 | arm64 |
| Windows | 1.26 | amd64 |
| Windows | 1.25 | amd64 |
| Windows | 1.26 | 386 |
| Windows | 1.25 | 386 |
While this project should work for other systems, no compatibility guarantees
are made for those systems currently.
Getting Started
You can find a getting started guide on opentelemetry.io.
OpenTelemetry's goal is to provide a single set of APIs to capture distributed
traces and metrics from your application and send them to an observability
platform. This project allows you to do just that for applications written in
Go. There are two steps to this process: instrument your application, and
configure an exporter.
Instrumentation
To start capturing distributed traces and metric events from your application
it first needs to be instrumented. The easiest way to do this is by using an
instrumentation library for your code. Be sure to check out the officially
supported instrumentation
libraries.
If you need to extend the telemetry an instrumentation library provides or want
to build your own instrumentation for your application directly you will need
to use the
Go otel
package. The examples
are a good way to see some practical uses of this process.
Export
Now that your application is instrumented to collect telemetry, it needs an
export pipeline to send that telemetry to an observability platform.
All officially supported exporters for the OpenTelemetry project are contained in the exporters directory.
| Exporter | Logs | Metrics | Traces |
|---|---|---|---|
| OTLP | ✓ | ✓ | ✓ |
| Prometheus | ✓ | ||
| stdout | ✓ | ✓ | ✓ |
| Zipkin | ✓ |
Contributing
See the contributing documentation.
Emeritus
- Alex Kats, Triager
For more information about the emeritus role, see the
community repository.
Overview (`vendor/google.golang.org/grpc/README.md`)
gRPC-Go
The Go implementation of gRPC: A high performance, open source, general
RPC framework that puts mobile and HTTP/2 first. For more information see the
Go gRPC docs, or jump directly into the quick start.
Prerequisites
Installation
Simply add the following import to your code, and then go [build|run|test]
will automatically fetch the necessary dependencies:
import "google.golang.org/grpc"Note: If you are trying to access
grpc-gofrom China, see the
FAQ below.
Learn more
- Go gRPC docs, which include a quick start and API
reference among other resources - Low-level technical docs from this repository
- Performance benchmark
- Examples
- Contribution guidelines
FAQ
I/O Timeout Errors
The golang.org domain may be blocked from some countries. go get usually
produces an error like the following when this happens:
$ go get -u google.golang.org/grpc
package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc" (https fetch: Get https://google.golang.org/grpc?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)To build Go code, there are several options:
Set up a VPN and access google.golang.org through that.
With Go module support: it is possible to use the
replacefeature ofgo modto create aliases for golang.org packages. In your project's directory:shgo mod edit -replace=google.golang.org/grpc=github.com/grpc/grpc-go@latest go mod tidy go mod vendor go build -mod=vendorAgain, this will need to be done for all transitive dependencies hosted on
golang.org as well. For details, refer to golang/go issue
#28652.
Compiling error, undefined: grpc.SupportPackageIsVersion
Please update to the latest version of gRPC-Go usinggo get google.golang.org/grpc.
How to turn on logging
The default logger is controlled by environment variables. Turn everything on
like this:
$ export GRPC_GO_LOG_VERBOSITY_LEVEL=99
$ export GRPC_GO_LOG_SEVERITY_LEVEL=infoThe RPC failed with error `"code = Unavailable desc = transport is closing"`
This error means the connection the RPC is using was closed, and there are many
possible reasons, including:
- mis-configured transport credentials, connection failed on handshaking
- bytes disrupted, possibly by a proxy in between
- server shutdown
- Keepalive parameters caused connection shutdown, for example if you have
configured your server to terminate connections regularly to trigger DNS
lookups.
If this is the case, you may want to increase your
MaxConnectionAgeGrace,
to allow longer RPC calls to finish.
It can be tricky to debug this because the error happens on the client side but
the root cause of the connection being closed is on the server side. Turn on
logging on both client and server, and see if there are any transport
errors.
Overview (`vendor/cloud.google.com/go/auth/README.md`)
Google Auth Library for Go
Install
go get cloud.google.com/go/auth@latestUsage
The most common way this library is used is transitively, by default, from any
of our Go client libraries.
Notable use-cases
- To create a credential directly please see examples in the
credentials
package. - To create a authenticated HTTP client please see examples in the
httptransport
package. - To create a authenticated gRPC connection please see examples in the
grpctransport
package. - To create an ID token please see examples in the
idtoken
package.
Contributing
Contributions are welcome. Please, see the
CONTRIBUTING
document for details.
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.
See Contributor Code of Conduct
for more information.
Overview (`vendor/cloud.google.com/go/iam/README.md`)
IAM API
Go Client Library for IAM API.
Install
go get cloud.google.com/go/iamStability
The stability of this module is indicated by SemVer.
However, a v1+ module may have breaking changes in two scenarios:
- Packages with
alphaorbetain the import path - The GoDoc has an explicit stability disclaimer (for example, for an experimental feature).
Go Version Support
See the Go Versions Supported
section in the root directory's README.
Authorization
See the Authorization
section in the root directory's README.
Contributing
Contributions are welcome. Please, see the CONTRIBUTING
document for details.
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms. See
Contributor Code of Conduct
for more information.
Overview (`vendor/cloud.google.com/go/internal/README.md`)
Internal
This directory contains internal code for cloud.google.com/go packages.
.repo-metadata-full.json
.repo-metadata-full.json contains metadata about the packages in this repo. It
is generated by internal/gapicgen/generator. It's processed by external tools
to build lists of all of the packages.
Don't make breaking changes to the format without consulting with the external
tools.
One day, we may want to create individual .repo-metadata.json files next to
each package, which is the pattern followed by some other languages. External
tools would then talk to pkg.go.dev or some other service to get the overall
list of packages and use the .repo-metadata.json files to get the additional
metadata required. For now, .repo-metadata-full.json includes everything.
Updating OwlBot SHA
You may want to manually update the which version of the post-processor will be
used -- to do this you need to update the SHA in the OwlBot lock file.
See the postprocessor/README for detailed
instructions.
Note: OwlBot will eventually open a pull request to update this value if it
discovers a new version of the container.
Overview (`vendor/cloud.google.com/go/storage/README.md`)
Cloud Storage [](https://pkg.go.dev/cloud.google.com/go/storage)
Example Usage
First create a storage.Client to use throughout your application:
client, err := storage.NewClient(ctx)
if err != nil {
log.Fatal(err)
}// Read the object1 from bucket.
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
if err != nil {
log.Fatal(err)
}
defer rc.Close()
body, err := io.ReadAll(rc)
if err != nil {
log.Fatal(err)
}Overview (`vendor/github.com/AdaLogics/go-fuzz-headers/README.md`)
go-fuzz-headers
This repository contains various helper functions for go fuzzing. It is mostly used in combination with go-fuzz, but compatibility with fuzzing in the standard library will also be supported. Any coverage guided fuzzing engine that provides an array or slice of bytes can be used with go-fuzz-headers.
Usage
Using go-fuzz-headers is easy. First create a new consumer with the bytes provided by the fuzzing engine:
import (
fuzz "github.com/AdaLogics/go-fuzz-headers"
)
data := []byte{'R', 'a', 'n', 'd', 'o', 'm'}
f := fuzz.NewConsumer(data)This creates a Consumer that consumes the bytes of the input as it uses them to fuzz different types.
After that, f can be used to easily create fuzzed instances of different types. Below are some examples:
Structs
One of the most useful features of go-fuzz-headers is its ability to fill structs with the data provided by the fuzzing engine. This is done with a single line:
type Person struct {
Name string
Age int
}
p := Person{}
// Fill p with values based on the data provided by the fuzzing engine:
err := f.GenerateStruct(&p)This includes nested structs too. In this example, the fuzz Consumer will also insert values in p.BestFriend:
type PersonI struct {
Name string
Age int
BestFriend PersonII
}
type PersonII struct {
Name string
Age int
}
p := PersonI{}
err := f.GenerateStruct(&p)If the consumer should insert values for unexported fields as well as exported, this can be enabled with:
f.AllowUnexportedFields()...and disabled with:
f.DisallowUnexportedFields()Other types:
Other useful APIs:
createdString, err := f.GetString() // Gets a string
createdInt, err := f.GetInt() // Gets an integer
createdByte, err := f.GetByte() // Gets a byte
createdBytes, err := f.GetBytes() // Gets a byte slice
createdBool, err := f.GetBool() // Gets a boolean
err := f.FuzzMap(target_map) // Fills a map
createdTarBytes, err := f.TarBytes() // Gets bytes of a valid tar archive
err := f.CreateFiles(inThisDir) // Fills inThisDir with files
createdString, err := f.GetStringFrom("anyCharInThisString", ofThisLength) // Gets a string that consists of chars from "anyCharInThisString" and has the exact length "ofThisLength"Most APIs are added as they are needed.
Projects that use go-fuzz-headers
Feel free to add your own project to the list, if you use go-fuzz-headers to fuzz it.
Status
The project is under development and will be updated regularly.
References
go-fuzz-headers' approach to fuzzing structs is strongly inspired by gofuzz.
Overview (`vendor/github.com/cyphar/filepath-securejoin/README.md`)
`filepath-securejoin`
An implementation of SecureJoin, a candidate for inclusion in the Go
standard library. The purpose of this function is to be a "secure"
alternative to filepath.Join, and in particular it provides certain
guarantees that are not provided by filepath.Join.
NOTE: This code is only safe if you are not at risk of other processes
modifying path components after you've usedSecureJoin. If it is possible
for a malicious process to modify path components of the resolved path, then
you will be vulnerable to some fairly trivial TOCTOU race conditions. There
are some Linux kernel patches I'm working on which might allow for a better
solution.In addition, with a slightly modified API it might be possible to use
O_PATHand verify that the opened path is actually the resolved one -- but
I have not done that yet. I might add it in the future as a helper function
to help users verify the path (we can't just return/proc/self/fd/<foo>
because that doesn't always work transparently for all users).
This is the function prototype:
func SecureJoin(root, unsafePath string) (string, error)This library guarantees the following:
If no error is set, the resulting string must be a child path of
rootand will not contain any symlink path components (they will all be
expanded).When expanding symlinks, all symlink path components must be resolved
relative to the provided root. In particular, this can be considered a
userspace implementation of howchroot(2)operates on file paths. Note that
these symlinks will not be expanded lexically (filepath.Cleanis not
called on the input before processing).Non-existent path components are unaffected by
SecureJoin(similar tofilepath.EvalSymlinks's semantics).The returned path will always be
filepath.Cleaned and thus not contain any..components.
A (trivial) implementation of this function on GNU/Linux systems could be done
with the following (note that this requires root privileges and is far more
opaque than the implementation in this library, and also requires thatreadlink is inside the root path):
package securejoin
import (
"os/exec"
"path/filepath"
)
func SecureJoin(root, unsafePath string) (string, error) {
unsafePath = string(filepath.Separator) + unsafePath
cmd := exec.Command("chroot", root,
"readlink", "--canonicalize-missing", "--no-newline", unsafePath)
output, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
expanded := string(output)
return filepath.Join(root, expanded), nil
}License
The license of this project is the same as Go, which is a BSD 3-clause license
available in the LICENSE file.
Overview (`vendor/github.com/distribution/reference/README.md`)
Distribution reference
Go library to handle references to container images.
This repository contains a library for handling references to container images held in container registries. Please see godoc for details.
Contribution
Please see CONTRIBUTING.md for details on how to contribute
issues, fixes, and patches to this project.
Communication
For async communication and long running discussions please use issues and pull requests on the github repo.
This will be the best place to discuss design and implementation.
For sync communication we have a #distribution channel in the CNCF Slack
that everyone is welcome to join and chat about development.
Licenses
The distribution codebase is released under the Apache 2.0 license.
Overview (`vendor/github.com/docker/go-events/README.md`)
Docker Events Package
The Docker events package implements a composable event distribution package
for Go.
Originally created to implement the notifications in Docker Registry
2,
we've found the pattern to be useful in other applications. This package is
most of the same code with slightly updated interfaces. Much of the internals
have been made available.
Usage
The events package centers around a Sink type. Events are written with
calls to Sink.Write(event Event). Sinks can be wired up in various
configurations to achieve interesting behavior.
The canonical example is that employed by the
docker/distribution/notifications
package. Let's say we have a type httpSink where we'd like to queue
notifications. As a rule, it should send a single http request and return an
error if it fails:
func (h *httpSink) Write(event Event) error {
p, err := json.Marshal(event)
if err != nil {
return err
}
body := bytes.NewReader(p)
resp, err := h.client.Post(h.url, "application/json", body)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.Status != 200 {
return errors.New("unexpected status")
}
return nil
}
// implement (*httpSink).Close()With just that, we can start using components from this package. One can call(*httpSink).Write to send events as the body of a post request to a
configured URL.
Retries
HTTP can be unreliable. The first feature we'd like is to have some retry:
hs := newHTTPSink(/*...*/)
retry := NewRetryingSink(hs, NewBreaker(5, time.Second))We now have a sink that will retry events against the httpSink until they
succeed. The retry will backoff for one second after 5 consecutive failures
using the breaker strategy.
Queues
This isn't quite enough. We we want a sink that doesn't block while we are
waiting for events to be sent. Let's add a Queue:
queue := NewQueue(retry)Now, we have an unbounded queue that will work through all events sent with(*Queue).Write. Events can be added asynchronously to the queue without
blocking the current execution path. This is ideal for use in an http request.
Broadcast
It usually turns out that you want to send to more than one listener. We can
use Broadcaster to support this:
var broadcast = NewBroadcaster() // make it available somewhere in your application.
broadcast.Add(queue) // add your queue!
broadcast.Add(queue2) // and another!With the above, we can now call broadcast.Write in our http handlers and have
all the events distributed to each queue. Because the events are queued, not
listener blocks another.
Extending
For the most part, the above is sufficient for a lot of applications. However,
extending the above functionality can be done implementing your own Sink. The
behavior and semantics of the sink can be completely dependent on the
application requirements. The interface is provided below for reference:
type Sink {
Write(Event) error
Close() error
}Application behavior can be controlled by how Write behaves. The examples
above are designed to queue the message and return as quickly as possible.
Other implementations may block until the event is committed to durable
storage.
Copyright and license
Copyright © 2016 Docker, Inc. go-events is licensed under the Apache License,
Version 2.0. See LICENSE for the full license text.
Overview (`vendor/github.com/docker/go-metrics/README.md`)
go-metrics
This package is small wrapper around the prometheus go client to help enforce convention and best practices for metrics collection in Docker projects.
Best Practices
This packages is meant to be used for collecting metrics. It is not meant to be
used as a replacement for the prometheus client but to help enforce consistent
naming across metrics collected. If you have not already read the prometheus
best practices around naming and labels you can read the naming section in the
prometheus documentation.
The following are a few conventions that help naming metrics in your project.
Namespace and Subsystem
This package provides you with a namespace type that allows you to specify the
same namespace and subsystem for your metrics.
ns := metrics.NewNamespace("engine", "daemon", metrics.Labels{
"version": daemon.Version,
"commit": daemon.GitCommit,
})In the example above we are creating metrics for the daemon package.engine would be the namespace in this example where daemon is the subsystem
or package where we are collecting the metrics.
A namespace also allows you to attach constant labels to the metrics such as
the git commit and version that it is collecting.
Declaring your Metrics
Try to keep all your metric declarations in one file. This makes it easy for
others to see what constant labels are defined on the namespace and what
labels are defined on the metrics when they are created.
Use labels instead of multiple metrics
Labels allow you to define one metric such as the time it takes to perform a
certain action on an object. If we wanted to collect timings on various container
actions such as create, start, and delete then we can define one metric calledcontainer_actions and use labels to specify the type of action.
containerActions = ns.NewLabeledTimer("container_actions", "The number of milliseconds it takes to process each container action", "action")The last parameter is the label name or key. When adding a data point to the
metric you can use the WithValues function to specify the action that you
are collecting for.
containerActions.WithValues("create").UpdateSince(start)Always use a unit
The metric name should describe what you are measuring but you also need to
provide the unit that it is being measured with. For a timer, the standard
unit is seconds and a counter's standard unit is a total. For gauges you must
provide the unit. This package provides a standard set of units for use within
your projects.
Nanoseconds Unit = "nanoseconds"
Seconds Unit = "seconds"
Bytes Unit = "bytes"
Total Unit = "total"If you need to use a unit but it is not defined in the package please open
a PR to add it but first try to see if one of the existing units work for
your metric, i.e., seconds or nanoseconds vs adding milliseconds.
HTTP Metrics
To instrument a http handler, you can wrap the code like this:
namespace := metrics.NewNamespace("api_server", "http", metrics.Labels{"handler": "your_http_handler_name"})
httpMetrics := namespace.NewDefaultHttpMetrics()
metrics.Register(namespace)
instrumentedHandler = metrics.InstrumentHandler(httpMetrics, unInstrumentedHandler)Note: The handler label must be provided when a new namespace is created.
Additional Metrics
Additional metrics are also defined here that are not available in the prometheus client.
If you need a custom metrics and it is generic enough to be used by multiple projects, define it here.
Copyright and license
Copyright © 2016 Docker, Inc. All rights reserved, except as follows. Code is released under the Apache 2.0 license.
Overview (`vendor/github.com/felixge/httpsnoop/README.md`)
httpsnoop
Package httpsnoop provides an easy way to capture http related metrics (i.e.
response time, bytes written, and http status code) from your application's
http.Handlers.
Doing this requires non-trivial wrapping of the http.ResponseWriter interface,
which is also exposed for users interested in a more low-level API.
Usage Example
// myH is your app's http handler, perhaps a http.ServeMux or similar.
var myH http.Handler
// wrappedH wraps myH in order to log every request.
wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
m := httpsnoop.CaptureMetrics(myH, w, r)
log.Printf(
"%s %s (code=%d dt=%s written=%d)",
r.Method,
r.URL,
m.Code,
m.Duration,
m.Written,
)
})
http.ListenAndServe(":8080", wrappedH)Why this package exists
Instrumenting an application's http.Handler is surprisingly difficult.
However if you google for e.g. "capture ResponseWriter status code" you'll find
lots of advise and code examples that suggest it to be a fairly trivial
undertaking. Unfortunately everything I've seen so far has a high chance of
breaking your application.
The main problem is that a http.ResponseWriter often implements additional
interfaces such as http.Flusher, http.CloseNotifier, http.Hijacker, http.Pusher, andio.ReaderFrom. So the naive approach of just wrapping http.ResponseWriter
in your own struct that also implements the http.ResponseWriter interface
will hide the additional interfaces mentioned above. This has a high change of
introducing subtle bugs into any non-trivial application.
Another approach I've seen people take is to return a struct that implements
all of the interfaces above. However, that's also problematic, because it's
difficult to fake some of these interfaces behaviors when the underlyinghttp.ResponseWriter doesn't have an implementation. It's also dangerous,
because an application may choose to operate differently, merely because it
detects the presence of these additional interfaces.
This package solves this problem by checking which additional interfaces ahttp.ResponseWriter implements, returning a wrapped version implementing the
exact same set of interfaces.
Additionally this package properly handles edge cases such as WriteHeader not
being called, or called more than once, as well as concurrent calls tohttp.ResponseWriter methods, and even calls happening after the wrappedServeHTTP has already returned.
Unfortunately this package is not perfect either. It's possible that it is
still missing some interfaces provided by the go core (let me know if you find
one), and it won't work for applications adding their own interfaces into the
mix. You can however use httpsnoop.Unwrap(w) to access the underlyinghttp.ResponseWriter and type-assert the result to its other interfaces.
However, hopefully the explanation above has sufficiently scared you of rolling
your own solution to this problem. httpsnoop may still break your application,
but at least it tries to avoid it as much as possible.
Anyway, the real problem here is that smuggling additional interfaces insidehttp.ResponseWriter is a problematic design choice, but it probably goes as
deep as the Go language specification itself. But that's okay, I still prefer
Go over the alternatives ;).
Performance
BenchmarkBaseline-8 20000 94912 ns/op
BenchmarkCaptureMetrics-8 20000 95461 ns/opAs you can see, using CaptureMetrics on a vanilla http.Handler introduces an
overhead of ~500 ns per http request on my machine. However, the margin of
error appears to be larger than that, therefor it should be reasonable to
assume that the overhead introduced by CaptureMetrics is absolutely
negligible.
License
MIT
Overview (`vendor/github.com/go-logr/logr/README.md`)
A minimal logging API for Go
logr offers an(other) opinion on how Go programs and libraries can do logging
without becoming coupled to a particular logging implementation. This is not
an implementation of logging - it is an API. In fact it is two APIs with two
different sets of users.
The Logger type is intended for application and library authors. It provides
a relatively small API which can be used everywhere you want to emit logs. It
defers the actual act of writing logs (to files, to stdout, or whatever) to theLogSink interface.
The LogSink interface is intended for logging library implementers. It is a
pure interface which can be implemented by logging frameworks to provide the actual logging
functionality.
This decoupling allows application and library developers to write code in
terms of logr.Logger (which has very low dependency fan-out) while the
implementation of logging is managed "up stack" (e.g. in or near main().)
Application developers can then switch out implementations as necessary.
Many people assert that libraries should not be logging, and as such efforts
like this are pointless. Those people are welcome to convince the authors of
the tens-of-thousands of libraries that DO write logs that they are all
wrong. In the meantime, logr takes a more practical approach.
Typical usage
Somewhere, early in an application's life, it will make a decision about which
logging library (implementation) it actually wants to use. Something like:
func main() {
// ... other setup code ...
// Create the "root" logger. We have chosen the "logimpl" implementation,
// which takes some initial parameters and returns a logr.Logger.
logger := logimpl.New(param1, param2)
// ... other setup code ...Most apps will call into other libraries, create structures to govern the flow,
etc. The logr.Logger object can be passed to these other libraries, stored
in structs, or even used as a package-global variable, if needed. For example:
app := createTheAppObject(logger)
app.Run()Outside of this early setup, no other packages need to know about the choice of
implementation. They write logs in terms of the logr.Logger that they
received:
type appObject struct {
// ... other fields ...
logger logr.Logger
// ... other fields ...
}
func (app *appObject) Run() {
app.logger.Info("starting up", "timestamp", time.Now())
// ... app code ...Background
If the Go standard library had defined an interface for logging, this project
probably would not be needed. Alas, here we are.
When the Go developers started developing such an interface with
slog, they adopted some of the
logr design but also left out some parts and changed others:
| Feature | logr | slog |
|---|---|---|
| High-level API | Logger (passed by value) |
Logger (passed by pointer) |
| Low-level API | LogSink |
Handler |
| Stack unwinding | done by LogSink |
done by Logger |
| Skipping helper functions | WithCallDepth, WithCallStackHelper |
not supported by Logger |
| Generating a value for logging on demand | Marshaler |
LogValuer |
| Log levels | >= 0, higher meaning "less important" | positive and negative, with 0 for "info" and higher meaning "more important" |
| Error log entries | always logged, don't have a verbosity level | normal log entries with level >= LevelError |
| Passing logger via context | NewContext, FromContext |
no API |
| Adding a name to a logger | WithName |
no API |
| Modify verbosity of log entries in a call chain | V |
no API |
| Grouping of key/value pairs | not supported | WithGroup, GroupValue |
| Pass context for extracting additional values | no API | API variants like InfoCtx |
The high-level slog API is explicitly meant to be one of many different APIs
that can be layered on top of a shared slog.Handler. logr is one such
alternative API, with interoperability provided by
some conversion functions.
Inspiration
Before you consider this package, please read this blog post by the
inimitable Dave Cheney. We really appreciate what
he has to say, and it largely aligns with our own experiences.
Differences from Dave's ideas
The main differences are:
- Dave basically proposes doing away with the notion of a logging API in favor
offmt.Printf(). We disagree, especially when you consider things like output
locations, timestamps, file and line decorations, and structured logging. This
package restricts the logging API to just 2 types of logs: info and error.
Info logs are things you want to tell the user which are not errors. Error
logs are, well, errors. If your code receives an error from a subordinate
function call and is logging that error and not returning it, use error
logs.
- Verbosity-levels on info logs. This gives developers a chance to indicate
arbitrary grades of importance for info logs, without assigning names with
semantic meaning such as "warning", "trace", and "debug." Superficially this
may feel very similar, but the primary difference is the lack of semantics.
Because verbosity is a numerical value, it's safe to assume that an app running
with higher verbosity means more (and less important) logs will be generated.
Implementations (non-exhaustive)
There are implementations for the following logging libraries:
- a function (can bridge to non-structured libraries): funcr
- a testing.T (for use in Go tests, with JSON-like output): testr
- github.com/google/glog: glogr
- k8s.io/klog (for Kubernetes): klogr
- a testing.T (with klog-like text output): ktesting
- go.uber.org/zap: zapr
- log (the Go standard library logger): stdr
- github.com/sirupsen/logrus: logrusr
- github.com/wojas/genericr: genericr (makes it easy to implement your own backend)
- logfmt (Heroku style logging): logfmtr
- github.com/rs/zerolog: zerologr
- github.com/go-kit/log: gokitlogr (also compatible with github.com/go-kit/kit/log since v0.12.0)
- bytes.Buffer (writing to a buffer): bufrlogr (useful for ensuring values were logged, like during testing)
slog interoperability
Interoperability goes both ways, using the logr.Logger API with a slog.Handler
and using the slog.Logger API with a logr.LogSink. FromSlogHandler andToSlogHandler convert between a logr.Logger and a slog.Handler.
As usual, slog.New can be used to wrap such a slog.Handler in the high-level
slog API.
Using a `logr.LogSink` as backend for slog
Ideally, a logr sink implementation should support both logr and slog by
implementing both the normal logr interface(s) and SlogSink. Because
of a conflict in the parameters of the common Enabled method, it is not
possible to implement both slog.Handler and logr.Sink in the same
type.
If both are supported, log calls can go from the high-level APIs to the backend
without the need to convert parameters. FromSlogHandler and ToSlogHandler can
convert back and forth without adding additional wrappers, with one exception:
when Logger.V was used to adjust the verbosity for a slog.Handler, thenToSlogHandler has to use a wrapper which adjusts the verbosity for future
log calls.
Such an implementation should also support values that implement specific
interfaces from both packages for logging (logr.Marshaler, slog.LogValuer,slog.GroupValue). logr does not convert those.
Not supporting slog has several drawbacks:
- Recording source code locations works correctly if the handler gets called
throughslog.Logger, but may be wrong in other cases. That's because alogr.Sinkdoes its own stack unwinding instead of using the program counter
provided by the high-level API. - slog levels <= 0 can be mapped to logr levels by negating the level without a
loss of information. But all slog levels > 0 (e.g.slog.LevelWarningas
used byslog.Logger.Warn) must be mapped to 0 before calling the sink
because logr does not support "more important than info" levels. - The slog group concept is supported by prefixing each key in a key/value
pair with the group names, separated by a dot. For structured output like
JSON it would be better to group the key/value pairs inside an object. - Special slog values and interfaces don't work as expected.
- The overhead is likely to be higher.
These drawbacks are severe enough that applications using a mixture of slog and
logr should switch to a different backend.
Using a `slog.Handler` as backend for logr
Using a plain slog.Handler without support for logr works better than the
other direction:
- All logr verbosity levels can be mapped 1:1 to their corresponding slog level
by negating them. - Stack unwinding is done by the
SlogSinkand the resulting program
counter is passed to theslog.Handler. - Names added via
Logger.WithNameare gathered and recorded in an additional
attribute withloggeras key and the names separated by slash as value. Logger.Erroris turned into a log record withslog.LevelErroras level
and an additional attribute witherras key, if an error was provided.
The main drawback is that logr.Marshaler will not be supported. Types should
ideally support both logr.Marshaler and slog.Valuer. If compatibility
with logr implementations without slog support is not important, thenslog.Valuer is sufficient.
Context support for slog
Storing a logger in a context.Context is not supported by
slog. NewContextWithSlogLogger and FromContextAsSlogLogger can be
used to fill this gap. They store and retrieve a slog.Logger pointer
under the same context key that is also used by NewContext andFromContext for logr.Logger value.
When NewContextWithSlogLogger is followed by FromContext, the latter will
automatically convert the slog.Logger to alogr.Logger. FromContextAsSlogLogger does the same for the other direction.
With this approach, binaries which use either slog or logr are as efficient as
possible with no unnecessary allocations. This is also why the API stores aslog.Logger pointer: when storing a slog.Handler, creating a slog.Logger
on retrieval would need to allocate one.
The downside is that switching back and forth needs more allocations. Because
logr is the API that is already in use by different packages, in particular
Kubernetes, the recommendation is to use the logr.Logger API in code which
uses contextual logging.
An alternative to adding values to a logger and storing that logger in the
context is to store the values in the context and to configure a logging
backend to extract those values when emitting log entries. This only works when
log calls are passed the context, which is not supported by the logr API.
With the slog API, it is possible, but not
required. https://github.com/veqryn/slog-context is a package for slog which
provides additional support code for this approach. It also contains wrappers
for the context functions in logr, so developers who prefer to not use the logr
APIs directly can use those instead and the resulting code will still be
interoperable with logr.
FAQ
Conceptual
Why structured logging?
Structured logs are more easily queryable: Since you've got
key-value pairs, it's much easier to query your structured logs for
particular values by filtering on the contents of a particular key --
think searching request logs for error codes, Kubernetes reconcilers for
the name and namespace of the reconciled object, etc.Structured logging makes it easier to have cross-referenceable logs:
Similarly to searchability, if you maintain conventions around your
keys, it becomes easy to gather all log lines related to a particular
concept.Structured logs allow better dimensions of filtering: if you have
structure to your logs, you've got more precise control over how much
information is logged -- you might choose in a particular configuration
to log certain keys but not others, only log lines where a certain key
matches a certain value, etc., instead of just having v-levels and names
to key off of.Structured logs better represent structured data: sometimes, the
data that you want to log is inherently structured (think tuple-link
objects.) Structured logs allow you to preserve that structure when
outputting.
Why V-levels?
V-levels give operators an easy way to control the chattiness of log
operations. V-levels provide a way for a given package to distinguish
the relative importance or verbosity of a given log message. Then, if
a particular logger or package is logging too many messages, the user
of the package can simply change the v-levels for that library.
Why not named levels, like Info/Warning/Error?
Read Dave Cheney's post. Then read Differences
from Dave's ideas.
Why not allow format strings, too?
Format strings negate many of the benefits of structured logs:
They're not easily searchable without resorting to fuzzy searching,
regular expressions, etc.They don't store structured data well, since contents are flattened into
a string.They're not cross-referenceable.
They don't compress easily, since the message is not constant.
(Unless you turn positional parameters into key-value pairs with numerical
keys, at which point you've gotten key-value logging with meaningless
keys.)
Practical
Why key-value pairs, and not a map?
Key-value pairs are much easier to optimize, especially around
allocations. Zap (a structured logger that inspired logr's interface) has
performance measurements
that show this quite nicely.
While the interface ends up being a little less obvious, you get
potentially better performance, plus avoid making users typemap[string]string{} every time they want to log.
What if my V-levels differ between libraries?
That's fine. Control your V-levels on a per-logger basis, and use theWithName method to pass different loggers to different libraries.
Generally, you should take care to ensure that you have relatively
consistent V-levels within a given logger, however, as this makes deciding
on what verbosity of logs to request easier.
But I really want to use a format string!
That's not actually a question. Assuming your question is "how do
I convert my mental model of logging with format strings to logging with
constant messages":
Figure out what the error actually is, as you'd write in a TL;DR style,
and use that as a message.For every place you'd write a format specifier, look to the word before
it, and add that as a key value pair.
For instance, consider the following examples (all taken from spots in the
Kubernetes codebase):
klog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err)becomeslogger.Error(err, "client returned an error", "code", responseCode)klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v", seconds, retries, url)becomeslogger.V(4).Info("got a retry-after response when requesting url", "attempt", retries, "after seconds", seconds, "url", url)
If you really must use a format string, use it in a key's value, and
call fmt.Sprintf yourself. For instance: log.Printf("unable to reflect over type %T") becomes logger.Info("unable to reflect over type", "type", fmt.Sprintf("%T")). In general though, the cases where
this is necessary should be few and far between.
How do I choose my V-levels?
This is basically the only hard constraint: increase V-levels to denote
more verbose or more debug-y logs.
Otherwise, you can start out with 0 as "you always want to see this",1 as "common logging that you might possibly want to turn off", and10 as "I would like to performance-test your log collection stack."
Then gradually choose levels in between as you need them, working your way
down from 10 (for debug and trace style logs) and up from 1 (for chattier
info-type logs). For reference, slog pre-defines -4 for debug logs
(corresponds to 4 in logr), which matches what is
recommended for Kubernetes.
How do I choose my keys?
Keys are fairly flexible, and can hold more or less any string
value. For best compatibility with implementations and consistency
with existing code in other projects, there are a few conventions you
should consider.
- Make your keys human-readable.
- Constant keys are generally a good idea.
- Be consistent across your codebase.
- Keys should naturally match parts of the message string.
- Use lower case for simple keys and
lowerCamelCase for
more complex ones. Kubernetes is one example of a project that has
adopted that
convention.
While key names are mostly unrestricted (and spaces are acceptable),
it's generally a good idea to stick to printable ascii characters, or at
least match the general character set of your log lines.
Why should keys be constant values?
The point of structured logging is to make later log processing easier. Your
keys are, effectively, the schema of each log message. If you use different
keys across instances of the same log line, you will make your structured logs
much harder to use. Sprintf() is for values, not for keys!
Why is this not a pure interface?
The Logger type is implemented as a struct in order to allow the Go compiler to
optimize things like high-V Info logs that are not triggered. Not all of
these implementations are implemented yet, but this structure was suggested as
a way to ensure they can be implemented. All of the real work is behind theLogSink interface.
Overview (`vendor/github.com/go-logr/stdr/README.md`)
Minimal Go logging using logr and Go's standard library
This package implements the logr interface
in terms of Go's standard log package(https://pkg.go.dev/log).
Overview (`vendor/github.com/google/s2a-go/README.md`)
Secure Session Agent Client Libraries
The Secure Session Agent is a service that enables a workload to offload select
operations from the mTLS handshake and protects a workload's private key
material from exfiltration. Specifically, the workload asks the Secure Session
Agent for the TLS configuration to use during the handshake, to perform private
key operations, and to validate the peer certificate chain. The Secure Session
Agent's client libraries enable applications to communicate with the Secure
Session Agent during the TLS handshake, and to encrypt traffic to the peer
after the TLS handshake is complete.
This repository contains the source code for the Secure Session Agent's Go
client libraries, which allow gRPC and HTTP Go applications to use the Secure Session
Agent.
Overview (`vendor/github.com/google/uuid/README.md`)
uuid
The uuid package generates and inspects UUIDs based on
RFC 4122
and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid). It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice. One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).
Install
go get github.com/google/uuidDocumentation
Full go doc style documentation for the package can be viewed online without
installing this package by using the GoDoc site here:
http://pkg.go.dev/github.com/google/uuid
Overview (`vendor/github.com/gorilla/handlers/README.md`)
gorilla/handlers
Package handlers is a collection of handlers (aka "HTTP middleware") for use
with Go's net/http package (or any framework supporting http.Handler), including:
- LoggingHandler for logging HTTP requests in the Apache Common Log
Format. - CombinedLoggingHandler for logging HTTP requests in the Apache Combined Log
Format commonly used by
both Apache and nginx. - CompressHandler for gzipping responses.
- ContentTypeHandler for validating requests against a list of accepted
content types. - MethodHandler for matching HTTP methods against handlers in a
map[string]http.Handler - ProxyHeaders for populating
r.RemoteAddrandr.URL.Schemebased on theX-Forwarded-For,X-Real-IP,X-Forwarded-Protoand RFC7239Forwarded
headers when running a Go server behind a HTTP reverse proxy. - CanonicalHost for re-directing to the preferred host when handling multiple
domains (i.e. multiple CNAME aliases). - RecoveryHandler for recovering from unexpected panics.
Other handlers are documented on the Gorilla
website.
Example
A simple example using handlers.LoggingHandler and handlers.CompressHandler:
import (
"net/http"
"github.com/gorilla/handlers"
)
func main() {
r := http.NewServeMux()
// Only log requests to our admin dashboard to stdout
r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
r.HandleFunc("/", ShowIndex)
// Wrap our server with our gzip handler to gzip compress all responses.
http.ListenAndServe(":8000", handlers.CompressHandler(r))
}License
BSD licensed. See the included LICENSE file for details.
Overview (`vendor/github.com/gorilla/mux/README.md`)
gorilla/mux
Package gorilla/mux implements a request router and dispatcher for matching incoming requests to
their respective handler.
The name mux stands for "HTTP request multiplexer". Like the standard http.ServeMux, mux.Router matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
- It implements the
http.Handlerinterface so it is compatible with the standardhttp.ServeMux. - Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
- URL hosts, paths and query values can have variables with an optional regular expression.
- Registered URLs can be built, or "reversed", which helps maintaining references to resources.
- Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
- Install
- Examples
- Matching Routes
- Static Files
- Serving Single Page Applications (e.g. React, Vue, Ember.js, etc.)
- Registered URLs
- Walking Routes
- Graceful Shutdown
- Middleware
- Handling CORS Requests
- Testing Handlers
- Full Example
Install
With a correctly configured Go toolchain:
go get -u github.com/gorilla/muxExamples
Let's start registering a couple of URL paths and handlers:
func main() {
r := mux.NewRouter()
r.HandleFunc("/", HomeHandler)
r.HandleFunc("/products", ProductsHandler)
r.HandleFunc("/articles", ArticlesHandler)
http.Handle("/", r)
}Here we register three routes mapping URL paths to handlers. This is equivalent to how http.HandleFunc() works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (http.ResponseWriter, *http.Request) as parameters.
Paths can have variables. They are defined using the format {name} or {name:pattern}. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)The names are used to create a map of route variables which can be retrieved calling mux.Vars():
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Category: %v\n", vars["category"])
}And this is all you need to know about the basic usage. More advanced options are explained below.
Matching Routes
Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
r := mux.NewRouter()
// Only matches if domain is "www.example.com".
r.Host("www.example.com")
// Matches a dynamic subdomain.
r.Host("{subdomain:[a-z]+}.example.com")There are several other matchers that can be added. To match path prefixes:
r.PathPrefix("/products/")...or HTTP methods:
r.Methods("GET", "POST")...or URL schemes:
r.Schemes("https")...or header values:
r.Headers("X-Requested-With", "XMLHttpRequest")...or query values:
r.Queries("key", "value")...or to use a custom matcher function:
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
return r.ProtoMajor == 0
})...and finally, it is possible to combine several matchers in a single route:
r.HandleFunc("/products", ProductsHandler).
Host("www.example.com").
Methods("GET").
Schemes("http")Routes are tested in the order they were added to the router. If two routes match, the first one wins:
r := mux.NewRouter()
r.HandleFunc("/specific", specificHandler)
r.PathPrefix("/").Handler(catchAllHandler)Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
For example, let's say we have several URLs that should only match when the host is www.example.com. Create a route for that host and get a "subrouter" from it:
r := mux.NewRouter()
s := r.Host("www.example.com").Subrouter()Then register routes in the subrouter:
s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)The three URL paths we registered above will only be tested if the domain is www.example.com, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.
There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:
r := mux.NewRouter()
s := r.PathPrefix("/products").Subrouter()
// "/products/"
s.HandleFunc("/", ProductsHandler)
// "/products/{key}/"
s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)Static Files
Note that the path provided to PathPrefix() represents a "wildcard": callingPathPrefix("/static/").Handler(...) means that the handler will be passed any
request that matches "/static/*". This makes it easy to serve static files with mux:
func main() {
var dir string
flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
flag.Parse()
r := mux.NewRouter()
// This will serve files under http://localhost:8000/static/<filename>
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
srv := &http.Server{
Handler: r,
Addr: "127.0.0.1:8000",
// Good practice: enforce timeouts for servers you create!
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}Serving Single Page Applications
Most of the time it makes sense to serve your SPA on a separate web server from your API,
but sometimes it's desirable to serve them both from one place. It's possible to write a simple
handler for serving your SPA (for use with React Router's BrowserRouter for example), and leverage
mux's powerful routing for your API endpoints.
/* Detailed source-code truncated for AI context efficiency. */Registered URLs
Now let's see how to build registered URLs.
Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling Name() on a route. For example:
r := mux.NewRouter()
r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
Name("article")To build a URL, get the route and call the URL() method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:
url, err := r.Get("article").URL("category", "technology", "id", "42")...and the result will be a url.URL with the following path:
"/articles/technology/42"This also works for host and query value variables:
r := mux.NewRouter()
r.Host("{subdomain}.example.com").
Path("/articles/{category}/{id:[0-9]+}").
Queries("filter", "{filter}").
HandlerFunc(ArticleHandler).
Name("article")
// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42",
"filter", "gorilla")All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
Regex support also exists for matching Headers within a route. For example, we could do:
r.HeadersRegexp("Content-Type", "application/(text|json)")...and the route will match both requests with a Content-Type of application/json as well as application/text
There's also a way to build only the URL host or path for a route: use the methods URLHost() or URLPath() instead. For the previous route, we would do:
// "http://news.example.com/"
host, err := r.Get("article").URLHost("subdomain", "news")
// "/articles/technology/42"
path, err := r.Get("article").URLPath("category", "technology", "id", "42")And if you use subrouters, host and path defined separately can be built as well:
r := mux.NewRouter()
s := r.Host("{subdomain}.example.com").Subrouter()
s.Path("/articles/{category}/{id:[0-9]+}").
HandlerFunc(ArticleHandler).
Name("article")
// "http://news.example.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42")To find all the required variables for a given route when calling URL(), the method GetVarNames() is available:
r := mux.NewRouter()
r.Host("{domain}").
Path("/{group}/{item_id}").
Queries("some_data1", "{some_data1}").
Queries("some_data2", "{some_data2}").
Name("article")
// Will print [domain group item_id some_data1 some_data2] <nil>
fmt.Println(r.Get("article").GetVarNames())Walking Routes
The Walk function on mux.Router can be used to visit all of the routes that are registered on a router. For example,
the following prints all of the registered routes:
package main
import (
"fmt"
"net/http"
"strings"
"github.com/gorilla/mux"
)
func handler(w http.ResponseWriter, r *http.Request) {
return
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.HandleFunc("/products", handler).Methods("POST")
r.HandleFunc("/articles", handler).Methods("GET")
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
pathTemplate, err := route.GetPathTemplate()
if err == nil {
fmt.Println("ROUTE:", pathTemplate)
}
pathRegexp, err := route.GetPathRegexp()
if err == nil {
fmt.Println("Path regexp:", pathRegexp)
}
queriesTemplates, err := route.GetQueriesTemplates()
if err == nil {
fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
}
queriesRegexps, err := route.GetQueriesRegexp()
if err == nil {
fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
}
methods, err := route.GetMethods()
if err == nil {
fmt.Println("Methods:", strings.Join(methods, ","))
}
fmt.Println()
return nil
})
if err != nil {
fmt.Println(err)
}
http.Handle("/", r)
}Graceful Shutdown
Go 1.8 introduced the ability to gracefully shutdown a *http.Server. Here's how to do that alongside mux:
/* Detailed source-code truncated for AI context efficiency. */Middleware
Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters.
Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
Mux middlewares are defined using the de facto standard type:
type MiddlewareFunc func(http.Handler) http.HandlerTypically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.
A very basic middleware which logs the URI of the request being handled could be written as:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do stuff here
log.Println(r.RequestURI)
// Call the next handler, which can be another middleware in the chain, or the final handler.
next.ServeHTTP(w, r)
})
}Middlewares can be added to a router using Router.Use():
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(loggingMiddleware)A more complex authentication middleware, which maps session token to users, could be written as:
// Define our struct
type authenticationMiddleware struct {
tokenUsers map[string]string
}
// Initialize it somewhere
func (amw *authenticationMiddleware) Populate() {
amw.tokenUsers["00000000"] = "user0"
amw.tokenUsers["aaaaaaaa"] = "userA"
amw.tokenUsers["05f717e5"] = "randomUser"
amw.tokenUsers["deadbeef"] = "user0"
}
// Middleware function, which will be called for each request
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-Session-Token")
if user, found := amw.tokenUsers[token]; found {
// We found the token in our map
log.Printf("Authenticated user %s\n", user)
// Pass down the request to the next middleware (or final handler)
next.ServeHTTP(w, r)
} else {
// Write an error and stop the handler chain
http.Error(w, "Forbidden", http.StatusForbidden)
}
})
}r := mux.NewRouter()
r.HandleFunc("/", handler)
amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
amw.Populate()
r.Use(amw.Middleware)Note: The handler chain will be stopped if your middleware doesn't call next.ServeHTTP() with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares should write to ResponseWriter if they are going to terminate the request, and they should not write to ResponseWriter if they are not going to terminate it.
Handling CORS Requests
CORSMethodMiddleware intends to make it easier to strictly set the Access-Control-Allow-Methods response header.
- You will still need to use your own CORS handler to set the other CORS headers such as
Access-Control-Allow-Origin - The middleware will set the
Access-Control-Allow-Methodsheader to all the method matchers (e.g.r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)->Access-Control-Allow-Methods: GET,PUT,OPTIONS) on a route - If you do not specify any methods, then:
Important: there must be an
OPTIONSmethod matcher for the middleware to set the headers.
Here is an example of using CORSMethodMiddleware along with a custom OPTIONS handler to set all the required CORS headers:
package main
import (
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
// IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers
r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)
r.Use(mux.CORSMethodMiddleware(r))
http.ListenAndServe(":8080", r)
}
func fooHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
if r.Method == http.MethodOptions {
return
}
w.Write([]byte("foo"))
}And an request to /foo using something like:
curl localhost:8080/foo -vWould look like:
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /foo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.59.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS
< Access-Control-Allow-Origin: *
< Date: Fri, 28 Jun 2019 20:13:30 GMT
< Content-Length: 3
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
fooTesting Handlers
Testing handlers in a Go web application is straightforward, and mux doesn't complicate this any further. Given two files: endpoints.go and endpoints_test.go, here's how we'd test an application using mux.
First, our simple HTTP handler:
// endpoints.go
package main
func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
// A very simple health check.
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
// In the future we could report back on the status of our DB, or our cache
// (e.g. Redis) by performing a simple PING, and include them in the response.
io.WriteString(w, `{"alive": true}`)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/health", HealthCheckHandler)
log.Fatal(http.ListenAndServe("localhost:8080", r))
}Our test code:
// endpoints_test.go
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHealthCheckHandler(t *testing.T) {
// Create a request to pass to our handler. We don't have any query parameters for now, so we'll
// pass 'nil' as the third parameter.
req, err := http.NewRequest("GET", "/health", nil)
if err != nil {
t.Fatal(err)
}
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(HealthCheckHandler)
// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
// directly and pass in our Request and ResponseRecorder.
handler.ServeHTTP(rr, req)
// Check the status code is what we expect.
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
// Check the response body is what we expect.
expected := `{"alive": true}`
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}In the case that our routes have variables, we can pass those in the request. We could write
table-driven tests to test multiple
possible route variables as needed.
// endpoints.go
func main() {
r := mux.NewRouter()
// A route with a route variable:
r.HandleFunc("/metrics/{type}", MetricsHandler)
log.Fatal(http.ListenAndServe("localhost:8080", r))
}Our test file, with a table-driven test of routeVariables:
// endpoints_test.go
func TestMetricsHandler(t *testing.T) {
tt := []struct{
routeVariable string
shouldPass bool
}{
{"goroutines", true},
{"heap", true},
{"counters", true},
{"queries", true},
{"adhadaeqm3k", false},
}
for _, tc := range tt {
path := fmt.Sprintf("/metrics/%s", tc.routeVariable)
req, err := http.NewRequest("GET", path, nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
// To add the vars to the context,
// we need to create a router through which we can pass the request.
router := mux.NewRouter()
router.HandleFunc("/metrics/{type}", MetricsHandler)
router.ServeHTTP(rr, req)
// In this case, our MetricsHandler returns a non-200 response
// for a route variable it doesn't know about.
if rr.Code == http.StatusOK && !tc.shouldPass {
t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
tc.routeVariable, rr.Code, http.StatusOK)
}
}
}Full Example
Here's a complete, runnable example of a small mux based server:
package main
import (
"net/http"
"log"
"github.com/gorilla/mux"
)
func YourHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Gorilla!\n"))
}
func main() {
r := mux.NewRouter()
// Routes consist of a path and a handler function.
r.HandleFunc("/", YourHandler)
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}License
BSD licensed. See the LICENSE file for details.
Overview (`vendor/github.com/inconshreveable/mousetrap/README.md`)
mousetrap
mousetrap is a tiny library that answers a single question.
On a Windows machine, was the process invoked by someone double clicking on
the executable file while browsing in explorer?
Motivation
Windows developers unfamiliar with command line tools will often "double-click"
the executable for a tool. Because most CLI tools print the help and then exit
when invoked without arguments, this is often very frustrating for those users.
mousetrap provides a way to detect these invocations so that you can provide
more helpful behavior and instructions on how to run the CLI tool. To see what
this looks like, both from an organizational and a technical perspective, see
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/
The interface
The library exposes a single interface:
func StartedByExplorer() (bool)Overview (`vendor/github.com/jmespath/go-jmespath/README.md`)
go-jmespath - A JMESPath implementation in Go
go-jmespath is a GO implementation of JMESPath,
which is a query language for JSON. It will take a JSON
document and transform it into another JSON document
through a JMESPath expression.
Using go-jmespath is really easy. There's a single function
you use, jmespath.search:
> import "github.com/jmespath/go-jmespath"
>
> var jsondata = []byte(`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.Search("foo.bar.baz[2]", data)
result = 2In the example we gave the search function input data of{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}} as well as the JMESPath
expression foo.bar.baz[2], and the search function evaluated
the expression against the input data to produce the result 2.
The JMESPath language can do a lot more than select an element
from a list. Here are a few more examples:
> var jsondata = []byte(`{"foo": {"bar": {"baz": [0, 1, 2, 3, 4]}}}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search("foo.bar", data)
result = { "baz": [ 0, 1, 2, 3, 4 ] }
> var jsondata = []byte(`{"foo": [{"first": "a", "last": "b"},
{"first": "c", "last": "d"}]}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search({"foo[*].first", data)
result [ 'a', 'c' ]
> var jsondata = []byte(`{"foo": [{"age": 20}, {"age": 25},
{"age": 30}, {"age": 35},
{"age": 40}]}`) // your data
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> result, err := jmespath.search("foo[?age > `30`]")
result = [ { age: 35 }, { age: 40 } ]You can also pre-compile your query. This is usefull if
you are going to run multiple searches with it:
> var jsondata = []byte(`{"foo": "bar"}`)
> var data interface{}
> err := json.Unmarshal(jsondata, &data)
> precompiled, err := Compile("foo")
> if err != nil{
> // ... handle the error
> }
> result, err := precompiled.Search(data)
result = "bar"More Resources
The example above only show a small amount of what
a JMESPath expression can do. If you want to take a
tour of the language, the best place to go is the
JMESPath Tutorial.
One of the best things about JMESPath is that it is
implemented in many different programming languages including
python, ruby, php, lua, etc. To see a complete list of libraries,
check out the JMESPath libraries page.
And finally, the full JMESPath specification can be found
on the JMESPath site.
Overview (`vendor/github.com/klauspost/compress/README.md`)
compress
This package provides various compression algorithms.
- zstandard compression and decompression in pure Go.
- S2 is a high performance replacement for Snappy.
- Optimized deflate packages which can be used as a dropin replacement for gzip, zip and zlib.
- snappy is a drop-in replacement for
github.com/golang/snappyoffering better compression and concurrent streams. - huff0 and FSE implementations for raw entropy encoding.
- gzhttp Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
- pgzip is a separate package that provides a very fast parallel gzip implementation.
package usage
Use go get github.com/klauspost/compress@latest to add it to your project.
This package will support the current Go version and 2 versions back.
- Use the
nounsafetag to disable all use of the "unsafe" package. - Use the
noasmtag to disable all assembly across packages.
Use the links above for more information on each.
changelog
Jan 16th, 2026 1.18.3
- Downstream CVE-2025-61728. See golang/go#77102.
Dec 1st, 2025 - 1.18.2
- flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
- flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106
Oct 20, 2025 - 1.18.1 - RETRACTED
- zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079
- zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
- s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
- zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
- gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
- flate: Faster load+store https://github.com/klauspost/compress/pull/1104
- flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
- flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103
Feb 19th, 2025 - 1.18.0
Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
fix: check
r.err != nilbut return a nil value errorerrby @alingse in https://github.com/klauspost/compress/pull/1028flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
See changes to v1.17.x
Oct 11th, 2024 - 1.17.11
- zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
- s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
- gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
- gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013
Sep 23rd, 2024 - 1.17.10
- gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
- gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
- s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
- zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
- flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996
Jun 12th, 2024 - 1.17.9
- s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
- flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
- Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
- zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951
Apr 9th, 2024 - 1.17.8
- zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
- zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938
Feb 21st, 2024 - 1.17.7
- s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
- s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
Feb 5th, 2024 - 1.17.6
- zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
- s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
Jan 26th, 2024 - v1.17.5
- flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912
- zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908
- zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913
- zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910
- s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917
https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918
Dec 1st, 2023 - v1.17.4
- huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887
- huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886
- gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892
- gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890
- gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891
Nov 15th, 2023 - v1.17.3
- fse: Fix max header size https://github.com/klauspost/compress/pull/881
- zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877
- gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883
Oct 22nd, 2023 - v1.17.2
- zstd: Fix rare CORRUPTION output in "best" mode. See https://github.com/klauspost/compress/pull/876
Oct 14th, 2023 - v1.17.1
- s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
- flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
- s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867
Sept 19th, 2023 - v1.17.0
- Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
- Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
- flate: Add limited window compression https://github.com/klauspost/compress/pull/843
- s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
- flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
- gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
See changes to v1.16.x
July 1st, 2023 - v1.16.7
- zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
- s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832
June 13, 2023 - v1.16.6
- zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
- zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
- gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815
- s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663
Apr 16, 2023 - v1.16.5
- zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802
- gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804
Apr 5, 2023 - v1.16.4
- zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784
- zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792
- zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785
- zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
- s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
- s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
- gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
Mar 13, 2023 - v1.16.1
- zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
- gzhttp: Add optional BREACH mitigation. https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
- s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
- zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
- huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
Feb 26, 2023 - v1.16.0
- s2: Add Dictionary support. https://github.com/klauspost/compress/pull/685
- s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
- s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
- s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
- s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
- s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
See changes to v1.15.x
Jan 21st, 2023 (v1.15.15)
- deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
- zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
- zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
- gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
Jan 3rd, 2023 (v1.15.14)
- flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
- zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
- export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
- s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723
Dec 11, 2022 (v1.15.13)
- zstd: Add MaxEncodedSize to encoder https://github.com/klauspost/compress/pull/691
- zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708
Oct 26, 2022 (v1.15.12)
- zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
- gzhttp: Always delete
HeaderNoCompressionhttps://github.com/klauspost/compress/pull/683
Sept 26, 2022 (v1.15.11)
- flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678
- zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677
- zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668
- zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667
Sept 16, 2022 (v1.15.10)
- zstd: Add WithDecodeAllCapLimit https://github.com/klauspost/compress/pull/649
- Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
- flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
- zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657
- s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
- s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
- s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
- Use arrays for constant size copies https://github.com/klauspost/compress/pull/659
July 21, 2022 (v1.15.9)
- zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
- zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
- zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643
July 13, 2022 (v1.15.8)
- gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641
- s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638
- zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636
- zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637
- huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634
- zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640
- gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639
June 29, 2022 (v1.15.7)
- s2: Fix absolute forward seeks https://github.com/klauspost/compress/pull/633
- zip: Merge upstream https://github.com/klauspost/compress/pull/631
- zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624
- zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598
- flate: Faster histograms https://github.com/klauspost/compress/pull/620
- deflate: Use compound hcode https://github.com/klauspost/compress/pull/622
June 3, 2022 (v1.15.6)
- s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613
- s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611
- zstd: Always use configured block size https://github.com/klauspost/compress/pull/605
- zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606
- zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608
- gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612
- s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609
- s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607
- snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614
- s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610
May 25, 2022 (v1.15.5)
- s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
- s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
- huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
- zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
- zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
- zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
- zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
- huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
- flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590
May 11, 2022 (v1.15.4)
May 5, 2022 (v1.15.3)
Apr 26, 2022 (v1.15.2)
Mar 11, 2022 (v1.15.1)
Mar 3, 2022 (v1.15.0)
Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.
Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected.
While the release has been extensively tested, it is recommended to testing when upgrading.
See changes to v1.14.xFeb 22, 2022 (v1.14.4)
Feb 17, 2022 (v1.14.3)
Jan 25, 2022 (v1.14.2)
Jan 11, 2022 (v1.14.1)
- s2: Add stream index in #462
- flate: Speed and efficiency improvements in #439 #461 #455 #452 #458
- zstd: Performance improvement in #420 #456 #437 #467 #468
- zstd: add arm64 xxhash assembly in #464
- Add garbled for binaries for s2 in #445
See changes to v1.13.x
Aug 30, 2021 (v1.13.5)
Aug 12, 2021 (v1.13.4)
- Add snappy replacement package.
- zstd: Fix incorrect encoding in "best" mode #415
Aug 3, 2021 (v1.13.3)
Jun 14, 2021 (v1.13.1)
- s2: Add full Snappy output support #396
- zstd: Add configurable Decoder window size #394
- gzhttp: Add header to skip compression #389
- s2: Improve speed with bigger output margin #395
Jun 3, 2021 (v1.13.0)
- Added gzhttp which allows wrapping HTTP servers and clients with GZIP compressors.
- zstd: Detect short invalid signatures #382
- zstd: Spawn decoder goroutine only if needed. #380
See changes to v1.12.x
May 25, 2021 (v1.12.3)
Apr 27, 2021 (v1.12.2)
Apr 14, 2021 (v1.12.1)
- snappy package removed. Upstream added as dependency.
- s2: Better compression in "best" mode #353
- s2sx: Add stdin input and detect pre-compressed from signature #352
- s2c/s2d: Add http as possible input #348
- s2c/s2d/s2sx: Always truncate when writing files #352
- zstd: Reduce memory usage further when using WithLowerEncoderMem #346
- s2: Fix potential problem with amd64 assembly and profilers #349
See changes to v1.11.x
Mar 26, 2021 (v1.11.13)
Mar 5, 2021 (v1.11.12)
- s2: Add
s2sxbinary that creates self extracting archives. - s2: Speed up decompression on non-assembly platforms #328
- s2: Add
Mar 1, 2021 (v1.11.9)
Feb 25, 2021 (v1.11.8)
Jan 14, 2021 (v1.11.7)
Jan 7, 2021 (v1.11.6)
Dec 20, 2020 (v1.11.4)
Nov 15, 2020 (v1.11.3)
Oct 11, 2020 (v1.11.2)
- s2: Fix out of bounds read in "better" block compression #291
Oct 1, 2020 (v1.11.1)
- zstd: Set allLitEntropy true in default configuration #286
Sept 8, 2020 (v1.11.0)
- zstd: Add experimental compression dictionaries #281
- zstd: Fix mixed Write and ReadFrom calls #282
- inflate/gz: Limit variable shifts, ~5% faster decompression #274
See changes to v1.10.x
July 8, 2020 (v1.10.11)
June 23, 2020 (v1.10.10)
- zstd: Skip entropy compression in fastest mode when no matches. #270
June 16, 2020 (v1.10.9):
June 5, 2020 (v1.10.8):
- 1.15x faster zstd block decompression. #265
June 1, 2020 (v1.10.7):
- Added zstd decompression dictionary support
- Increase zstd decompression speed up to 1.19x. #259
- Remove internal reset call in zstd compression and reduce allocations. #263
May 21, 2020: (v1.10.6)
April 12, 2020: (v1.10.5)
- s2-commands: Flush output when receiving SIGINT. #239
Apr 8, 2020: (v1.10.4)
Mar 11, 2020: (v1.10.3)
Feb 27, 2020: (v1.10.2)
Feb 18, 2020: (v1.10.1)
Feb 4, 2020: (v1.10.0)
- Add optional dictionary to stateless deflate. Breaking change, send
nilfor previous behaviour. #216 - Fix buffer overflow on repeated small block deflate. #218
- Allow copying content from an existing ZIP file without decompressing+compressing. #214
- Added S2 AMD64 assembler and various optimizations. Stream speed >10GB/s. #186
See changes prior to v1.10.0
- Add optional dictionary to stateless deflate. Breaking change, send
Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. #207 by luyu6056, #206.
Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. #204
Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed.
Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases.
Jan 4, 2020: Faster IO in s2c + s2d commandline tools compression/decompression. #192
Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder.
Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. #199
Dec 29, 2019: zip package updated with latest Go features
Dec 29, 2019: zstd: Single segment flag condintions tweaked. #197
Dec 18, 2019: s2: Faster compression when ReadFrom is used. #198
Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit.
Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. #191
Dec 3, 2019: (v1.9.4) S2: limit max repeat length. #188
Dec 3, 2019: Add WithNoEntropyCompression to zstd #187
Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines.
Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate.
Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. #184
Nov 12, 2019 (v1.9.2) Added Stateless Compression for gzip/deflate.
Nov 12, 2019: Fixed zstd decompression of large single blocks. #180
Nov 11, 2019: Set default s2c block size to 4MB.
Nov 11, 2019: Reduce inflate memory use by 1KB.
Nov 10, 2019: Less allocations in deflate bit writer.
Nov 10, 2019: Fix inconsistent error returned by zstd decoder.
Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. #174
Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption #173
Oct 24, 2019 zstd: Fix huff0 out of buffer write #171 and always return errors #172
Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression #105
See changes prior to v1.9.0
Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. #169
Oct 3, 2019: Fix inconsistent results on broken zstd streams.
Sep 25, 2019: Added
-rm(remove source files) and-q(no output except errors) tos2cands2dcommandsSep 16, 2019: (v1.8.4) Add
s2cands2dcommandline tools.Sep 10, 2019: (v1.8.3) Fix s2 decoder Skip.
Sep 7, 2019: zstd: Added WithWindowSize, contributed by ianwilkes.
Sep 5, 2019: (v1.8.2) Add WithZeroFrames which adds full zero payload block encoding option.
Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables.
Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode.
Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding.
Aug 24, 2019: (v1.8.0) Added S2 compression, a high performance replacement for Snappy.
Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing.
Aug 18, 2019: Add fuzzit continuous fuzzing.
Aug 14, 2019: zstd: Skip incompressible data 2x faster. #147
Aug 4, 2019 (v1.7.5): Better literal compression. #146
July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder.
July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder.
July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content.
July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix.
June 17, 2019: zstd decompression bugfix.
June 17, 2019: fix 32 bit builds.
June 17, 2019: Easier use in modules (less dependencies).
June 9, 2019: New stronger "default" zstd compression mode. Matches zstd default compression ratio.
June 5, 2019: 20-40% throughput in zstandard compression and better compression.
June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels.
June 2, 2019: Added zstandard compression!
May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels.
Apr 22, 2019: zstd decompression added.
Aug 1, 2018: Added huff0 README.
Jul 8, 2018: Added Performance Update 2018 below.
Jun 23, 2018: Merged Go 1.11 inflate optimizations. Go 1.9 is now required. Backwards compatible version tagged with v1.3.0.
Apr 2, 2018: Added huff0 en/decoder. Experimental for now, API may change.
Mar 4, 2018: Added FSE Entropy en/decoder. Experimental for now, API may change.
Nov 3, 2017: Add compression Estimate function.
May 28, 2017: Reduce allocations when resetting decoder.
Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7.
Jan 14, 2017: Reduce stack pressure due to array copies. See Issue #18625.
Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before.
Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update.
Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level.
Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression.
Mar 24, 2016: Small speedup for level 1-3.
Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
Feb 19, 2016: Handle small payloads faster in level 1-3.
Feb 19, 2016: Added faster level 2 + 3 compression modes.
Feb 19, 2016: Rebalanced compression levels, so there is a more even progression in terms of compression. New default level is 5.
Feb 14, 2016: Snappy: Merge upstream changes.
Feb 14, 2016: Snappy: Fix aggressive skipping.
Feb 14, 2016: Snappy: Update benchmark.
Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression.
Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%.
Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content.
Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup.
Jan 16, 2016: Optimization on deflate level 1,2,3 compression.
Jan 8 2016: Merge CL 18317: fix reading, writing of zip64 archives.
Dec 8 2015: Make level 1 and -2 deterministic even if write size differs.
Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms.
Dec 8 2015: Fixed rare one byte out-of bounds read. Please update!
Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by @dsnet.
Nov 20 2015: Small optimization to bit writer on 64 bit systems.
Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See #15.
Nov 12 2015: Added io.WriterTo support to gzip/inflate.
Nov 11 2015: Merged CL 16669: archive/zip: enable overriding (de)compressors per file
Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x.
deflate usage
The packages are drop-in replacements for standard library deflate, gzip, zip, and zlib. Simply replace the import path to use them:
Typical speed is about 2x of the standard library packages.
| old import | new import | Documentation |
|---|---|---|
compress/gzip |
github.com/klauspost/compress/gzip |
gzip |
compress/zlib |
github.com/klauspost/compress/zlib |
zlib |
archive/zip |
github.com/klauspost/compress/zip |
zip |
compress/flate |
github.com/klauspost/compress/flate |
flate |
You may also be interested in pgzip, which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized crc32 package used by these packages.
The packages implement the same API as the standard library, so you can use the original godoc documentation: gzip, zip, zlib, flate.
Currently there is only minor speedup on decompression (mostly CRC32 calculation).
Memory usage is typically 1MB for a Writer. stdlib is in the same range.
If you expect to have a lot of concurrently allocated Writers consider using
the stateless compression described below.
For compression performance, see: this spreadsheet.
To disable all assembly add -tags=noasm. This works across all packages.
Stateless compression
This package offers stateless compression as a special option for gzip/deflate.
It will do compression but without maintaining any state between Write calls.
This means there will be no memory kept between Write calls, but compression and speed will be suboptimal.
This is only relevant in cases where you expect to run many thousands of compressors concurrently,
but with very little activity. This is not intended for regular web servers serving individual requests.
Because of this, the size of actual Write calls will affect output size.
In gzip, specify level -3 / gzip.StatelessCompression to enable.
For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See documentation
A bufio.Writer can of course be used to control write sizes. For example, to use a 4KB buffer:
// replace 'ioutil.Discard' with your output.
gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression)
if err != nil {
return err
}
defer gzw.Close()
w := bufio.NewWriterSize(gzw, 4096)
defer w.Flush()
// Write to 'w'This will only use up to 4KB in memory when the writer is idle.
Compression is almost always worse than the fastest compression level
and each write will allocate (a little) memory.
Other packages
Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code):
- github.com/pierrec/lz4 - strong multithreaded LZ4 compression.
- github.com/cosnicolaou/pbzip2 - multithreaded bzip2 decompression.
- github.com/dsnet/compress - brotli decompression, bzip2 writer.
- github.com/ronanh/intcomp - Integer compression.
- github.com/spenczar/fpc - Float compression.
- github.com/minio/zipindex - External ZIP directory index.
- github.com/ybirader/pzip - Fast concurrent zip archiver and extractor.
license
This code is licensed under the same conditions as the original Go code. See LICENSE file.
Overview (`vendor/github.com/mitchellh/mapstructure/README.md`)
mapstructure [](https://godoc.org/github.com/mitchellh/mapstructure)
mapstructure is a Go library for decoding generic map values to structures
and vice versa, while providing helpful error handling.
This library is most useful when decoding values from some data stream (JSON,
Gob, etc.) where you don't quite know the structure of the underlying data
until you read a part of it. You can therefore read a map[string]interface{}
and use this library to decode it into the proper underlying native Go
structure.
Installation
Standard go get:
$ go get github.com/mitchellh/mapstructureUsage & Example
For usage and examples see the Godoc.
The Decode function has examples associated with it there.
But Why?!
Go offers fantastic standard libraries for decoding formats such as JSON.
The standard method is to have a struct pre-created, and populate that struct
from the bytes of the encoded format. This is great, but the problem is if
you have configuration or an encoding that changes slightly depending on
specific fields. For example, consider this JSON:
{
"type": "person",
"name": "Mitchell"
}Perhaps we can't populate a specific structure without first reading
the "type" field from the JSON. We could always do two passes over the
decoding of the JSON (reading the "type" first, and the rest later).
However, it is much simpler to just decode this into a map[string]interface{}
structure, read the "type" key, then use something like this library
to decode it into the proper structure.
Overview (`vendor/github.com/opencontainers/go-digest/README.md`)
go-digest
Common digest package used across the container ecosystem.
Please see the godoc for more information.
What is a digest?
A digest is just a hash.
The most common use case for a digest is to create a content identifier for use in Content Addressable Storage systems:
id := digest.FromBytes([]byte("my content"))In the example above, the id can be used to uniquely identify the byte slice "my content".
This allows two disparate applications to agree on a verifiable identifier without having to trust one another.
An identifying digest can be verified, as follows:
if id != digest.FromBytes([]byte("my content")) {
return errors.New("the content has changed!")
}A Verifier type can be used to handle cases where an io.Reader makes more sense:
rd := getContent()
verifier := id.Verifier()
io.Copy(verifier, rd)
if !verifier.Verified() {
return errors.New("the content has changed!")
}Using Merkle DAGs, this can power a rich, safe, content distribution system.
Usage
While the godoc is considered the best resource, a few important items need to be called out when using this package.
Make sure to import the hash implementations into your application or the package will panic.
You should have something like the following in the main (or other entrypoint) of your application:goimport ( _ "crypto/sha256" _ "crypto/sha512" )This may seem inconvenient but it allows you replace the hash
implementations with others, such as https://github.com/stevvooe/resumable.Even though
digest.Digestmay be assemblable as a string, always verify your input withdigest.Parseor useDigest.Validatewhen accepting untrusted input.
While there are measures to avoid common problems, this will ensure you have valid digests in the rest of your application.While alternative encodings of hash values (digests) are possible (for example, base64), this package deals exclusively with hex-encoded digests.
Stability
The Go API, at this stage, is considered stable, unless otherwise noted.
As always, before using a package export, read the godoc.
Contributing
This package is considered fairly complete.
It has been in production in thousands (millions?) of deployments and is fairly battle-hardened.
New additions will be met with skepticism.
If you think there is a missing feature, please file a bug clearly describing the problem and the alternatives you tried before submitting a PR.
Code of Conduct
Participation in the OpenContainers community is governed by OpenContainer's Code of Conduct.
Security
If you find an issue, please follow the security protocol to report it.
Copyright and license
Copyright © 2019, 2020 OCI Contributors
Copyright © 2016 Docker, Inc.
All rights reserved, except as follows.
Code is released under the Apache 2.0 license.
This README.md file and the CONTRIBUTING.md file are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file LICENSE.docs.
You may obtain a duplicate copy of the same license, titled CC BY-SA 4.0, at http://creativecommons.org/licenses/by-sa/4.0/.
Overview (`vendor/github.com/pkg/browser/README.md`)
browser
import "github.com/pkg/browser"Package browser provides helpers to open files, readers, and urls in a browser window.
The choice of which browser is started is entirely client dependant.
Variables
var Stderr io.Writer = os.StderrStderr is the io.Writer to which executed commands write standard error.
var Stdout io.Writer = os.StdoutStdout is the io.Writer to which executed commands write standard output.
func OpenFile
func OpenFile(path string) errorOpenFile opens new browser window for the file path.
func OpenReader
func OpenReader(r io.Reader) errorOpenReader consumes the contents of r and presents the
results in a new browser window.
func OpenURL
func OpenURL(url string) errorOpenURL opens a new browser window pointing to url.
Generated by godoc2md
Overview (`vendor/github.com/prometheus/otlptranslator/README.md`)
OTLP Prometheus Translator
A Go library for converting OpenTelemetry Protocol (OTLP) metric and attribute names to Prometheus-compliant formats. This is an internal library for both Prometheus and Open Telemetry, without any stability guarantees for external usage.
Part of the Prometheus ecosystem, following the OpenTelemetry to Prometheus compatibility specification.
Features
- Metric Name and Label Translation: Convert OTLP metric names and attributes to Prometheus-compliant format
- Unit Handling: Translate OTLP units to Prometheus unit conventions
- Type-Aware Suffixes: Optionally append
_total,_ratiobased on metric type - Namespace Support: Add configurable namespace prefixes
- UTF-8 Support: Choose between Prometheus legacy scheme compliant metric/label names (
[a-zA-Z0-9:_]) or untranslated metric/label names - Translation Strategy Configuration: Select a translation strategy with a standard set of strings.
Installation
go get github.com/prometheus/otlptranslatorQuick Start
package main
import (
"fmt"
"github.com/prometheus/otlptranslator"
)
func main() {
// Create a metric namer using traditional Prometheus name translation, with suffixes added and UTF-8 disallowed.
strategy := otlptranslator.UnderscoreEscapingWithSuffixes
namer := otlptranslator.NewMetricNamer("myapp", strategy)
// Translate OTLP metric to Prometheus format
metric := otlptranslator.Metric{
Name: "http.server.request.duration",
Unit: "s",
Type: otlptranslator.MetricTypeHistogram,
}
fmt.Println(namer.Build(metric)) // Output: myapp_http_server_request_duration_seconds
// Translate label names
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: false}
fmt.Println(labelNamer.Build("http.method")) // Output: http_method
}Usage Examples
Metric Name Translation
namer := otlptranslator.MetricNamer{WithMetricSuffixes: true, UTF8Allowed: false}
// Counter gets _total suffix
counter := otlptranslator.Metric{
Name: "requests.count", Unit: "1", Type: otlptranslator.MetricTypeMonotonicCounter,
}
fmt.Println(namer.Build(counter)) // requests_count_total
// Gauge with unit conversion
gauge := otlptranslator.Metric{
Name: "memory.usage", Unit: "By", Type: otlptranslator.MetricTypeGauge,
}
fmt.Println(namer.Build(gauge)) // memory_usage_bytes
// Dimensionless gauge gets _ratio suffix
ratio := otlptranslator.Metric{
Name: "cpu.utilization", Unit: "1", Type: otlptranslator.MetricTypeGauge,
}
fmt.Println(namer.Build(ratio)) // cpu_utilization_ratioLabel Translation
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: false}
labelNamer.Build("http.method") // http_method
labelNamer.Build("123invalid") // key_123invalid
labelNamer.Build("_private") // key_private
labelNamer.Build("__reserved__") // __reserved__ (preserved)
labelNamer.Build("label@with$symbols") // label_with_symbolsUnit Translation
unitNamer := otlptranslator.UnitNamer{UTF8Allowed: false}
unitNamer.Build("s") // seconds
unitNamer.Build("By") // bytes
unitNamer.Build("requests/s") // requests_per_second
unitNamer.Build("1") // "" (dimensionless)Configuration Options
// Prometheus-compliant mode - supports [a-zA-Z0-9:_]
compliantNamer := otlptranslator.MetricNamer{UTF8Allowed: false, WithMetricSuffixes: true}
// Transparent pass-through mode, aka "NoTranslation"
utf8Namer := otlptranslator.MetricNamer{UTF8Allowed: true, WithMetricSuffixes: false}
utf8Namer = otlptranslator.NewMetricNamer("", otlpTranslator.NoTranslation)
// With namespace and suffixes
productionNamer := otlptranslator.MetricNamer{
Namespace: "myservice",
WithMetricSuffixes: true,
UTF8Allowed: false,
}License
Licensed under the Apache License 2.0 - see the LICENSE file for details.
Overview (`vendor/github.com/prometheus/procfs/README.md`)
procfs
This package provides functions to retrieve system, kernel, and process
metrics from the pseudo-filesystems /proc and /sys.
WARNING: This package is a work in progress. Its API may still break in
backwards-incompatible ways without warnings. Use it at your own risk.
Usage
The procfs library is organized by packages based on whether the gathered data is coming from
/proc, /sys, or both. Each package contains an FS type which represents the path to either /proc,
/sys, or both. For example, cpu statistics are gathered from/proc/stat and are available via the root procfs package. First, the proc filesystem mount
point is initialized, and then the stat information is read.
fs, err := procfs.NewFS("/proc")
stats, err := fs.Stat()Some sub-packages such as blockdevice, require access to both the proc and sys filesystems.
fs, err := blockdevice.NewFS("/proc", "/sys")
stats, err := fs.ProcDiskstats()Package Organization
The packages in this project are organized according to (1) whether the data comes from the /proc or/sys filesystem and (2) the type of information being retrieved. For example, most process information
can be gathered from the functions in the root procfs package. Information about block devices such as disk drives
is available in the blockdevices sub-package.
Building and Testing
The procfs library is intended to be built as part of another application, so there are no distributable binaries.
However, most of the API includes unit tests which can be run with make test.
Updating Test Fixtures
The procfs library includes a set of test fixtures which include many example files from
the /proc and /sys filesystems. These fixtures are included as a ttar file
which is extracted automatically during testing. To add/update the test fixtures, first
ensure the testdata/fixtures directory is up to date by removing the existing directory and then
extracting the ttar file using make testdata/fixtures/.unpacked or just make test.
rm -rf testdata/fixtures
make testNext, make the required changes to the extracted files in the testdata/fixtures directory. When
the changes are complete, run make update_fixtures to create a new fixtures.ttar file
based on the updated fixtures directory. And finally, verify the changes usinggit diff testdata/fixtures.ttar.
Overview (`vendor/github.com/sirupsen/logrus/README.md`)
Logrus [](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [](https://pkg.go.dev/github.com/sirupsen/logrus)
Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger.
Logrus is in maintenance mode. The project focuses on security, bug fixes,
and performance improvements. New features are not planned, aside from changes
required to provide interoperability with other logging ecosystems (e.g., Go's
log/slog).
I believe Logrus' biggest contribution is to have played a part in today's
widespread use of structured logging in Golang. There doesn't seem to be a
reason to do a major, breaking iteration into Logrus V2, since the fantastic Go
community has built those independently. Many fantastic alternatives have sprung
up. Logrus would look like those, had it been re-designed with what we know
about structured logging in Go today. Check out, for example,
Zerolog, Zap, and Apex.
Nicely color-coded in development (when a TTY is attached, otherwise just
plain text):
With logrus.SetFormatter(&logrus.JSONFormatter{}), for easy parsing by logstash
or Splunk:
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
{"level":"warning","msg":"The group's number increased tremendously!","number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"A giant walrus appears!","size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.","size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}With the default logrus.SetFormatter(&logrus.TextFormatter{}) when a TTY is not
attached, the output is compatible with the
logfmt format:
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" animal=orca err="It's over 9000!" number=100 omg=true size=9009To ensure this behaviour even if a TTY is attached, set your formatter as follows:
logrus.SetFormatter(&logrus.TextFormatter{
DisableColors: true,
FullTimestamp: true,
})Logging Method Name
If you wish to add the calling method as a field, instruct the logger via:
logrus.SetReportCaller(true)This adds the caller as 'method' like so:
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by","time":"2014-03-10 19:57:38.562543129 -0400 EDT"}time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguinNote that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
environment via benchmarks:
go test -bench=ReportCallerCase-sensitivity
The organization's name was changed to lower-case. If you are getting import
conflicts due to case sensitivity, please use the lower-case import:github.com/sirupsen/logrus.
Example
The simplest way to use Logrus is simply the package-level exported logger:
package main
import "github.com/sirupsen/logrus"
func main() {
logrus.WithFields(logrus.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}Note that it's completely api-compatible with the stdlib logger, so you can
replace your log imports everywhere with log "github.com/sirupsen/logrus"
and you'll now have the flexibility of Logrus. You can customize it all you
want:
package main
import (
"os"
log "github.com/sirupsen/logrus"
)
func init() {
// Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{})
// Output to stdout instead of the default stderr
// Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above.
log.SetLevel(log.WarnLevel)
}
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
log.WithFields(log.Fields{
"omg": true,
"number": 122,
}).Warn("The group's number increased tremendously!")
log.WithFields(log.Fields{
"omg": true,
"number": 100,
}).Fatal("The ice breaks!")
// A common pattern is to re-use fields between logging statements by re-using
// the logrus.Entry returned from WithFields()
contextLogger := log.WithFields(log.Fields{
"common": "this is a common field",
"other": "I also should be logged always",
})
contextLogger.Info("I'll be logged with common and other field")
contextLogger.Info("Me too")
}For more advanced usage such as logging to multiple locations from the same
application, you can also create an instance of the logrus Logger:
package main
import (
"os"
"github.com/sirupsen/logrus"
)
// Create a new instance of the logger. You can have any number of instances.
var logger = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
logger.Out = os.Stdout
// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err == nil {
// logger.Out = file
// } else {
// logger.Info("Failed to log to file, using default stderr")
// }
logger.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}Fields
Logrus encourages careful, structured logging through logging fields instead of
long, unparseable error messages. For example, instead of: logrus.Fatalf("Failed to send event %s to topic %s with key %d"), you should log the much more
discoverable:
logrus.WithFields(logrus.Fields{
"event": event,
"topic": topic,
"key": key,
}).Fatal("Failed to send event")We've found this API forces you to think about logging in a way that produces
much more useful logging messages. We've been in countless situations where just
a single added field to a log statement that was already there would've saved us
hours. The WithFields call is optional.
In general, with Logrus using any of the printf-family functions should be
seen as a hint you should add a field, however, you can still use theprintf-family functions with Logrus.
Default Fields
Often it's helpful to have fields always attached to log statements in an
application or parts of one. For example, you may want to always log therequest_id and user_ip in the context of a request. Instead of writinglogger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip}) on
every line, you can create a logrus.Entry to pass around instead:
requestLogger := logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip})
requestLogger.Info("something happened on that request") // will log request_id and user_ip
requestLogger.Warn("something not great happened")Hooks
You can add hooks for logging levels. For example to send errors to an exception
tracking service on Error, Fatal and Panic, info to StatsD or log to
multiple places simultaneously, e.g. syslog.
Logrus comes with built-in hooks. Add those, or your custom hook, ininit:
package main
import (
"log/syslog"
"github.com/sirupsen/logrus"
airbrake "gopkg.in/gemnasium/logrus-airbrake-hook.v2"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
)
func init() {
// Use the Airbrake hook to report errors that have Error severity or above to
// an exception tracker. You can create custom hooks, see the Hooks section.
logrus.AddHook(airbrake.NewHook(123, "xyz", "production"))
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err != nil {
logrus.Error("Unable to connect to local syslog daemon")
} else {
logrus.AddHook(hook)
}
}Note: Syslog hooks also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the syslog hook README.
A list of currently known service hooks can be found in this wiki page
Level logging
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
logrus.Trace("Something very low level.")
logrus.Debug("Useful debugging information.")
logrus.Info("Something noteworthy happened!")
logrus.Warn("You should probably take a look at this.")
logrus.Error("Something failed but I'm not quitting.")
// Calls os.Exit(1) after logging
logrus.Fatal("Bye.")
// Calls panic() after logging
logrus.Panic("I'm bailing.")You can set the logging level on a Logger, then it will only log entries with
that severity or anything above it:
// Will log anything that is info or above (warn, error, fatal, panic). Default.
logrus.SetLevel(logrus.InfoLevel)It may be useful to set logrus.Level = logrus.DebugLevel in a debug or verbose
environment if your application has that.
Note: If you want different log levels for global (logrus.SetLevel(...)) and syslog logging, please check the syslog hook README.
Entries
Besides the fields added with WithField or WithFields some fields are
automatically added to all logging events:
time. The timestamp when the entry was created.msg. The logging message passed to{Info,Warn,Error,Fatal,Panic}after
theAddFieldscall. E.g.Failed to send event.level. The logging level. E.g.info.
Environments
Logrus has no notion of environment.
If you wish for hooks and formatters to only be used in specific environments,
you should handle that yourself. For example, if your application has a global
variable Environment, which is a string representation of the environment you
could do:
import (
"github.com/sirupsen/logrus"
)
func init() {
// do something here to set environment depending on an environment variable
// or command-line flag
if Environment == "production" {
logrus.SetFormatter(&logrus.JSONFormatter{})
} else {
// The TextFormatter is default, you don't actually have to do this.
logrus.SetFormatter(&logrus.TextFormatter{})
}
}This configuration is how logrus was intended to be used, but JSON in
production is mostly only useful if you do log aggregation with tools like
Splunk or Logstash.
Formatters
The built-in logging formatters are:
logrus.TextFormatter
logs the event in colors if the logger output is a TTY, otherwise without colors.- To force colored output when there is no TTY, set the
ForceColors
field totrue. To force no colored output even if there is a TTY set theDisableColorsfield totrue. - On modern Windows terminals with ANSI (Virtual Terminal) support, TextFormatter
automatically enables colored output. - If your environment does not support ANSI escape sequences, wrap the logger output
using github.com/mattn/go-colorable
and setForceColors(orCLICOLOR_FORCE=1) to enable colors through the wrapper. - When colors are enabled, levels are truncated to 4 characters by default. To disable
truncation set theDisableLevelTruncationfield totrue. - When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the
PadLevelTextfield totrueenables this behavior, by adding padding to the level text.
- To force colored output when there is no TTY, set the
logrus.JSONFormatter
logs fields as JSON.
Third-party logging formatters:
FluentdFormatter. Formats entries that can be parsed by Kubernetes and Google Container Engine.GELF. Formats entries so they comply to Graylog's GELF 1.1 specification.logstash. Logs fields as Logstash Events.prefixed. Displays log entry source along with alternative layout.zalgo. Invoking the Power of Zalgo.nested-logrus-formatter. Converts logrus fields to a nested structure.powerful-logrus-formatter. get fileName, log's line number and the latest function's name when print log; Save log to files.caption-json-formatter. logrus's message json formatter with human-readable caption added.easy-logrus-formatter. Provide a user-friendly formatter for logrus.redactrus. Redacts sensitive information like password, apikeys, email, etc. from logs.
You can define your formatter by implementing the Formatter interface,
requiring a Format method. Format takes an *Entry. entry.Data is aFields type (map[string]any) with all your fields as well as the
default ones (see Entries section above):
type MyJSONFormatter struct{}
logrus.SetFormatter(new(MyJSONFormatter))
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
// Note this doesn't include Time, Level and Message which are available on
// the Entry. Consult `godoc` on information about those fields or read the
// source of the official loggers.
serialized, err := json.Marshal(entry.Data)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %w", err)
}
return append(serialized, '\n'), nil
}Logger as an `io.Writer`
Logrus can be transformed into an io.Writer. That writer is the end of an io.Pipe and it is your responsibility to close it.
w := logger.Writer()
defer w.Close()
srv := http.Server{
// create a stdlib log.Logger that writes to
// logrus.Logger.
ErrorLog: log.New(w, "", 0),
}Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is info.
This means that we can override the standard library logger easily:
logger := logrus.New()
logger.Formatter = &logrus.JSONFormatter{}
// Use logrus for standard log output
// Note that `log` here references stdlib's log
// Not logrus imported under the name `log`.
log.SetOutput(logger.Writer())Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an
external program (like logrotate(8)) that can compress and delete old log
entries. It should not be a feature of the application-level logger.
Tools
| Tool | Description |
|---|---|
| Logrus Mate | Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments. |
| Logrus Viper Helper | An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of Logrus Mate. sample |
Testing
Logrus has a built-in facility for asserting the presence of log messages. This is implemented through the test hook and provides:
- decorators for existing logger (
test.NewLocalandtest.NewGlobal) which basically just adds thetesthook - a test logger (
test.NewNullLogger) that just records log messages (and does not output any):
import(
"testing"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
)
func TestSomething(t*testing.T){
logger, hook := test.NewNullLogger()
logger.Error("Helloerror")
assert.Equal(t, 1, len(hook.Entries))
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
hook.Reset()
assert.Nil(t, hook.LastEntry())
}Fatal handlers
Logrus can register one or more functions that will be called when any fatal
level message is logged. The registered handlers will be executed before
logrus performs an os.Exit(1). This behavior may be helpful if callers need
to gracefully shut down. Unlike a panic("Something went wrong...") call which can be intercepted with a deferred recover a call to os.Exit(1) can not be intercepted.
// ...
handler := func() {
// gracefully shut down something...
}
logrus.RegisterExitHandler(handler)
// ...Thread safety
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
Situations when locking is not needed include:
You have no hooks registered, or hooks calling is already thread-safe.
Writing to logger.Out is already thread-safe, for example:
logger.Out is protected by locks.
logger.Out is an os.File handler opened with
O_APPENDflag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
Overview (`vendor/github.com/spf13/cobra/README.md`)
Cobra is a library for creating powerful modern CLI applications.
Visit Cobra.dev for extensive documentation
Cobra is used in many Go projects such as Kubernetes,
Hugo, and GitHub CLI to
name a few. This list contains a more extensive list of projects using Cobra.
Overview
Cobra is a library providing a simple interface to create powerful modern CLI
interfaces similar to git & go tools.
Cobra provides:
- Easy subcommand-based CLIs:
app server,app fetch, etc. - Fully POSIX-compliant flags (including short & long versions)
- Nested subcommands
- Global, local and cascading flags
- Intelligent suggestions (
app srver... did you meanapp server?) - Automatic help generation for commands and flags
- Grouping help for subcommands
- Automatic help flag recognition of
-h,--help, etc. - Automatically generated shell autocomplete for your application (bash, zsh, fish, powershell)
- Automatically generated man pages for your application
- Command aliases so you can change things without breaking them
- The flexibility to define your own help, usage, etc.
- Optional seamless integration with viper for 12-factor apps
Concepts
Cobra is built on a structure of commands, arguments & flags.
Commands represent actions, Args are things and Flags are modifiers for those actions.
The best applications read like sentences when used, and as a result, users
intuitively know how to interact with them.
The pattern to follow isAPPNAME VERB NOUN --ADJECTIVE
orAPPNAME COMMAND ARG --FLAG.
A few good real world examples may better illustrate this point.
In the following example, 'server' is a command, and 'port' is a flag:
hugo server --port=1313In this command we are telling Git to clone the url bare.
git clone URL --bareCommands
Command is the central point of the application. Each interaction that
the application supports will be contained in a Command. A command can
have children commands and optionally run an action.
In the example above, 'server' is the command.
Flags
A flag is a way to modify the behavior of a command. Cobra supports
fully POSIX-compliant flags as well as the Go flag package.
A Cobra command can define flags that persist through to children commands
and flags that are only available to that command.
In the example above, 'port' is the flag.
Flag functionality is provided by the pflag
library, a fork of the flag standard library
which maintains the same interface while adding POSIX compliance.
Installing
Using Cobra is easy. First, use go get to install the latest version
of the library.
go get -u github.com/spf13/cobra@latestNext, include Cobra in your application:
import "github.com/spf13/cobra"Usage
cobra-cli is a command line program to generate cobra applications and command files.
It will bootstrap your application scaffolding to rapidly
develop a Cobra-based application. It is the easiest way to incorporate Cobra into your application.
It can be installed by running:
go install github.com/spf13/cobra-cli@latestFor complete details on using the Cobra-CLI generator, please read The Cobra Generator README
For complete details on using the Cobra library, please read The Cobra User Guide.
License
Cobra is released under the Apache 2.0 license. See LICENSE.txt
Overview (`vendor/github.com/spf13/pflag/README.md`)
Description
pflag is a drop-in replacement for Go's flag package, implementing
POSIX/GNU-style --flags.
pflag is compatible with the GNU extensions to the POSIX recommendations
for command-line options. For a more precise description, see the
"Command-line flag syntax" section below.
pflag is available under the same style of BSD license as the Go language,
which can be found in the LICENSE file.
Installation
pflag is available using the standard go get command.
Install by running:
go get github.com/spf13/pflagRun tests by running:
go test github.com/spf13/pflagUsage
pflag is a drop-in replacement of Go's native flag package. If you import
pflag under the name "flag" then all code should continue to function
with no changes.
import flag "github.com/spf13/pflag"There is one exception to this: if you directly instantiate the Flag struct
there is one more field "Shorthand" that you will need to set.
Most code never instantiates this struct directly, and instead uses
functions such as String(), BoolVar(), and Var(), and is therefore
unaffected.
Define flags using flag.String(), Bool(), Int(), etc.
This declares an integer flag, -flagname, stored in the pointer ip, with type *int.
var ip *int = flag.Int("flagname", 1234, "help message for flagname")If you like, you can bind the flag to a variable using the Var() functions.
var flagvar int
func init() {
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
}Or you can create custom flags that satisfy the Value interface (with
pointer receivers) and couple them to flag parsing by
flag.Var(&flagVal, "name", "help message for flagname")For such flags, the default value is just the initial value of the variable.
After all flags are defined, call
flag.Parse()to parse the command line into the defined flags.
Flags may then be used directly. If you're using the flags themselves,
they are all pointers; if you bind to variables, they're values.
fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar)There are helper functions available to get the value stored in a Flag if you have a FlagSet but find
it difficult to keep up with all of the pointers in your code.
If you have a pflag.FlagSet with a flag called 'flagname' of type int you
can use GetInt() to get the int value. But notice that 'flagname' must exist
and it must be an int. GetString("flagname") will fail.
i, err := flagset.GetInt("flagname")After parsing, the arguments after the flag are available as the
slice flag.Args() or individually as flag.Arg(i).
The arguments are indexed from 0 through flag.NArg()-1.
The pflag package also defines some new functions that are not in flag,
that give one-letter shorthands for flags. You can use these by appending
'P' to the name of any function that defines a flag.
var ip = flag.IntP("flagname", "f", 1234, "help message")
var flagvar bool
func init() {
flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
}
flag.VarP(&flagVal, "varname", "v", "help message")Shorthand letters can be used with single dashes on the command line.
Boolean shorthand flags can be combined with other shorthand flags.
The default set of command-line flags is controlled by
top-level functions. The FlagSet type allows one to define
independent sets of flags, such as to implement subcommands
in a command-line interface. The methods of FlagSet are
analogous to the top-level functions for the command-line
flag set.
Setting no option default values for flags
After you create a flag it is possible to set the pflag.NoOptDefVal for
the given flag. Doing this changes the meaning of the flag slightly. If
a flag has a NoOptDefVal and the flag is set on the command line without
an option the flag will be set to the NoOptDefVal. For example given:
var ip = flag.IntP("flagname", "f", 1234, "help message")
flag.Lookup("flagname").NoOptDefVal = "4321"Would result in something like
| Parsed Arguments | Resulting Value |
|---|---|
| --flagname=1357 | ip=1357 |
| --flagname | ip=4321 |
| [nothing] | ip=1234 |
Command line flag syntax
--flag // boolean flags, or flags with no option default values
--flag x // only on flags without a default value
--flag=xUnlike the flag package, a single dash before an option means something
different than a double dash. Single dashes signify a series of shorthand
letters for flags. All but the last shorthand letter must be boolean flags
or a flag with a default value
// boolean or flags where the 'no option default value' is set
-f
-f=true
-abc
but
-b true is INVALID
// non-boolean and flags without a 'no option default value'
-n 1234
-n=1234
-n1234
// mixed
-abcs "hello"
-absd="hello"
-abcs1234Flag parsing stops after the terminator "--". Unlike the flag package,
flags can be interspersed with arguments anywhere on the command line
before this terminator.
Integer flags accept 1234, 0664, 0x1234 and may be negative.
Boolean flags (in their long form) accept 1, 0, t, f, true, false,
TRUE, FALSE, True, False.
Duration flags accept any input valid for time.ParseDuration.
Mutating or "Normalizing" Flag names
It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow.
Example #1: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag
func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
from := []string{"-", "_"}
to := "."
for _, sep := range from {
name = strings.Replace(name, sep, to, -1)
}
return pflag.NormalizedName(name)
}
myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc)Example #2: You want to alias two flags. aka --old-flag-name == --new-flag-name
func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName {
switch name {
case "old-flag-name":
name = "new-flag-name"
break
}
return pflag.NormalizedName(name)
}
myFlagSet.SetNormalizeFunc(aliasNormalizeFunc)Deprecating a flag or its shorthand
It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used.
Example #1: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead.
// deprecate a flag by specifying its name and a usage message
flags.MarkDeprecated("badflag", "please use --good-flag instead")This hides "badflag" from help text, and prints Flag --badflag has been deprecated, please use --good-flag instead when "badflag" is used.
Example #2: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n".
// deprecate a flag shorthand by specifying its flag name and a usage message
flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only")This hides the shortname "n" from help text, and prints Flag shorthand -n has been deprecated, please use --noshorthandflag only when the shorthand "n" is used.
Note that usage message is essential here, and it should not be empty.
Hidden flags
It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text.
Example: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available.
// hide a flag by specifying its name
flags.MarkHidden("secretFlag")Disable sorting of flags
pflag allows you to disable sorting of flags for help and usage message.
Example:
flags.BoolP("verbose", "v", false, "verbose output")
flags.String("coolflag", "yeaah", "it's really cool flag")
flags.Int("usefulflag", 777, "sometimes it's very useful")
flags.SortFlags = false
flags.PrintDefaults()Output:
-v, --verbose verbose output
--coolflag string it's really cool flag (default "yeaah")
--usefulflag int sometimes it's very useful (default 777)Supporting Go flags when using pflag
In order to support flags defined using Go's flag package, they must be added to the pflag flagset. This is usually necessary
to support flags defined by third-party dependencies (e.g. golang/glog).
Example: You want to add the Go flags to the CommandLine flagset
import (
goflag "flag"
flag "github.com/spf13/pflag"
)
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
func main() {
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
flag.Parse()
}Using pflag with go test
pflag does not parse the shorthand versions of go test's built-in flags (i.e., those starting with -test.).
For more context, see issues #63 and #238 for more details.
For example, if you use pflag in your TestMain function and call pflag.Parse() after defining your custom flags, running a test like this:
go test /your/tests -run ^YourTest -v --your-test-pflagswill result in the -v flag being ignored. This happens because of the way pflag handles flag parsing, skipping over go test's built-in shorthand flags.
To work around this, you can use the ParseSkippedFlags function, which ensures that go test's flags are parsed separately using the standard flag package.
Example: You want to parse go test flags that are otherwise ignore by pflag.Parse()
import (
goflag "flag"
flag "github.com/spf13/pflag"
)
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
func main() {
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
flag.ParseSkippedFlags(os.Args[1:], goflag.CommandLine)
flag.Parse()
}More info
You can see the full reference documentation of the pflag package
at godoc.org, or through go's standard documentation system by
running godoc -http=:6060 and browsing to
http://localhost:6060/pkg/github.com/spf13/pflag after
installation.
Overview (`vendor/go.opentelemetry.io/otel/attribute/README.md`)
Attribute
Overview (`vendor/go.opentelemetry.io/otel/baggage/README.md`)
Baggage
Overview (`vendor/go.opentelemetry.io/otel/codes/README.md`)
Codes
Overview (`vendor/go.opentelemetry.io/otel/log/README.md`)
Log API
Overview (`vendor/go.opentelemetry.io/otel/metric/README.md`)
Metric API
Overview (`vendor/go.opentelemetry.io/otel/propagation/README.md`)
Propagation
Overview (`vendor/go.opentelemetry.io/otel/sdk/README.md`)
SDK
Overview (`vendor/go.opentelemetry.io/otel/trace/README.md`)
Trace API
Overview (`vendor/go.yaml.in/yaml/v2/README.md`)
YAML support for the Go language
Introduction
The yaml package enables Go programs to comfortably encode and decode YAML
values. It was developed within Canonical as
part of the juju project, and is based on a
pure Go port of the well-known libyaml
C library to parse and generate YAML data quickly and reliably.
Compatibility
The yaml package supports most of YAML 1.1 and 1.2, including support for
anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
implemented, and base-60 floats from YAML 1.1 are purposefully not
supported since they're a poor design and are gone in YAML 1.2.
Installation and usage
The import path for the package is go.yaml.in/yaml/v2.
To install it, run:
go get go.yaml.in/yaml/v2API documentation
See: https://pkg.go.dev/go.yaml.in/yaml/v2
API stability
The package API for yaml v2 will remain stable as described in gopkg.in.
License
The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.
Example
package main
import (
"fmt"
"log"
"go.yaml.in/yaml/v2"
)
var data = `
a: Easy!
b:
c: 2
d: [3, 4]
`
// Note: struct fields must be public in order for unmarshal to
// correctly populate the data.
type T struct {
A string
B struct {
RenamedC int `yaml:"c"`
D []int `yaml:",flow"`
}
}
func main() {
t := T{}
err := yaml.Unmarshal([]byte(data), &t)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- t:\n%v\n\n", t)
d, err := yaml.Marshal(&t)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- t dump:\n%s\n\n", string(d))
m := make(map[interface{}]interface{})
err = yaml.Unmarshal([]byte(data), &m)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- m:\n%v\n\n", m)
d, err = yaml.Marshal(&m)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- m dump:\n%s\n\n", string(d))
}This example will generate the following output:
--- t:
{Easy! {2 [3 4]}}
--- t dump:
a: Easy!
b:
c: 2
d: [3, 4]
--- m:
map[a:Easy! b:map[c:2 d:[3 4]]]
--- m dump:
a: Easy!
b:
c: 2
d:
- 3
- 4Overview (`vendor/go.yaml.in/yaml/v3/README.md`)
go.yaml.in/yaml
YAML Support for the Go Language
Introduction
The yaml package enables Go programs to comfortably encode
and decode YAML values.
It was originally developed within Canonical as
part of the juju project, and is based on a pure Go
port of the well-known libyaml C library to
parse and generate YAML data quickly and reliably.
Project Status
This project started as a fork of the extremely popular go-yaml
project, and is being maintained by the official YAML organization.
The YAML team took over ongoing maintenance and development of the project after
discussion with go-yaml's author, @niemeyer, following his decision to
label the project repository as "unmaintained" in April 2025.
We have put together a team of dedicated maintainers including representatives
of go-yaml's most important downstream projects.
We will strive to earn the trust of the various go-yaml forks to switch back to
this repository as their upstream.
Please contact us if you
would like to contribute or be involved.
Compatibility
The yaml package supports most of YAML 1.2, but preserves some behavior from
1.1 for backwards compatibility.
Specifically, v3 of the yaml package:
- Supports YAML 1.1 bools (
yes/no,on/off) as long as they are being
decoded into a typed bool value.
Otherwise they behave as a string.
Booleans in YAML 1.2 aretrue/falseonly. - Supports octals encoded and decoded as
0777per YAML 1.1, rather than0o777as specified in YAML 1.2, because most parsers still use the old
format.
Octals in the0o777format are supported though, so new files work. - Does not support base-60 floats.
These are gone from YAML 1.2, and were actually never supported by this
package as it's clearly a poor choice.
Installation and Usage
The import path for the package is go.yaml.in/yaml/v3.
To install it, run:
go get go.yaml.in/yaml/v3API Documentation
See: https://pkg.go.dev/go.yaml.in/yaml/v3
API Stability
The package API for yaml v3 will remain stable as described in gopkg.in.
Example
package main
import (
"fmt"
"log"
"go.yaml.in/yaml/v3"
)
var data = `
a: Easy!
b:
c: 2
d: [3, 4]
`
// Note: struct fields must be public in order for unmarshal to
// correctly populate the data.
type T struct {
A string
B struct {
RenamedC int `yaml:"c"`
D []int `yaml:",flow"`
}
}
func main() {
t := T{}
err := yaml.Unmarshal([]byte(data), &t)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- t:\n%v\n\n", t)
d, err := yaml.Marshal(&t)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- t dump:\n%s\n\n", string(d))
m := make(map[interface{}]interface{})
err = yaml.Unmarshal([]byte(data), &m)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- m:\n%v\n\n", m)
d, err = yaml.Marshal(&m)
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("--- m dump:\n%s\n\n", string(d))
}This example will generate the following output:
--- t:
{Easy! {2 [3 4]}}
--- t dump:
a: Easy!
b:
c: 2
d: [3, 4]
--- m:
map[a:Easy! b:map[c:2 d:[3 4]]]
--- m dump:
a: Easy!
b:
c: 2
d:
- 3
- 4License
The yaml package is licensed under the MIT and Apache License 2.0 licenses.
Please see the LICENSE file for details.
Overview (`vendor/golang.org/x/oauth2/README.md`)
OAuth2 for Go
oauth2 package contains a client implementation for OAuth 2.0 spec.
See pkg.go.dev for further documentation and examples.
Policy for new endpoints
We no longer accept new provider-specific packages in this repo if all
they do is add a single endpoint variable. If you just want to add a
single endpoint, add it to the
pkg.go.dev/golang.org/x/oauth2/endpoints
package.
Report Issues / Send Patches
The main issue tracker for the oauth2 repository is located at
https://github.com/golang/oauth2/issues.
This repository uses Gerrit for code changes. To learn how to submit changes to
this repository, see https://go.dev/doc/contribute.
The git repository is https://go.googlesource.com/oauth2.
Note:
- Excluding trivial changes, all contributions should be connected to an existing issue.
- API changes must go through the change proposal process before they can be accepted.
- The code owners are listed at dev.golang.org/owners.
Overview (`vendor/cloud.google.com/go/compute/metadata/README.md`)
Compute API
This is a utility library for communicating with Google Cloud metadata service
on Google Cloud.
Install
go get cloud.google.com/go/compute/metadataGo Version Support
See the Go Versions Supported
section in the root directory's README.
Contributing
Contributions are welcome. Please, see the CONTRIBUTING
document for details.
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms. See
Contributor Code of Conduct
for more information.
Overview (`vendor/github.com/alicebob/miniredis/v2/README.md`)
Miniredis
Pure Go Redis test server, used in Go unittests.
Sometimes you want to test code which uses Redis, without making it a full-blown
integration test.
Miniredis implements (parts of) the Redis server, to be used in unittests. It
enables a simple, cheap, in-memory, Redis replacement, with a real TCP interface. Think of it as the Redis version of net/http/httptest.
It saves you from using mock code, and since the redis server lives in the
test process you can query for values directly, without going through the server
stack.
There are no dependencies on external binaries, so you can easily integrate it in automated build processes.
Be sure to import v2:
import "github.com/alicebob/miniredis/v2"Commands
Implemented commands:
- Connection (complete)
- AUTH -- see RequireAuth()
- ECHO
- HELLO -- see RequireUserAuth()
- PING
- SELECT
- SWAPDB
- QUIT
- Key
- COPY
- DEL
- EXISTS
- EXPIRE
- EXPIREAT
- EXPIRETIME
- KEYS
- MOVE
- PERSIST
- PEXPIRE
- PEXPIREAT
- PEXPIRETIME
- PTTL
- RANDOMKEY -- see m.Seed(...)
- RENAME
- RENAMENX
- SCAN
- TOUCH
- TTL
- TYPE
- UNLINK
- Transactions (complete)
- DISCARD
- EXEC
- MULTI
- UNWATCH
- WATCH
- Server
- DBSIZE
- FLUSHALL
- FLUSHDB
- TIME -- returns time.Now() or value set by SetTime()
- COMMAND -- partly
- INFO -- partly, returns only "clients" section with one field "connected_clients"
- String keys (complete)
- APPEND
- BITCOUNT
- BITOP
- BITPOS
- DECR
- DECRBY
- GET
- GETBIT
- GETRANGE
- GETSET
- GETDEL
- GETEX
- INCR
- INCRBY
- INCRBYFLOAT
- MGET
- MSET
- MSETNX
- PSETEX
- SET
- SETBIT
- SETEX
- SETNX
- SETRANGE
- STRLEN
- Hash keys (complete)
- HDEL
- HEXISTS
- HGET
- HGETALL
- HINCRBY
- HINCRBYFLOAT
- HKEYS
- HLEN
- HMGET
- HMSET
- HRANDFIELD
- HSET
- HSETNX
- HSTRLEN
- HVALS
- HSCAN
- List keys (complete)
- BLPOP
- BRPOP
- BRPOPLPUSH
- LINDEX
- LINSERT
- LLEN
- LPOP
- LPUSH
- LPUSHX
- LRANGE
- LREM
- LSET
- LTRIM
- RPOP
- RPOPLPUSH
- RPUSH
- RPUSHX
- LMOVE
- BLMOVE
- Pub/Sub (complete)
- PSUBSCRIBE
- PUBLISH
- PUBSUB
- PUNSUBSCRIBE
- SUBSCRIBE
- UNSUBSCRIBE
- Set keys (complete)
- SADD
- SCARD
- SDIFF
- SDIFFSTORE
- SINTER
- SINTERSTORE
- SINTERCARD
- SISMEMBER
- SMEMBERS
- SMISMEMBER
- SMOVE
- SPOP -- see m.Seed(...)
- SRANDMEMBER -- see m.Seed(...)
- SREM
- SSCAN
- SUNION
- SUNIONSTORE
- Sorted Set keys (complete)
- ZADD
- ZCARD
- ZCOUNT
- ZINCRBY
- ZINTER
- ZINTERSTORE
- ZLEXCOUNT
- ZPOPMIN
- ZPOPMAX
- ZRANDMEMBER
- ZRANGE
- ZRANGEBYLEX
- ZRANGEBYSCORE
- ZRANK
- ZREM
- ZREMRANGEBYLEX
- ZREMRANGEBYRANK
- ZREMRANGEBYSCORE
- ZREVRANGE
- ZREVRANGEBYLEX
- ZREVRANGEBYSCORE
- ZREVRANK
- ZSCORE
- ZUNION
- ZUNIONSTORE
- ZSCAN
- Stream keys
- XACK
- XADD
- XAUTOCLAIM
- XCLAIM
- XDEL
- XGROUP CREATE
- XGROUP CREATECONSUMER
- XGROUP DESTROY
- XGROUP DELCONSUMER
- XINFO STREAM -- partly
- XINFO GROUPS
- XINFO CONSUMERS -- partly
- XLEN
- XRANGE
- XREAD
- XREADGROUP
- XREVRANGE
- XPENDING
- XTRIM
- Scripting
- EVAL
- EVALSHA
- SCRIPT LOAD
- SCRIPT EXISTS
- SCRIPT FLUSH
- GEO
- GEOADD
- GEODIST
GEOHASH- GEOPOS
- GEORADIUS
- GEORADIUS_RO
- GEORADIUSBYMEMBER
- GEORADIUSBYMEMBER_RO
- Cluster
- CLUSTER SLOTS
- CLUSTER KEYSLOT
- CLUSTER NODES
- HyperLogLog (complete)
- PFADD
- PFCOUNT
- PFMERGE
TTLs, key expiration, and time
Since miniredis is intended to be used in unittests TTLs don't decrease
automatically. You can use TTL() to get the TTL (as a time.Duration) of a
key. It will return 0 when no TTL is set.
m.FastForward(d) can be used to decrement all TTLs. All TTLs which become <=
0 will be removed.
EXPIREAT and PEXPIREAT values will be
converted to a duration. For that you can either set m.SetTime(t) to use that
time as the base for the (P)EXPIREAT conversion, or don't call SetTime(), in
which case time.Now() will be used.
SetTime() also sets the value returned by TIME, which defaults to time.Now().
It is not updated by FastForward, only by SetTime.
Randomness and Seed()
Miniredis will use math/rand's global RNG for randomness unless a seed is
provided by calling m.Seed(...). If a seed is provided, then miniredis will
use its own RNG based on that seed.
Commands which use randomness are: RANDOMKEY, SPOP, and SRANDMEMBER.
Example
import (
...
"github.com/alicebob/miniredis/v2"
...
)
func TestSomething(t *testing.T) {
s := miniredis.RunT(t)
// Optionally set some keys your code expects:
s.Set("foo", "bar")
s.HSet("some", "other", "key")
// Run your code and see if it behaves.
// An example using the redigo library from "github.com/gomodule/redigo/redis":
c, err := redis.Dial("tcp", s.Addr())
_, err = c.Do("SET", "foo", "bar")
// Optionally check values in redis...
if got, err := s.Get("foo"); err != nil || got != "bar" {
t.Error("'foo' has the wrong value")
}
// ... or use a helper for that:
s.CheckGet(t, "foo", "bar")
// TTL and expiration:
s.Set("foo", "bar")
s.SetTTL("foo", 10*time.Second)
s.FastForward(11 * time.Second)
if s.Exists("foo") {
t.Fatal("'foo' should not have existed anymore")
}
}Not supported
Commands which will probably not be implemented:
- CLUSTER (all)
CLUSTER *READONLYREADWRITE
- Key
DUMPMIGRATEOBJECTRESTOREWAIT
- Scripting
FCALL / FCALL_RO *FUNCTION *SCRIPT DEBUGSCRIPT KILL
- Server
BGSAVEBGWRITEAOFCLIENT *CONFIG *DEBUG *LASTSAVEMONITORROLESAVESHUTDOWNSLAVEOFSLOWLOGSYNC
&c.
Integration tests are run against Redis 7.2.4. The ./integration subdir
compares miniredis against a real redis instance.
The Redis 6 RESP3 protocol is supported. If there are problems, please open
an issue.
If you want to test Redis Sentinel have a look at minisentinel.
A changelog is kept at CHANGELOG.md.
Overview (`vendor/github.com/cenkalti/backoff/v5/README.md`)
Exponential Backoff [![GoDoc][godoc image]][godoc]
This is a Go port of the exponential backoff algorithm from Google's HTTP Client Library for Java.
Exponential backoff
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
in order to gradually find an acceptable rate.
The retries exponentially increase and stop increasing when a certain threshold is met.
Usage
Import path is github.com/cenkalti/backoff/v5. Please note the version part at the end.
For most cases, use Retry function. See example_test.go for an example.
If you have specific needs, copy Retry function (from retry.go) into your code and modify it as needed.
Contributing
- I would like to keep this library as small as possible.
- Please don't send a PR without opening an issue and discussing it first.
- If proposed change is not a common use case, I will probably not accept it.
Overview (`vendor/github.com/cespare/xxhash/v2/README.md`)
xxhash
xxhash is a Go implementation of the 64-bit xxHash algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.
This package provides a straightforward API:
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
func New() *DigestThe Digest type implements hash.Hash64. Its key methods are:
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64The package is written with optimized pure Go and also contains even faster
assembly implementations for amd64 and arm64. If desired, the purego build tag
opts into using the Go code even on those architectures.
Compatibility
This package is in a module and the latest code is in version 2 of the module.
You need a version of Go with at least "minimal module compatibility" to use
github.com/cespare/xxhash/v2:
- 1.9.7+ for Go 1.9
- 1.10.3+ for Go 1.10
- Go 1.11 or later
I recommend using the latest release of Go.
Benchmarks
Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.
| input size | purego | asm |
|---|---|---|
| 4 B | 1.3 GB/s | 1.2 GB/s |
| 16 B | 2.9 GB/s | 3.5 GB/s |
| 100 B | 6.9 GB/s | 8.1 GB/s |
| 4 KB | 11.7 GB/s | 16.7 GB/s |
| 10 MB | 12.0 GB/s | 17.3 GB/s |
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
CPU using the following commands under Go 1.19.2:
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')Projects using this package
Overview (`vendor/github.com/go-jose/go-jose/v4/README.md`)
Go JOSE
Package jose aims to provide an implementation of the Javascript Object Signing
and Encryption set of standards. This includes support for JSON Web Encryption,
JSON Web Signature, and JSON Web Token standards.
Overview
The implementation follows the
JSON Web Encryption (RFC 7516),
JSON Web Signature (RFC 7515), and
JSON Web Token (RFC 7519) specifications.
Tables of supported algorithms are shown below. The library supports both
the compact and JWS/JWE JSON Serialization formats, and has optional support for
multiple recipients. It also comes with a small command-line utility
(jose-util)
for dealing with JOSE messages in a shell.
Note: We use a forked version of the encoding/json package from the Go
standard library which uses case-sensitive matching for member names (instead
of case-insensitive matching).
This is to avoid differences in interpretation of messages between go-jose and
libraries in other languages.
Versions
The forthcoming Version 5 will be released with several breaking API changes,
and will require Golang's encoding/json/v2, which is currently requires
Go 1.25 built with GOEXPERIMENT=jsonv2.
Version 4 is the current stable version:
import "github.com/go-jose/go-jose/v4"It supports at least the current and previous Golang release. Currently it
requires Golang 1.24.
Version 3 is only receiving critical security updates. Migration to Version 4 is recommended.
Versions 1 and 2 are obsolete, but can be found in the old repository, square/go-jose.
Supported algorithms
See below for a table of supported algorithms. Algorithm identifiers match
the names in the JSON Web Algorithms
standard where possible. The Godoc reference has a list of constants.
| Key encryption | Algorithm identifier(s) |
|---|---|
| RSA-PKCS#1v1.5 | RSA1_5 |
| RSA-OAEP | RSA-OAEP, RSA-OAEP-256 |
| AES key wrap | A128KW, A192KW, A256KW |
| AES-GCM key wrap | A128GCMKW, A192GCMKW, A256GCMKW |
| ECDH-ES + AES key wrap | ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW |
| ECDH-ES (direct) | ECDH-ES1 |
| Direct encryption | dir1 |
1. Not supported in multi-recipient mode
| Signing / MAC | Algorithm identifier(s) |
|---|---|
| RSASSA-PKCS#1v1.5 | RS256, RS384, RS512 |
| RSASSA-PSS | PS256, PS384, PS512 |
| HMAC | HS256, HS384, HS512 |
| ECDSA | ES256, ES384, ES512 |
| Ed25519 | EdDSA2 |
2. Only available in version 2 of the package
| Content encryption | Algorithm identifier(s) |
|---|---|
| AES-CBC+HMAC | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 |
| AES-GCM | A128GCM, A192GCM, A256GCM |
| Compression | Algorithm identifiers(s) |
|---|---|
| DEFLATE (RFC 1951) | DEF |
Supported key types
See below for a table of supported key types. These are understood by the
library, and can be passed to corresponding functions such as NewEncrypter orNewSigner. Each of these keys can also be wrapped in a JWK if desired, which
allows attaching a key id.
| Algorithm(s) | Corresponding types |
|---|---|
| RSA | *rsa.PublicKey, *rsa.PrivateKey |
| ECDH, ECDSA | *ecdsa.PublicKey, *ecdsa.PrivateKey |
| EdDSA1 | ed25519.PublicKey, ed25519.PrivateKey |
| AES, HMAC | []byte |
1. Only available in version 2 or later of the package
Examples
Examples can be found in the Godoc
reference for this package. Thejose-util
subdirectory also contains a small command-line utility which might be useful
as an example as well.
Overview (`vendor/github.com/golang-jwt/jwt/v5/README.md`)
jwt-go
A go (or 'golang' for search engine friendliness)
implementation of JSON Web
Tokens.
Starting with v4.0.0
this project adds Go module support, but maintains backward compatibility with
older v3.x.y tags and upstream github.com/dgrijalva/jwt-go. See theMIGRATION_GUIDE.md for more information. Version
v5.0.0 introduces major improvements to the validation of tokens, but is not
entirely backward compatible.
After the original author of the library suggested migrating the maintenance
ofjwt-go, a dedicated team of open source maintainers decided to clone the
existing library into this repository. See
dgrijalva/jwt-go#462 for a
detailed discussion on this topic.
SECURITY NOTICE: Some older versions of Go have a security issue in the
crypto/elliptic. The recommendation is to upgrade to at least 1.15 See issue
dgrijalva/jwt-go#216 for more
detail.
SECURITY NOTICE: It's important that you validate the alg presented is
what you
expect.
This library attempts to make it easy to do the right thing by requiring key
types to match the expected alg, but you should take the extra step to verify it in
your usage. See the examples provided.
Supported Go versions
Our support of Go versions is aligned with Go's version release
policy. So we will support a major
version of Go until there are two newer major releases. We no longer support
building jwt-go with unsupported Go versions, as these contain security
vulnerabilities that will not be fixed.
What the heck is a JWT?
JWT.io has a great introduction to JSON Web
Tokens.
In short, it's a signed JSON object that does something useful (for example,
authentication). It's commonly used for Bearer tokens in Oauth 2. A token is
made of three parts, separated by .'s. The first two parts are JSON objects,
that have been base64url
encoded. The last part is the signature, encoded the same way.
The first part is called the header. It contains the necessary information for
verifying the last part, the signature. For example, which encryption method
was used for signing and what key was used.
The part in the middle is the interesting bit. It's called the Claims and
contains the actual stuff you care about. Refer to RFC
7519 for information about
reserved keys and the proper way to add your own.
What's in the box?
This library supports the parsing and verification as well as the generation and
signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA,
RSA-PSS, and ECDSA, though hooks are present for adding your own.
Installation Guidelines
- To install the jwt package, you first need to have
Go installed, then you can use the command
below to addjwt-goas a dependency in your Go program.
go get -u github.com/golang-jwt/jwt/v5- Import it in your code:
import "github.com/golang-jwt/jwt/v5"Usage
A detailed usage guide, including how to sign and verify tokens can be found on
our documentation website.
Examples
See the project documentation
for examples of usage:
- Simple example of parsing and validating a
token - Simple example of building and signing a
token - Directory of
Examples
Compliance
This library was last reviewed to comply with RFC
7519 dated May 2015 with a few
notable differences:
- In order to protect against accidental use of Unsecured
JWTs, tokens usingalg=nonewill only be accepted if the constantjwt.UnsafeAllowNoneSignatureTypeis provided as the key.
Project Status & Versioning
This library is considered production ready. Feedback and feature requests are
appreciated. The API should be considered stable. There should be very few
backward-incompatible changes outside of major version updates (and only with
good reason).
This project uses Semantic Versioning 2.0.0. Accepted pull
requests will land on main. Periodically, versions will be tagged frommain. You can find all the releases on the project releases
page.
BREAKING CHANGES: A full list of breaking changes is available inVERSION_HISTORY.md. See MIGRATION_GUIDE.md for more information on updating
your code.
Extensions
This library publishes all the necessary components for adding your own signing
methods or key functions. Simply implement the SigningMethod interface and
register a factory method using RegisterSigningMethod or provide ajwt.Keyfunc.
A common use case would be integrating with different 3rd party signature
providers, like key management services from various cloud providers or Hardware
Security Modules (HSMs) or to implement additional standards.
| Extension | Purpose | Repo |
|---|---|---|
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
| JWKS | Provides support for JWKS (RFC 7517) as a jwt.Keyfunc |
https://github.com/MicahParks/keyfunc |
Disclaimer: Unless otherwise specified, these integrations are maintained by
third parties and should not be considered as a primary offer by any of the
mentioned cloud providers
More
Go package documentation can be found on
pkg.go.dev. Additional
documentation can be found on our project
page.
The command line utility included in this project (cmd/jwt) provides a
straightforward example of token creation and parsing as well as a useful tool
for debugging your own integration. You'll also find several implementation
examples in the documentation.
golang-jwt incorporates a modified version
of the JWT logo, which is distributed under the terms of the MIT
License.
Overview (`vendor/github.com/klauspost/compress/fse/README.md`)
Finite State Entropy
This package provides Finite State Entropy encoding and decoding.
Finite State Entropy (also referenced as tANS)
encoding provides a fast near-optimal symbol encoding/decoding
for byte blocks as implemented in zstandard.
This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
This does not perform any multi-byte dictionary coding as LZ coders,
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
News
- Feb 2018: First implementation released. Consider this beta software for now.
Usage
This package provides a low level interface that allows to compress single independent blocks.
Each block is separate, and there is no built in integrity checks.
This means that the caller should keep track of block sizes and also do checksums if needed.
Compressing a block is done via the Compress function.
You must provide input and will receive the output and maybe an error.
These error values can be returned:
| Error | Description |
|---|---|
<nil> |
Everything ok, output is returned |
ErrIncompressible |
Returned when input is judged to be too hard to compress |
ErrUseRLE |
Returned from the compressor when the input is a single byte value repeated |
(error) |
An internal error occurred. |
As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
To reduce allocations you can provide a Scratch object
that can be re-used for successive calls. Both compression and decompression accepts a Scratch object, and the same
object can be used for both.
Be aware, that when re-using a Scratch object that the output buffer is also re-used, so if you are still using this
you must set the Out field in the scratch to nil. The same buffer is used for compression and decompression output.
Decompressing is done by calling the Decompress function.
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
your input was likely corrupted.
It is important to note that a successful decoding does not mean your output matches your original input.
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
For more detailed usage, see examples in the godoc documentation.
Performance
A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
All compression functions are currently only running on the calling goroutine so only one core will be used per block.
The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
beneficial to transpose all your input values down by 64.
With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
around 300MB/s decompression speed.
The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
Plans
At one point, more internals will be exposed to facilitate more "expert" usage of the components.
A streaming interface is also likely to be implemented. Likely compatible with FSE stream format.
Contributing
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
changes will likely not be accepted. If in doubt open an issue before writing the PR.
Overview (`vendor/github.com/klauspost/compress/huff0/README.md`)
Huff0 entropy compression
This package provides Huff0 encoding and decoding as used in zstd.
Huff0,
a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
This does not perform any multi-byte dictionary coding as LZ coders,
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
News
This is used as part of the zstandard compression and decompression package.
This ensures that most functionality is well tested.
Usage
This package provides a low level interface that allows to compress single independent blocks.
Each block is separate, and there is no built in integrity checks.
This means that the caller should keep track of block sizes and also do checksums if needed.
Compressing a block is done via the Compress1X andCompress4X functions.
You must provide input and will receive the output and maybe an error.
These error values can be returned:
| Error | Description |
|---|---|
<nil> |
Everything ok, output is returned |
ErrIncompressible |
Returned when input is judged to be too hard to compress |
ErrUseRLE |
Returned from the compressor when the input is a single byte value repeated |
ErrTooBig |
Returned if the input block exceeds the maximum allowed size (128 Kib) |
(error) |
An internal error occurred. |
As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
To reduce allocations you can provide a Scratch object
that can be re-used for successive calls. Both compression and decompression accepts a Scratch object, and the same
object can be used for both.
Be aware, that when re-using a Scratch object that the output buffer is also re-used, so if you are still using this
you must set the Out field in the scratch to nil. The same buffer is used for compression and decompression output.
The Scratch object will retain state that allows to re-use previous tables for encoding and decoding.
Tables and re-use
Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
The Scratch object allows you to set a ReusePolicy
that controls this behaviour. See the documentation for details. This can be altered between each block.
Do however note that this information is not stored in the output block and it is up to the users of the package to
record whether ReadTable should be called,
based on the boolean reported back from the CompressXX call.
If you want to store the table separate from the data, you can access them as OutData and OutTable on theScratch object.
Decompressing
The first part of decoding is to initialize the decoding table through ReadTable.
This will initialize the decoding tables.
You can supply the complete block to ReadTable and it will return the data part of the block
which can be given to the decompressor.
Decompressing is done by calling the Decompress1X
or Decompress4X function.
For concurrently decompressing content with a fixed table a stateless Decoder can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
your input was likely corrupted.
It is important to note that a successful decoding does not mean your output matches your original input.
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
Contributing
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
changes will likely not be accepted. If in doubt open an issue before writing the PR.
Overview (`vendor/github.com/klauspost/compress/zstd/README.md`)
zstd
Zstandard is a real-time compression algorithm, providing high compression ratios.
It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder.
A high performance compression algorithm is implemented. For now focused on speed.
This package provides compression to and decompression of Zstandard content.
This package is pure Go. Use noasm and nounsafe to disable relevant features.
The zstd package is provided as open source software using a Go standard license.
Currently the package is heavily optimized for 64 bit processors and will be significantly slower on 32 bit processors.
For seekable zstd streams, see this excellent package.
Installation
Install using go get -u github.com/klauspost/compress. The package is located in github.com/klauspost/compress/zstd.
Compressor
Status:
STABLE - there may always be subtle bugs, a wide variety of content has been tested and the library is actively
used by several projects. This library is being fuzz-tested for all updates.
There may still be specific combinations of data types/size/settings that could lead to edge cases,
so as always, testing is recommended.
For now, a high speed (fastest) and medium-fast (default) compressor has been implemented.
- The "Fastest" compression ratio is roughly equivalent to zstd level 1.
- The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
- The "Better" compression ratio is roughly equivalent to zstd level 7.
- The "Best" compression ratio is roughly equivalent to zstd level 11.
In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode.
The compression ratio compared to stdlib is around level 3, but usually 3x as fast.
Usage
An Encoder can be used for either compressing a stream via theio.WriteCloser interface supported by the Encoder or as multiple independent
tasks via the EncodeAll function.
Smaller encodes are encouraged to use the EncodeAll function.
Use NewWriter to create a new instance that can be used for both.
To create a writer with default options, do like this:
// Compress input to output.
func Compress(in io.Reader, out io.Writer) error {
enc, err := zstd.NewWriter(out)
if err != nil {
return err
}
_, err = io.Copy(enc, in)
if err != nil {
enc.Close()
return err
}
return enc.Close()
}Now you can encode by writing data to enc. The output will be finished writing when Close() is called.
Even if your encode fails, you should still call Close() to release any resources that may be held up.
The above is fine for big encodes. However, whenever possible try to reuse the writer.
To reuse the encoder, you can use the Reset(io.Writer) function to change to another output.
This will allow the encoder to reuse all resources and avoid wasteful allocations.
Currently stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part
of a stream. This is independent of the WithEncoderConcurrency(n), but that is likely to change
in the future. So if you want to limit concurrency for future updates, specify the concurrency
you would like.
If you would like stream encoding to be done without spawning async goroutines, use WithEncoderConcurrency(1)
which will compress input as each block is completed, blocking on writes until each has completed.
You can specify your desired compression level using WithEncoderLevel() option. Currently only pre-defined
compression settings can be specified.
Future Compatibility Guarantees
This will be an evolving project. When using this package it is important to note that both the compression efficiency and speed may change.
The goal will be to keep the default efficiency at the default zstd (level 3).
However the encoding should never be assumed to remain the same,
and you should not use hashes of compressed output for similarity checks.
The Encoder can be assumed to produce the same output from the exact same code version.
However, the may be modes in the future that break this,
although they will not be enabled without an explicit option.
This encoder is not designed to (and will probably never) output the exact same bitstream as the reference encoder.
Also note, that the cgo decompressor currently does not report all errors on invalid input,
omits error checks, ignores checksums
and seems to ignore concatenated streams, even though it is part of the spec.
Blocks
For compressing small blocks, the returned encoder has a function called EncodeAll(src, dst []byte) []byte.
EncodeAll will encode all input in src and append it to dst.
This function can be called concurrently.
Each call will only run on a same goroutine as the caller.
Encoded blocks can be concatenated and the result will be the combined input stream.
Data compressed with EncodeAll can be decoded with the Decoder, using either a stream or DecodeAll.
Especially when encoding blocks you should take special care to reuse the encoder.
This will effectively make it run without allocations after a warmup period.
To make it run completely without allocations, supply a destination buffer with space for all content.
import "github.com/klauspost/compress/zstd"
// Create a writer that caches compressors.
// For this operation type we supply a nil Reader.
var encoder, _ = zstd.NewWriter(nil)
// Compress a buffer.
// If you have a destination buffer, the allocation in the call can also be eliminated.
func Compress(src []byte) []byte {
return encoder.EncodeAll(src, make([]byte, 0, len(src)))
}You can control the maximum number of concurrent encodes using the WithEncoderConcurrency(n)
option when creating the writer.
Using the Encoder for both a stream and individual blocks concurrently is safe.
Performance
I have collected some speed examples to compare speed and compression against other compressors.
fileis the input file.outis the compressor used.zskpis this package.zstdis the Datadog cgo library.gzstd/gzkpis gzip standard and this library.levelis the compression level used. Forzskplevel 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best".insize/outsizeis the input/output size.millisis the number of milliseconds used for compression.mb/sis megabytes (2^20 bytes) per second.
/* Detailed source-code truncated for AI context efficiency. */Decompressor
Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.
This library is being continuously fuzz-tested,
kindly supplied by fuzzit.dev.
The main purpose of the fuzz testing is to ensure that it is not possible to crash the decoder,
or run it past its limits with ANY input provided.
Usage
The package has been designed for two main usages, big streams of data and smaller in-memory buffers.
There are two main usages of the package for these. Both of them are accessed by creating a Decoder.
For streaming use a simple setup could look like this:
import "github.com/klauspost/compress/zstd"
func Decompress(in io.Reader, out io.Writer) error {
d, err := zstd.NewReader(in)
if err != nil {
return err
}
defer d.Close()
// Copy content...
_, err = io.Copy(out, d)
return err
}It is important to use the "Close" function when you no longer need the Reader to stop running goroutines,
when running with default settings.
Goroutines will exit once an error has been returned, including io.EOF at the end of a stream.
Streams are decoded concurrently in 4 asynchronous stages to give the best possible throughput.
However, if you prefer synchronous decompression, use WithDecoderConcurrency(1) which will decompress data
as it is being requested only.
For decoding buffers, it could look something like this:
import "github.com/klauspost/compress/zstd"
// Create a reader that caches decompressors.
// For this operation type we supply a nil Reader.
var decoder, _ = zstd.NewReader(nil, zstd.WithDecoderConcurrency(0))
// Decompress a buffer. We don't supply a destination buffer,
// so it will be allocated by the decoder.
func Decompress(src []byte) ([]byte, error) {
return decoder.DecodeAll(src, nil)
}Both of these cases should provide the functionality needed.
The decoder can be used for concurrent decompression of multiple buffers.
By default 4 decompressors will be created.
It will only allow a certain number of concurrent operations to run.
To tweak that yourself use the WithDecoderConcurrency(n) option when creating the decoder.
It is possible to use WithDecoderConcurrency(0) to create GOMAXPROCS decoders.
Dictionaries
Data compressed with dictionaries can be decompressed.
Dictionaries are added individually to Decoders.
Dictionaries are generated by the zstd --train command and contains an initial state for the decoder.
To add a dictionary use the WithDecoderDicts(dicts ...[]byte) option with the dictionary data.
Several dictionaries can be added at once.
The dictionary will be used automatically for the data that specifies them.
A re-used Decoder will still contain the dictionaries registered.
When registering multiple dictionaries with the same ID, the last one will be used.
It is possible to use dictionaries when compressing data.
To enable a dictionary use WithEncoderDict(dict []byte). Here only one dictionary will be used
and it will likely be used even if it doesn't improve compression.
The used dictionary must be used to decompress the content.
For any real gains, the dictionary should be built with similar data.
If an unsuitable dictionary is used the output may be slightly larger than using no dictionary.
Use the zstd commandline tool to build a dictionary from sample data.
For information see zstd dictionary information.
For now there is a fixed startup performance penalty for compressing content with dictionaries.
This will likely be improved over time. Just be aware to test performance when implementing.
Allocation-less operation
The decoder has been designed to operate without allocations after a warmup.
This means that you should store the decoder for best performance.
To re-use a stream decoder, use the Reset(r io.Reader) error to switch to another stream.
A decoder can safely be re-used even if the previous stream failed.
To release the resources, you must call the Close() function on a decoder.
After this it can no longer be reused, but all running goroutines will be stopped.
So you must use this if you will no longer need the Reader.
For decompressing smaller buffers a single decoder can be used.
When decoding buffers, you can supply a destination slice with length 0 and your expected capacity.
In this case no unneeded allocations should be made.
Concurrency
The buffer decoder does everything on the same goroutine and does nothing concurrently.
It can however decode several buffers concurrently. Use WithDecoderConcurrency(n) to limit that.
The stream decoder will create goroutines that:
- Reads input and splits the input into blocks.
- Decompression of literals.
- Decompression of sequences.
- Reconstruction of output stream.
So effectively this also means the decoder will "read ahead" and prepare data to always be available for output.
The concurrency level will, for streams, determine how many blocks ahead the compression will start.
Since "blocks" are quite dependent on the output of the previous block stream decoding will only have limited concurrency.
In practice this means that concurrency is often limited to utilizing about 3 cores effectively.
Benchmarks
The first two are streaming decodes and the last are smaller inputs.
Running on AMD Ryzen 9 3950X 16-Core Processor. AMD64 assembly used.
/* Detailed source-code truncated for AI context efficiency. */This reflects the performance around May 2022, but this may be out of date.
Zstd inside ZIP files
It is possible to use zstandard to compress individual files inside zip archives.
While this isn't widely supported it can be useful for internal files.
To support the compression and decompression of these files you must register a compressor and decompressor.
It is highly recommended registering the (de)compressors on individual zip Reader/Writer and NOT
use the global registration functions. The main reason for this is that 2 registrations from
different packages will result in a panic.
It is a good idea to only have a single compressor and decompressor, since they can be used for multiple zip
files concurrently, and using a single instance will allow reusing some resources.
See this example for
how to compress and decompress files inside zip archives.
Contributions
Contributions are always welcome.
For new features/fixes, remember to add tests and for performance enhancements include benchmarks.
For general feedback and experience reports, feel free to open an issue or write me on Twitter.
This package includes the excellent github.com/cespare/xxhash package Copyright (c) 2016 Caleb Spare.
Overview (`vendor/github.com/prometheus/client_golang/prometheus/README.md`)
Overview (`vendor/github.com/redis/go-redis/v9/README.md`)
Redis client for Go
go-redis is brought to you by :star: uptrace/uptrace.
Uptrace is an open-source APM tool that supports distributed tracing, metrics, and logs. You can
use it to monitor applications and set up automatic alerts to receive notifications via email,
Slack, Telegram, and others.See OpenTelemetry example which
demonstrates how you can use Uptrace to monitor go-redis.
How do I Redis?
Learn for free at Redis University
Build faster with the Redis Launchpad
Documentation
Resources
Ecosystem
This client also works with Kvrocks, a distributed
key value NoSQL database that uses RocksDB as storage engine and is compatible with Redis protocol.
Features
- Redis commands except QUIT and SYNC.
- Automatic connection pooling.
- Pub/Sub.
- Pipelines and transactions.
- Scripting.
- Redis Sentinel.
- Redis Cluster.
- Redis Ring.
- Redis Performance Monitoring.
- Redis Probabilistic [RedisStack]
Installation
go-redis supports 2 last Go versions and requires a Go version with
modules support. So make sure to initialize a Go
module:
go mod init github.com/my/repoThen install go-redis/v9:
go get github.com/redis/go-redis/v9Quickstart
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func ExampleClient() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val)
val2, err := rdb.Get(ctx, "key2").Result()
if err == redis.Nil {
fmt.Println("key2 does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("key2", val2)
}
// Output: key value
// key2 does not exist
}The above can be modified to specify the version of the RESP protocol by adding the protocol
option to the Options struct:
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
Protocol: 3, // specify 2 for RESP 2 or 3 for RESP 3
})Connecting via a redis url
go-redis also supports connecting via the
redis uri specification.
The example below demonstrates how the connection can easily be configured using a string, adhering
to this specification.
import (
"github.com/redis/go-redis/v9"
)
func ExampleClient() *redis.Client {
url := "redis://user:password@localhost:6379/0?protocol=3"
opts, err := redis.ParseURL(url)
if err != nil {
panic(err)
}
return redis.NewClient(opts)
}Advanced Configuration
go-redis supports extending the client identification phase to allow projects to send their own custom client identification.
Default Client Identification
By default, go-redis automatically sends the client library name and version during the connection process. This feature is available in redis-server as of version 7.2. As a result, the command is "fire and forget", meaning it should fail silently, in the case that the redis server does not support this feature.
Disabling Identity Verification
When connection identity verification is not required or needs to be explicitly disabled, a DisableIdentity configuration option exists.
Initially there was a typo and the option was named DisableIndentity instead of DisableIdentity. The misspelled option is marked as Deprecated and will be removed in V10 of this library.
Although both options will work at the moment, the correct option is DisableIdentity. The deprecated option will be removed in V10 of this library, so please use the correct option name to avoid any issues.
To disable verification, set the DisableIdentity option to true in the Redis client options:
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
DisableIdentity: true, // Disable set-info on connect
})Unstable RESP3 Structures for RediSearch Commands
When integrating Redis with application functionalities using RESP3, it's important to note that some response structures aren't final yet. This is especially true for more complex structures like search and query results. We recommend using RESP2 when using the search and query capabilities, but we plan to stabilize the RESP3-based API-s in the coming versions. You can find more guidance in the upcoming release notes.
To enable unstable RESP3, set the option in your client configuration:
redis.NewClient(&redis.Options{
UnstableResp3: true,
})Note: When UnstableResp3 mode is enabled, it's necessary to use RawResult() and RawVal() to retrieve a raw data.
Since, raw response is the only option for unstable search commands Val() and Result() calls wouldn't have any affect on them:
res1, err := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawResult()
val1 := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawVal()Contributing
Please see out contributing guidelines to help us improve this library!
Look and feel
Some corner cases:
// SET key value EX 10 NX
set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result()
// SET key value keepttl NX
set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result()
// SORT list LIMIT 0 2 ASC
vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()
// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{
Min: "-inf",
Max: "+inf",
Offset: 0,
Count: 2,
}).Result()
// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{
Keys: []string{"zset1", "zset2"},
Weights: []int64{2, 3}
}).Result()
// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()
// custom command
res, err := rdb.Do(ctx, "set", "key", "value").Result()Run the test
go-redis will start a redis-server and run the test cases.
The paths of redis-server bin file and redis config file are defined in main_test.go:
var (
redisServerBin, _ = filepath.Abs(filepath.Join("testdata", "redis", "src", "redis-server"))
redisServerConf, _ = filepath.Abs(filepath.Join("testdata", "redis", "redis.conf"))
)For local testing, you can change the variables to refer to your local files, or create a soft link
to the corresponding folder for redis-server and copy the config file to testdata/redis/:
ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src
cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/Lastly, run:
go testAnother option is to run your specific tests with an already running redis. The example below, tests
against a redis running on port 9999.:
REDIS_PORT=9999 go test <your options>See also
- Golang ORM for PostgreSQL, MySQL, MSSQL, and SQLite
- Golang PostgreSQL
- Golang HTTP router
- Golang ClickHouse ORM
Contributors
Thanks to all the people who already contributed!
Overview (`vendor/go.opentelemetry.io/contrib/detectors/gcp/README.md`)
GCP Resource detector
The GCP resource detector supports detecting resources on:
- Google Compute Engine (GCE)
- Google Kubernetes Engine (GKE)
- Google App Engine (GAE)
- Cloud Run
- Cloud Run jobs
- Cloud Functions
Usage
ctx := context.Background()
// Detect your resources
res, err := resource.New(ctx,
// Use the GCP resource detector!
resource.WithDetectors(gcp.NewDetector()),
// Keep the default detectors
resource.WithTelemetrySDK(),
// Add your own custom attributes to identify your application
resource.WithAttributes(
semconv.ServiceNameKey.String("my-application"),
semconv.ServiceNamespaceKey.String("my-company-frontend-team"),
),
)
if err != nil {
// Handle err
}
// Use the resource in your tracerprovider (or meterprovider)
tp := trace.NewTracerProvider(
// ... other options
trace.WithResource(res),
)Setting Kubernetes attributes
Previous iterations of GCP resource detection attempted to detectcontainer.name, k8s.pod.name and k8s.namespace.name. When using this detector,
you should use this in your Pod Spec to set these usingOTEL_RESOURCE_ATTRIBUTES:
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CONTAINER_NAME
value: my-container-name
- name: OTEL_RESOURCE_ATTRIBUTES
value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)To have a detector unpack the OTEL_RESOURCE_ATTRIBUTES envvar, use the WithFromEnv option:
...
// Detect your resources
res, err := resource.New(ctx,
resource.WithDetectors(gcp.NewDetector()),
resource.WithTelemetrySDK(),
resource.WithFromEnv(), // unpacks OTEL_RESOURCE_ATTRIBUTES
// Add your own custom attributes to identify your application
resource.WithAttributes(
semconv.ServiceNameKey.String("my-application"),
semconv.ServiceNamespaceKey.String("my-company-frontend-team"),
),
)
...Overview (`vendor/go.opentelemetry.io/otel/exporters/prometheus/README.md`)
Prometheus Exporter
Overview (`vendor/go.opentelemetry.io/otel/log/embedded/README.md`)
Log Embedded
Overview (`vendor/go.opentelemetry.io/otel/log/noop/README.md`)
Log Noop
Overview (`vendor/go.opentelemetry.io/otel/metric/embedded/README.md`)
Metric Embedded
Overview (`vendor/go.opentelemetry.io/otel/metric/noop/README.md`)
Metric Noop
Overview (`vendor/go.opentelemetry.io/otel/sdk/instrumentation/README.md`)
SDK Instrumentation
Overview (`vendor/go.opentelemetry.io/otel/sdk/log/README.md`)
Log SDK
Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/README.md`)
Metric SDK
Overview (`vendor/go.opentelemetry.io/otel/sdk/resource/README.md`)
SDK Resource
Overview (`vendor/go.opentelemetry.io/otel/sdk/trace/README.md`)
SDK Trace
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.10.0/README.md`)
Semconv v1.10.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.12.0/README.md`)
Semconv v1.12.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.24.0/README.md`)
Semconv v1.24.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.30.0/README.md`)
Semconv v1.30.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.37.0/README.md`)
Semconv v1.37.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.4.0/README.md`)
Semconv v1.4.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.40.0/README.md`)
Semconv v1.40.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.41.0/README.md`)
Semconv v1.41.0
Overview (`vendor/go.opentelemetry.io/otel/semconv/v1.43.0/README.md`)
Semconv v1.43.0
Overview (`vendor/go.opentelemetry.io/otel/trace/embedded/README.md`)
Trace Embedded
Overview (`vendor/go.opentelemetry.io/otel/trace/noop/README.md`)
Trace Noop
Overview (`vendor/golang.org/x/net/http2/README.md`)
This package (golang.org/x/net/http2) is the original source of truth
of the Go HTTP/2 implementation.
As of Go 1.27, the source of truth has moved to the standard library
package net/http/internal/http2.
All new feature development should happen in that package.
Only critical bug fixes and security fixes will be backported to x/net.
The x/net package contains two implementations of the HTTP/2 transport and server:
The original implementation (no longer the source of truth).
A reimplementation of the x/net/http2 APIs in terms of net/http.
This is called "the wrapping implementation", since it wraps net/http.
The original implementation is used when the Go version is less than 1.27.
The wrapping implementation is used when the Go version is at least 1.27.
The build tag "http2legacy" may be set to use the original implementation.
Overview (`vendor/golang.org/x/sys/unix/README.md`)
Building `sys/unix`
The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.
Build Systems
There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
Old Build System (currently for `GOOS != "linux"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.
To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.
To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run mkall.sh. This will generate the files for
your specific system. Running mkall.sh -n shows the commands that will be run.
Requirements: bash, go
New Build System (currently for `GOOS == "linux"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.
The OS specific files for the new build system are located in the ${GOOS}
directory, and the build is coordinated by the ${GOOS}/mkall.go program. When
the kernel or system library updates, modify the Dockerfile at${GOOS}/Dockerfile to checkout the new release of the source.
To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running mkall.sh will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running mkall.sh -n shows the commands that will be run.
Requirements: bash, go, docker
Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts/programs cannot be called normally.
They must be called from within the docker container.
asm files
The hand-written assembly file at asm_${GOOS}_${GOARCH}.s implements system
call dispatch. There are three entry points:
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.
When porting Go to a new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.
mksysnum
Mksysnum is a Go program located at ${GOOS}/mksysnum.go (or mksysnum_${GOOS}.go
for the old system). This program takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See zsysnum_${GOOS}_${GOARCH}.go for the generated
constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you may need to update the
parsing in mksysnum.
mksyscall.go
The syscall.go, syscall_${GOOS}.go, syscall_${GOOS}_${GOARCH}.go are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list //sys comments giving prototypes for ones that can be generated.
The mksyscall.go program takes the //sys and //sysnb comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the zsysnum_${GOOS}_${GOARCH}.go file. The function
prototype can be exported (capitalized) or not.
Adding a new syscall often just requires adding a new //sys function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported //sys prototype, and then write a custom wrapper insyscall_${GOOS}.go.
types files
For each OS, there is a hand-written Go file at ${GOOS}/types.go (ortypes_${GOOS}.go on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written toztypes_${GOOS}_${GOARCH}.go.
The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be #defined to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a #define that can
get the real ones.
See types_darwin.go and linux/types.go for examples.
To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some #if/#elif macros in your include statements.
mkerrors.sh
This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
and a wide variety of miscellaneous constants. The constants come from the list
of include files in the includes_${uname} variable. A regex then picks out
the desired #define statements, and generates the corresponding Go constants.
The error numbers and strings are generated from #include <errno.h>, and the
signal numbers and strings are generated from #include <signal.h>. All of
these constants are written to zerrors_${GOOS}_${GOARCH}.go via a C program,_errors.c, which prints out all the constants.
To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.
internal/mkmerge
This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.
The merge is performed in the following steps:
- Construct the set of common code that is identical in all architecture-specific files.
- Write this common code to the merged file.
- Remove the common code from all architecture-specific files.
Generated files
`zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by mkerrors.sh (see above).
`zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by mksyscall.go (see above).
`zsysnum_${GOOS}_${GOARCH}.go`
A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).
`ztypes_${GOOS}_${GOARCH}.go`
A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).
Overview (`vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/README.md`)
Azure Core Client Module for Go
The azcore module provides a set of common interfaces and types for Go SDK client modules.
These modules follow the Azure SDK Design Guidelines for Go.
Getting started
This project uses Go modules for versioning and dependency management.
Typically, you will not need to explicitly install azcore as it will be installed as a client module dependency.
To add the latest version to your go.mod file, execute the following command.
go get github.com/Azure/azure-sdk-for-go/sdk/azcoreGeneral documentation and examples can be found on pkg.go.dev.
Contributing
This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution.
For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether
you need to provide a CLA and decorate the PR appropriately (e.g., label,
comment). Simply follow the instructions provided by the bot. You will only
need to do this once across all repos using our CLA.
This project has adopted the
Microsoft Open Source Code of Conduct.
For more information, see the
Code of Conduct FAQ
or contact [email protected] with any
additional questions or comments.
Overview (`vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md`)
Azure Identity Client Module for Go
The Azure Identity module provides Microsoft Entra ID (formerly Azure Active Directory) token authentication support across the Azure SDK. It includes a set of TokenCredential implementations, which can be used with Azure SDK clients supporting token authentication.
| Microsoft Entra ID documentation
| Source code
Getting started
Install the module
This project uses Go modules for versioning and dependency management.
Install the Azure Identity module:
go get -u github.com/Azure/azure-sdk-for-go/sdk/azidentityPrerequisites
- an Azure subscription
- Go 1.18
Authenticating during local development
When debugging and executing code locally, developers typically use their own accounts to authenticate calls to Azure services. The azidentity module supports authenticating through developer tools to simplify local development.
Authenticating via the Azure CLI
DefaultAzureCredential and AzureCLICredential can authenticate as the user
signed in to the Azure CLI. To sign in to the Azure CLI, run az login. On a system with a default web browser, the Azure CLI will launch the browser to authenticate a user.
When no default browser is available, az login will use the device code
authentication flow. This can also be selected manually by running az login --use-device-code.
Authenticate via the Azure Developer CLI
Developers coding outside of an IDE can also use the Azure Developer CLI to authenticate. Applications using the DefaultAzureCredential or the AzureDeveloperCLICredential can use the account logged in to the Azure Developer CLI to authenticate calls in their application when running locally.
To authenticate with the Azure Developer CLI, run azd auth login. On a system with a default web browser, azd will launch the browser to authenticate. On systems without a default web browser, run azd auth login --use-device-code to use the device code authentication flow.
Key concepts
Credentials
A credential is a type which contains or can obtain the data needed for a
service client to authenticate requests. Service clients across the Azure SDK
accept a credential instance when they are constructed, and use that credential
to authenticate requests.
The azidentity module focuses on OAuth authentication with Microsoft Entra ID. It offers a variety of credential types capable of acquiring a Microsoft Entra access token. See Credential Types for a list of this module's credential types.
DefaultAzureCredential
DefaultAzureCredential simplifies authentication while developing apps that deploy to Azure by combining credentials used in Azure hosting environments with credentials used in local development. For more information, see DefaultAzureCredential overview.
Managed Identity
DefaultAzureCredential and ManagedIdentityCredential support
managed identity authentication
in any hosting environment which supports managed identities, such as (this list is not exhaustive):
- Azure App Service
- Azure Arc
- Azure Cloud Shell
- Azure Kubernetes Service
- Azure Service Fabric
- Azure Virtual Machines
Examples
- Authenticate with DefaultAzureCredential
- Define a custom authentication flow with ChainedTokenCredential
- Specify a user-assigned managed identity for DefaultAzureCredential
Authenticate with DefaultAzureCredential
This example demonstrates authenticating a client from the armresources module with DefaultAzureCredential.
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
// handle error
}
client := armresources.NewResourceGroupsClient("subscription ID", cred, nil)Specify a user-assigned managed identity for DefaultAzureCredential
To configure DefaultAzureCredential to authenticate a user-assigned managed identity, set the environment variable AZURE_CLIENT_ID to the identity's client ID.
Define a custom authentication flow with `ChainedTokenCredential`
DefaultAzureCredential is generally the quickest way to get started developing apps for Azure. For more advanced scenarios, ChainedTokenCredential links multiple credential instances to be tried sequentially when authenticating. It will try each chained credential in turn until one provides a token or fails to authenticate due to an error.
The following example demonstrates creating a credential, which will attempt to authenticate using managed identity. It will fall back to authenticating via the Azure CLI when a managed identity is unavailable.
managed, err := azidentity.NewManagedIdentityCredential(nil)
if err != nil {
// handle error
}
azCLI, err := azidentity.NewAzureCLICredential(nil)
if err != nil {
// handle error
}
chain, err := azidentity.NewChainedTokenCredential([]azcore.TokenCredential{managed, azCLI}, nil)
if err != nil {
// handle error
}
client := armresources.NewResourceGroupsClient("subscription ID", chain, nil)Credential Types
Credential chains
| Credential | Usage | Reference |
|---|---|---|
| DefaultAzureCredential | Simplified authentication experience for getting started developing Azure apps | DefaultAzureCredential overview |
| ChainedTokenCredential | Define custom authentication flows, composing multiple credentials | ChainedTokenCredential overview |
Authenticating Azure-Hosted Applications
| Credential | Usage |
|---|---|
| EnvironmentCredential | Authenticate a service principal or user configured by environment variables |
| ManagedIdentityCredential | Authenticate the managed identity of an Azure resource |
| WorkloadIdentityCredential | Authenticate a workload identity on Kubernetes |
Authenticating Service Principals
| Credential | Usage |
|---|---|
| AzurePipelinesCredential | Authenticate an Azure Pipelines service connection |
| ClientAssertionCredential | Authenticate a service principal with a signed client assertion |
| ClientCertificateCredential | Authenticate a service principal with a certificate |
| ClientSecretCredential | Authenticate a service principal with a secret |
Authenticating Users
| Credential | Usage |
|---|---|
| InteractiveBrowserCredential | Interactively authenticate a user with the default web browser |
| DeviceCodeCredential | Interactively authenticate a user on a device with limited UI |
| UsernamePasswordCredential | Authenticate a user with a username and password |
Authenticating via Development Tools
| Credential | Usage |
|---|---|
| AzureCLICredential | Authenticate as the user signed in to the Azure CLI |
| AzureDeveloperCLICredential | Authenticates as the user signed in to the Azure Developer CLI |
Environment Variables
DefaultAzureCredential and EnvironmentCredential can be configured with environment variables. Each type of authentication requires values for specific variables:
Service principal with secret
| variable name | value |
|---|---|
AZURE_CLIENT_ID |
ID of a Microsoft Entra application |
AZURE_TENANT_ID |
ID of the application's Microsoft Entra tenant |
AZURE_CLIENT_SECRET |
one of the application's client secrets |
Service principal with certificate
| variable name | value |
|---|---|
AZURE_CLIENT_ID |
ID of a Microsoft Entra application |
AZURE_TENANT_ID |
ID of the application's Microsoft Entra tenant |
AZURE_CLIENT_CERTIFICATE_PATH |
path to a certificate file including private key |
AZURE_CLIENT_CERTIFICATE_PASSWORD |
password of the certificate file, if any |
Username and password
| variable name | value |
|---|---|
AZURE_CLIENT_ID |
ID of a Microsoft Entra application |
AZURE_USERNAME |
a username (usually an email address) |
AZURE_PASSWORD |
that user's password |
Configuration is attempted in the above order. For example, if values for a
client secret and certificate are both present, the client secret will be used.
Token caching
Token caching is an azidentity feature that allows apps to:
- Cache tokens in memory (default) or on disk (opt-in).
- Improve resilience and performance.
- Reduce the number of requests made to Microsoft Entra ID to obtain access tokens.
For more details, see the token caching documentation.
Troubleshooting
Error Handling
Credentials return an error when they fail to authenticate or lack data they require to authenticate. For guidance on resolving errors from specific credential types, see the troubleshooting guide.
For more details on handling specific Microsoft Entra errors, see the Microsoft Entra error code documentation.
Logging
This module uses the classification-based logging implementation in azcore. To enable console logging for all SDK modules, set AZURE_SDK_GO_LOGGING to all. Use the azcore/log package to control log event output or to enable logs for azidentity only. For example:
import azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
// print log output to stdout
azlog.SetListener(func(event azlog.Event, s string) {
fmt.Println(s)
})
// include only azidentity credential logs
azlog.SetEvents(azidentity.EventAuthentication)Credentials log basic information only, such as GetToken success or failure and errors. These log entries don't contain authentication secrets but may contain sensitive information.
Next steps
Client and management modules listed on the Azure SDK releases page support authenticating with azidentity credential types. You can learn more about using these libraries in their documentation, which is linked from the release page.
Provide Feedback
If you encounter bugs or have suggestions, please
open an issue.
Contributing
This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution.
For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether
you need to provide a CLA and decorate the PR appropriately (e.g., label,
comment). Simply follow the instructions provided by the bot. You will only
need to do this once across all repos using our CLA.
This project has adopted the
Microsoft Open Source Code of Conduct.
For more information, see the
Code of Conduct FAQ
or contact [email protected] with any
additional questions or comments.
Overview (`vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/README.md`)
GCP Resource detection library
This is a library intended to be used by Upstream OpenTelemetry resource detectors. It exists within this repository to allow for integration testing of the detection functions in real GCP environments.
Overview (`vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/README.md`)
OpenTelemetry Google Cloud Monitoring Exporter
OpenTelemetry Google Cloud Monitoring Exporter allows the user to send collected metrics to Google Cloud.
To get started with instrumentation in Google Cloud, see Generate traces and metrics with
Go.
To learn more about instrumentation and observability, including opinionated recommendations
for Google Cloud Observability, visit Instrumentation and
observability.
Google Cloud Monitoring provides visibility into the performance, uptime, and overall health of cloud-powered applications. It collects metrics, events, and metadata from Google Cloud, Amazon Web Services, hosted uptime probes, application instrumentation, and a variety of common application components including Cassandra, Nginx, Apache Web Server, Elasticsearch, and many others. Operations ingests that data and generates insights via dashboards, charts, and alerts. Cloud Monitoring alerting helps you collaborate by integrating with Slack, PagerDuty, and more.
Setup
Google Cloud Monitoring is a managed service provided by Google Cloud Platform. Google Cloud Monitoring requires to set up "Workspace" in advance. The guide to create a new Workspace is available on the official document.
Authentication
The Google Cloud Monitoring exporter depends upon google.FindDefaultCredentials, so the service account is automatically detected by default, but also the custom credential file (so called service_account_key.json) can be detected with specific conditions. Quoting from the document of google.FindDefaultCredentials:
- A JSON file whose path is specified by the
GOOGLE_APPLICATION_CREDENTIALSenvironment variable. - A JSON file in a location known to the gcloud command-line tool. On Windows, this is
%APPDATA%/gcloud/application_default_credentials.json. On other systems,$HOME/.config/gcloud/application_default_credentials.json.
When running code locally, you may need to specify a Google Project ID in addition to GOOGLE_APPLICATION_CREDENTIALS. This is best done using an environment variable (e.g. GOOGLE_CLOUD_PROJECT) and the metric.WithProjectID method, e.g.:
projectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
opts := []mexporter.Option{
mexporter.WithProjectID(projectID),
}Useful links
- For more information on OpenTelemetry, visit: https://opentelemetry.io/
- For more about OpenTelemetry Go, visit: https://github.com/open-telemetry/opentelemetry-go
- Learn more about Google Cloud Monitoring at https://cloud.google.com/monitoring
Overview (`vendor/github.com/alicebob/miniredis/v2/fpconv/README.md`)
This is a translation of the actual C code in Redis (7.2) which does the float
-> string conversion.
Strconv does a close enough job, but we can use the exact same logic, so why not.
Overview (`vendor/github.com/alicebob/miniredis/v2/geohash/README.md`)
This is a (selected) copy of github.com/mmcloughlin/geohash with the latitude
range changed from 90 to ~85, to align with the algorithm use by Redis.
Overview (`vendor/github.com/alicebob/miniredis/v2/gopher-json/README.md`)
Copied from https://github.com/layeh/gopher-json and https://github.com/alicebob/gopher-json
Overview (`vendor/github.com/alicebob/miniredis/v2/metro/README.md`)
This is a partial copy of github.com/dgryski/go-metro.
Overview (`vendor/github.com/alicebob/miniredis/v2/size/readme.md`)
Credits to DmitriyVTitov on his package https://github.com/DmitriyVTitov/size
Overview (`vendor/github.com/go-jose/go-jose/v4/json/README.md`)
Safe JSON
This repository contains a fork of the encoding/json package from Go 1.6.
The following changes were made:
- Object deserialization uses case-sensitive member name matching instead of
case-insensitive matching.
This is to avoid differences in the interpretation of JOSE messages between
go-jose and libraries written in other languages. - When deserializing a JSON object, we check for duplicate keys and reject the
input whenever we detect a duplicate. Rather than trying to work with malformed
data, we prefer to reject it right away.
Overview (`vendor/github.com/google/s2a-go/internal/v2/README.md`)
This directory has the implementation of the S2Av2's gRPC-Go client libraries
Overview (`vendor/github.com/stretchr/testify/internal/spew/README.md`)
go-spew
Go-spew implements a deep pretty printer for Go data structures to aid in
debugging. A comprehensive suite of tests with 100% test coverage is provided
to ensure proper functionality.
License
Go-spew is licensed under the copyfree ISC License.
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/README.md`)
OTLP Trace Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutlog/README.md`)
STDOUT Log Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric/README.md`)
STDOUT Metric Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/README.md`)
STDOUT Trace Exporter
Overview (`vendor/go.opentelemetry.io/otel/sdk/internal/x/README.md`)
Experimental Features
The SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These feature may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Resource
OpenTelemetry resource semantic conventions include many attribute definitions that are defined as experimental.
To have experimental semantic conventions be added by resource detectors set the OTEL_GO_X_RESOURCE environment variable.
The value set must be the case-insensitive string of "true" to enable the feature.
All other values are ignored.
Examples
Enable experimental resource semantic conventions.
export OTEL_GO_X_RESOURCE=trueDisable experimental resource semantic conventions.
unset OTEL_GO_X_RESOURCECompatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/exemplar/README.md`)
Metric SDK Exemplars
Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/metricdata/README.md`)
SDK Metric data
Overview (`vendor/go.opentelemetry.io/otel/sdk/trace/tracetest/README.md`)
SDK Trace test
Overview (`vendor/golang.org/x/net/internal/httpcommon/README.md`)
These two packages are identical:
- net/http/internal/httpcommon
- golang.org/x/net/internal/httpcommon
The two are kept in sync manually.
Any change to one should be made in the other.
Overview (`vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/README.md`)
Azure Blob Storage module for Go
Service Version: 2023-11-03
Azure Blob Storage is Microsoft's object storage solution for the cloud. Blob
Storage is optimized for storing massive amounts of unstructured data - data that does not adhere to a particular data model or
definition, such as text or binary data. For more information, see Introduction to Azure Blob Storage.
Use the Azure Blob Storage client module github.com/Azure/azure-sdk-for-go/sdk/storage/azblob to:
- Authenticate clients with Azure Blob Storage
- Manipulate containers and blobs in an Azure storage account
Key links:
Source code | API reference documentation | REST API documentation | Product documentation | Samples
Getting started
Prerequisites
- Go, version 1.18 or higher - Install Go
- Azure subscription - Create a free account
- Azure storage account - To create a storage account, use tools including the Azure portal,
Azure PowerShell, or the Azure CLI.
Here's an example using the Azure CLI:
az storage account create --name MyStorageAccount --resource-group MyResourceGroup --location westus --sku Standard_LRSInstall the package
Install the Azure Blob Storage client module for Go with go get:
go get github.com/Azure/azure-sdk-for-go/sdk/storage/azblobIf you plan to authenticate with Azure Active Directory (recommended), also install the azidentity module.
go get github.com/Azure/azure-sdk-for-go/sdk/azidentityAuthenticate the client
To interact with the Azure Blob Storage service, you'll need to create an instance of the azblob.Client type. The azidentity module makes it easy to add Azure Active Directory support for authenticating Azure SDK clients with their corresponding Azure services.
// create a credential for authenticating with Azure Active Directory
cred, err := azidentity.NewDefaultAzureCredential(nil)
// TODO: handle err
// create an azblob.Client for the specified storage account that uses the above credential
client, err := azblob.NewClient("https://MYSTORAGEACCOUNT.blob.core.windows.net/", cred, nil)
// TODO: handle errLearn more about enabling Azure Active Directory for authentication with Azure Storage:
Other options for authentication include connection strings, shared key, shared access signatures (SAS), and anonymous public access. Use the appropriate client constructor function for the authentication mechanism you wish to use. For examples, see:
Key concepts
Blob Storage is designed for:
- Serving images or documents directly to a browser.
- Storing files for distributed access.
- Streaming video and audio.
- Writing to log files.
- Storing data for backup and restore, disaster recovery, and archiving.
- Storing data for analysis by an on-premises or Azure-hosted service.
Blob Storage offers three types of resources:
- The storage account
- One or more containers in a storage account
- One or more blobs in a container
Instances of the azblob.Client type provide methods for manipulating containers and blobs within a storage account.
The storage account is specified when the azblob.Client is constructed.
Specialized clients
The Azure Blob Storage client module for Go also provides specialized clients in various subpackages. Use these clients when you need to interact with a specific kind of blob. Learn more about block blobs, append blobs, and page blobs.
The blob package contains APIs common to all blob types. This includes APIs for deleting and undeleting a blob, setting metadata, and more.
The lease package contains clients for managing leases on blobs and containers. See the REST API reference for general information on leases.
The container package contains APIs specific to containers. This includes APIs for setting access policies or properties, and more.
The service package contains APIs specific to the Blob service. This includes APIs for manipulating containers, retrieving account information, and more.
The sas package contains utilities to aid in the creation and manipulation of shared access signature (SAS) tokens.
See the package's documentation for more information.
Goroutine safety
We guarantee that all client instance methods are goroutine-safe and independent of each other (see guideline). This ensures that the recommendation to reuse client instances is always safe, even across goroutines.
Blob metadata
Blob metadata name-value pairs are valid HTTP headers and should adhere to all restrictions governing HTTP headers. Metadata names must be valid HTTP header names, may contain only ASCII characters, and should be treated as case-insensitive. Base64-encode or URL-encode metadata values containing non-ASCII characters.
Additional concepts
Client options |
Accessing the response |
Handling failures |
Logging
Examples
Upload a blob
const (
account = "https://MYSTORAGEACCOUNT.blob.core.windows.net/"
containerName = "sample-container"
blobName = "sample-blob"
sampleFile = "path/to/sample/file"
)
// authenticate with Azure Active Directory
cred, err := azidentity.NewDefaultAzureCredential(nil)
// TODO: handle error
// create a client for the specified storage account
client, err := azblob.NewClient(account, cred, nil)
// TODO: handle error
// open the file for reading
file, err := os.OpenFile(sampleFile, os.O_RDONLY, 0)
// TODO: handle error
defer file.Close()
// upload the file to the specified container with the specified blob name
_, err = client.UploadFile(context.TODO(), containerName, blobName, file, nil)
// TODO: handle errorDownload a blob
// this example accesses a public blob via anonymous access, so no credentials are required
client, err := azblob.NewClientWithNoCredential("https://azurestoragesamples.blob.core.windows.net/", nil)
// TODO: handle error
// create or open a local file where we can download the blob
file, err := os.Create("cloud.jpg")
// TODO: handle error
defer file.Close()
// download the blob
_, err = client.DownloadFile(context.TODO(), "samples", "cloud.jpg", file, nil)
// TODO: handle errorEnumerate blobs
const (
account = "https://MYSTORAGEACCOUNT.blob.core.windows.net/"
containerName = "sample-container"
)
// authenticate with Azure Active Directory
cred, err := azidentity.NewDefaultAzureCredential(nil)
// TODO: handle error
// create a client for the specified storage account
client, err := azblob.NewClient(account, cred, nil)
// TODO: handle error
// blob listings are returned across multiple pages
pager := client.NewListBlobsFlatPager(containerName, nil)
// continue fetching pages until no more remain
for pager.More() {
// advance to the next page
page, err := pager.NextPage(context.TODO())
// TODO: handle error
// print the blob names for this page
for _, blob := range page.Segment.BlobItems {
fmt.Println(*blob.Name)
}
}Troubleshooting
All Blob service operations will return an
*azcore.ResponseError on failure with a
populated ErrorCode field. Many of these errors are recoverable.
The bloberror package provides the possible Storage error codes
along with helper facilities for error handling.
const (
connectionString = "<connection_string>"
containerName = "sample-container"
)
// create a client with the provided connection string
client, err := azblob.NewClientFromConnectionString(connectionString, nil)
// TODO: handle error
// try to delete the container, avoiding any potential race conditions with an in-progress or completed deletion
_, err = client.DeleteContainer(context.TODO(), containerName, nil)
if bloberror.HasCode(err, bloberror.ContainerBeingDeleted, bloberror.ContainerNotFound) {
// ignore any errors if the container is being deleted or already has been deleted
} else if err != nil {
// TODO: some other error
}Next steps
Get started with our Blob samples. They contain complete examples of the above snippets and more.
Contributing
See the Storage CONTRIBUTING.md for details on building,
testing, and contributing to this library.
This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution. For
details, visit cla.microsoft.com.
This project has adopted the Microsoft Open Source Code of Conduct.
For more information see the Code of Conduct FAQ
or contact [email protected] with any
additional questions or comments.
Overview (`vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md`)
xxhash
VENDORED: Go to github.com/cespare/xxhash for original package.
xxhash is a Go implementation of the 64-bit xxHash algorithm, XXH64. This is a
high-quality hashing algorithm that is much faster than anything in the Go
standard library.
This package provides a straightforward API:
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
func New() *DigestThe Digest type implements hash.Hash64. Its key methods are:
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64The package is written with optimized pure Go and also contains even faster
assembly implementations for amd64 and arm64. If desired, the purego build tag
opts into using the Go code even on those architectures.
Compatibility
This package is in a module and the latest code is in version 2 of the module.
You need a version of Go with at least "minimal module compatibility" to use
github.com/cespare/xxhash/v2:
- 1.9.7+ for Go 1.9
- 1.10.3+ for Go 1.10
- Go 1.11 or later
I recommend using the latest release of Go.
Benchmarks
Here are some quick benchmarks comparing the pure-Go and assembly
implementations of Sum64.
| input size | purego | asm |
|---|---|---|
| 4 B | 1.3 GB/s | 1.2 GB/s |
| 16 B | 2.9 GB/s | 3.5 GB/s |
| 100 B | 6.9 GB/s | 8.1 GB/s |
| 4 KB | 11.7 GB/s | 16.7 GB/s |
| 10 MB | 12.0 GB/s | 17.3 GB/s |
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
CPU using the following commands under Go 1.19.2:
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')Projects using this package
Overview (`vendor/github.com/redis/go-redis/extra/redisotel/v9/README.md`)
OpenTelemetry instrumentation for go-redis
Installation
go get github.com/redis/go-redis/extra/redisotel/v9Usage
Tracing is enabled by adding a hook:
import (
"github.com/redis/go-redis/v9"
"github.com/redis/go-redis/extra/redisotel/v9"
)
rdb := rdb.NewClient(&rdb.Options{...})
// Enable tracing instrumentation.
if err := redisotel.InstrumentTracing(rdb); err != nil {
panic(err)
}
// Enable metrics instrumentation.
if err := redisotel.InstrumentMetrics(rdb); err != nil {
panic(err)
}See example and
Monitoring Go Redis Performance and Errors
for details.
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/README.md`)
OTLP Log gRPC Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/README.md`)
OTLP Log HTTP Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/README.md`)
OTLP Metric gRPC Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/README.md`)
OTLP Metric HTTP Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/README.md`)
OTLP Trace gRPC Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/README.md`)
OTLP Trace HTTP Exporter
Overview (`vendor/go.opentelemetry.io/otel/exporters/prometheus/internal/x/README.md`)
Experimental Features
The prometheus exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the prometheus exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These features may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The prometheus exporter can be configured to provide observability about itself using OpenTelemetry metrics.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the SDK will create the following metrics using the global MeterProvider:
otel.sdk.exporter.metric_data_point.inflightotel.sdk.exporter.metric_data_point.exportedotel.sdk.metric_reader.collection.durationotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/sdk/log/internal/x/README.md`)
Experimental Features
The Logs SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go Logs SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These feature may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The Logs SDK can be configured to provide observability about itself using OpenTelemetry metrics.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the SDK will create the following metrics using the global MeterProvider:
otel.sdk.log.createdotel.sdk.processor.log.queue.capacityotel.sdk.processor.log.queue.sizeotel.sdk.processor.log.processed
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/sdk/metric/internal/x/README.md`)
Experimental Features
The Metric SDK contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the OpenTelemetry Go Metric SDK prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These feature may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Metric Export Batch Size
The metric export can be split into batches before exporting by specifying a maximum number of data points per batch.
This experimental feature can be enabled by setting the OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE environment variable.
The value MUST be a positive integer.
All other values or an empty value will result in the default behavior of not batching.
Examples
Enable metrics to be batched by maximum export batch size of 200.
export OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE=200Disable metric export batching.
unset OTEL_GO_X_METRIC_EXPORT_BATCH_SIZECompatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/README.md`)
HTTP JSON Error Schema
The error.proto represents the HTTP-JSON schema used by Google APIs to convey
error payloads as described by https://cloud.google.com/apis/design/errors#http_mapping.
This package is for internal parsing logic only and should not be used in any
other context.
Regeneration
To regenerate the protobuf Go code you will need the following:
- A local copy of googleapis, the absolute path to which should be exported to
the environment variableGOOGLEAPIS - The protobuf compiler protoc
- The Go protobuf plugin
- The goimports tool
From this directory run the following command:
protoc -I $GOOGLEAPIS -I. --go_out=. --go_opt=module=github.com/googleapis/gax-go/v2/apierror/internal/proto error.proto
goimports -w .Note: the module plugin option ensures the generated code is placed in this
directory, and not in several nested directories defined by go_package option.
Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutlog/internal/x/README.md`)
Experimental Features
The stdoutlog exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the stdoutlog exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These features may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The stdoutlog exporter can be configured to provide observability about itself using OpenTelemetry metrics.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the exporter will create the following metrics using the global MeterProvider:
otel.sdk.exporter.log.inflightotel.sdk.exporter.log.exportedotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdoutmetric/internal/x/README.md`)
Experimental Features
The stdoutmetric exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the stdoutmetric exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These feature may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The stdoutmetric exporter provides an observability feature that allows you to monitor the exporter itself.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the exporter will create the following metrics using the global MeterProvider:
otel.sdk.exporter.metric_data_point.inflightotel.sdk.exporter.metric_data_point.exportedotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/exporters/stdout/stdouttrace/internal/x/README.md`)
Experimental Features
The stdouttrace exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the stdouttrace exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These features may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The stdouttrace exporter can be configured to provide observability about itself using OpenTelemetry metrics.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the SDK will create the following metrics using the global MeterProvider:
otel.sdk.exporter.span.inflightotel.sdk.exporter.span.exportedotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc/internal/x/README.md`)
Experimental Features
The otlploggrpc exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the otlploggrpc exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These features may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The otlploggrpc exporter can be configured to provide observability about itself using OpenTelemetry metrics.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the exporter will create the following metrics using the global MeterProvider:
otel.sdk.exporter.log.inflightotel.sdk.exporter.log.exportedotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp/internal/x/README.md`)
Experimental Features
The otlploghttp exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the otlploghttp exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These features may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The otlploghttp exporter can be configured to provide observability about itself using OpenTelemetry metrics.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the exporter will create the following metrics using the global MeterProvider:
otel.sdk.exporter.log.inflightotel.sdk.exporter.log.exportedotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Overview (`vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/x/README.md`)
Experimental Features
The otlptracegrpc exporter contains features that have not yet stabilized in the OpenTelemetry specification.
These features are added to the otlptracegrpc exporter prior to stabilization in the specification so that users can start experimenting with them and provide feedback.
These feature may change in backwards incompatible ways as feedback is applied.
See the Compatibility and Stability section for more information.
Features
Observability
The otlptracegrpc exporter provides a observability feature that allows you to monitor the SDK itself.
To opt-in, set the environment variable OTEL_GO_X_OBSERVABILITY to true.
When enabled, the SDK will create the following metrics using the global MeterProvider:
otel.sdk.exporter.span.inflightotel.sdk.exporter.span.exportedotel.sdk.exporter.operation.duration
Please see the Semantic conventions for OpenTelemetry SDK metrics documentation for more details on these metrics.
Compatibility and Stability
Experimental features do not fall within the scope of the OpenTelemetry Go versioning and stability policy.
These features may be removed or modified in successive version releases, including patch versions.
When an experimental feature is promoted to a stable feature, a migration path will be included in the changelog entry of the release.
There is no guarantee that any environment variable feature flags that enabled the experimental feature will be supported by the stable version.
If they are supported, they may be accompanied with a deprecation notice stating a timeline for the removal of that support.
Content Index (`docs/content/_index.md`)
keywords: registry, on-prem, images, tags, repository, distribution title: Distribution Registry
What it is
The Registry is a stateless, highly scalable server side application that stores
and lets you distribute container images and other content. The Registry is open-source, under the
permissive Apache license.
Why use it
You should use the Registry if you want to:
- tightly control where your images are being stored
- fully own your images distribution pipeline
- integrate image storage and distribution tightly into your in-house development workflow
Alternatives
Users looking for a zero maintenance, ready-to-go solution are encouraged to
use one of the existing registry services. Many of these provide support and security
scanning, and are free for public repositories. For example:
Cloud infrastructure providers such as AWS, Azure, Google Cloud and IBM Cloud also have container registry services available at a cost.
Compatibility
The distribution registry implements the OCI Distribution Spec version 1.0.1.
Basic commands
Start your registry
docker run -d -p 5000:5000 --name registry registry:3Pull (or build) some image from the hub
docker pull ubuntuTag the image so that it points to your registry
docker image tag ubuntu localhost:5000/myfirstimagePush it
docker push localhost:5000/myfirstimagePull it back
docker pull localhost:5000/myfirstimageNow stop your registry and remove all data
docker container stop registry && docker container rm -v registryNext
You should now read the detailed introduction about the registry,
or jump directly to deployment instructions.
Content About Index (`docs/content/about/_index.md`)
keywords: registry, on-prem, images, tags, repository, distribution, use cases, requirements title: About Registry
A registry is a storage and content delivery system, holding named container
images and other content, available in different tagged versions.
Example: the image
distribution/registry, with tags2.8and3.0.
Users interact with a registry by pushing and pulling images.
Example:
docker pull registry-1.docker.io/distribution/registry:3.0.
Storage itself is delegated to drivers. The default storage driver is the local
posix filesystem, which is suitable for development or small deployments.
Additional cloud-based storage drivers like S3, Microsoft Azure and Google Cloud Storage
are supported. People looking into using other storage drivers should consider if
the driver they'd like to be supported is S3 compatible like many cloud storage systems
as adding new storage driver support has been put on hold for the time being.
Since securing access to your hosted images is paramount, the Registry natively
supports TLS and basic authentication.
The Registry GitHub repository includes additional information about advanced
authentication and authorization methods. Only very large or public deployments
are expected to extend the Registry in this way.
Finally, the Registry ships with a robust notification system,
calling webhooks in response to activity, and both extensive logging and reporting,
mostly useful for large installations that want to collect metrics.
Understanding image naming
Image names as used in typical docker commands reflect their origin:
docker pull ubuntuinstructs docker to pull an image namedubuntufrom Docker Hub. This is simply a shortcut for the longerdocker pull docker.io/library/ubuntucommanddocker pull myregistrydomain:port/foo/barinstructs docker to contact the registry located atmyregistrydomain:portto find the imagefoo/bar
You can find out more about the various Docker commands dealing with images in
the Docker engine documentation.
Use cases
Running your own Registry is a great solution to integrate with and complement
your CI/CD system. In a typical workflow, a commit to your source revision
control system would trigger a build on your CI system, which would then push a
new image to your Registry if the build is successful. A notification from the
Registry would then trigger a deployment on a staging environment, or notify
other systems that a new image is available.
It's also an essential component if you want to quickly deploy a new image over
a large cluster of machines.
Finally, it's the best way to distribute images inside an isolated network.
Requirements
You absolutely need to be familiar with Docker, specifically with regard to
pushing and pulling images. You must understand the difference between the
daemon and the cli, and at least grasp basic concepts about networking.
Also, while just starting a registry is fairly easy, operating it in a
production environment requires operational skills, just like any other service.
You are expected to be familiar with systems availability and scalability,
logging and log processing, systems monitoring, and security 101. Strong
understanding of http and overall network communications, plus familiarity with
golang are certainly useful as well for advanced operations or hacking.
Next
Dive into deploying your registry
Content Recipes Index (`docs/content/recipes/_index.md`)
keywords: registry, on-prem, images, tags, repository, distribution, recipes, advanced title: Recipes overview
This list of "recipes" provides end-to-end scenarios for exotic or otherwise advanced use-cases.
These recipes are not useful for most standard set-ups.
Requirements
Before following these steps, work through the deployment guide.
At this point, it's assumed that:
- you understand Docker security requirements, and how to configure your docker engines properly
- you have installed Docker Compose
- it's HIGHLY recommended that you get a certificate from a known CA instead of self-signed certificates
- inside the current directory, you have a X509
domain.crtanddomain.key, for the CNmyregistrydomain.com - be sure you have stopped and removed any previously running registry (typically
docker container stop registry && docker container rm -v registry)
The List
- using Apache as an authenticating proxy
- using Nginx as an authenticating proxy
- running a Registry on macOS
- mirror the Docker Hub
- start registry via systemd
Content Spec Index (`docs/content/spec/_index.md`)
title: "Reference Overview" keywords: registry, service, images, repository, json
Docker Registry Reference
Content Storage Drivers Index (`docs/content/storage-drivers/_index.md`)
keywords: registry, on-prem, images, tags, repository, distribution, storage drivers, advanced title: Registry storage driver
This document describes the registry storage driver model, implementation, and explains how to contribute new storage drivers.
Provided drivers
This storage driver package comes bundled with several drivers:
- inmemory: A temporary storage driver using a local inmemory map. This exists solely for reference and testing.
- filesystem: A local storage driver configured to use a directory tree in the local filesystem.
- s3: A driver storing objects in an Amazon Simple Storage Service (S3) bucket.
- azure: A driver storing objects in Microsoft Azure Blob Storage.
- gcs: A driver storing objects in a Google Cloud Storage bucket.
- oss: NO LONGER SUPPORTED
- swift: NO LONGER SUPPORTED
Storage driver API
The storage driver API is designed to model a filesystem-like key/value storage in a manner abstract enough to support a range of drivers from the local filesystem to Amazon S3 or other distributed object storage systems.
Storage drivers are required to implement the storagedriver.StorageDriver interface provided in storagedriver.go, which includes methods for reading, writing, and deleting content, as well as listing child objects of a specified prefix key.
Storage drivers are intended to be written in Go, providing compile-time
validation of the storagedriver.StorageDriver interface.
Driver selection and configuration
The preferred method of selecting a storage driver is using the StorageDriverFactory interface in the storagedriver/factory package. These factories provide a common interface for constructing storage drivers with a parameters map. The factory model is based on the Register and Open methods in the builtin database/sql package.
Storage driver factories may be registered by name using thefactory.Register method, and then later invoked by calling factory.Create
with a driver name and parameters map. If no such storage driver can be found,factory.Create returns an InvalidStorageDriverError.
Driver contribution
New storage drivers are not currently being accepted.
See https://github.com/distribution/distribution/issues/3988 for discussion.
There are forks of this repo that implement custom storage drivers.
These are not supported by the OCI distribution project.
The known forks are:
- Storj DCS: https://github.com/storj/docker-registry
- HuaweiCloud OBS: https://github.com/setoru/distribution/tree/obs
- us3: https://github.com/lambertxiao/distribution/tree/main
- Baidu BOS: https://github.com/dolfly/distribution/tree/bos
- HDFS: https://github.com/haosdent/distribution/tree/master
Writing new storage drivers
To create a valid storage driver, one must implement thestoragedriver.StorageDriver interface and make sure to expose this driver
via the factory system.
Registering
Storage drivers should call factory.Register with their driver name in an init method, allowing callers of factory.New to construct instances of this driver without requiring modification of imports throughout the codebase.
Testing
Storage driver test suites are provided instoragedriver/testsuites/testsuites.go and may be used for any storage
driver written in Go. Tests can be registered using the RegisterSuite
function, which run the same set of tests for any registered drivers.
Content Spec Auth Index (`docs/content/spec/auth/_index.md`)
title: "Distribution Registry Token Authentication" keywords: registry, on-prem, images, tags, repository, distribution, authentication, advanced
Distribution Registry v2 authentication
See the Token Authentication Specification,
Token Authentication Implementation,
Token Scope Documentation,
OAuth2 Token Authentication for more information.
Content Storage Drivers Middleware Index (`docs/content/storage-drivers/middleware/_index.md`)
keywords: registry, on-prem, images, tags, repository, distribution, storage drivers, advanced title: Storage middleware
This document describes the registry storage middleware.
Provided middleware
This storage driver package comes bundled with several middleware options:
- cloudfront
- redirect
- rewrite: Partially rewrites the URL returned by the storage driver.
.Htmltest.Yml (`docs/.htmltest.yml`)
DirectoryPath: "public"
EnforceHTTPS: true
CheckDoctype: true
CheckExternal: true
IgnoreAltMissing: true
IgnoreAltEmpty: true
IgnoreEmptyHref: true
IgnoreInternalEmptyHash: true
IgnoreDirectoryMissingTrailingSlash: true
Dockerhub (`docs/dockerhub.md`)
Distribution
This repository provides container images for the Open Source Registry implementation for storing and distributing container artifacts in conformance with the
OCI Distribution Specification.
Quick start
Run the registry locally with the default configuration:
docker run -d -p 5000:5000 --restart always --name registry distribution/distribution:edgeNOTE: in order to run push/pull against the locally run registry you must allow
your docker (containerd) engine to use insecure registry by editing /etc/docker/daemon.json and subsequently restarting it
{
"insecure-registries": ["host.docker.internal:5000"]
}Now you are ready to use it:
docker pull alpine
docker tag alpine localhost:5000/alpine
docker push localhost:5000/alpine⚠️ Beware the default configuration uses filesystem storage driver
and the above example command does not mount a local filesystem volume into the running container.
If you wish to mount the local filesystem to the rootdirectory of thefilesystem storage driver run the following command:
docker run -d -p 5000:5000 -v $PWD/FS/PATH:/var/lib/registry --restart always --name registry distribution/distribution:edgeCustom configuration
If you don't wan to use the default configuration file, you can supply
your own custom configuration file as follows:
docker run -d -p 5000:5000 -v $PWD/PATH/TO/config.yml:/etc/distribution/config.yml --restart always --name registry distribution/distribution:edgeCommunication
For async communication and long-running discussions please use issues and pull requests
on the GitHub repo.
For sync communication we have a #distribution channel in the CNCF Slack
that everyone is welcome to join and chat about development.
Hugo.Yaml (`docs/hugo.yaml`)
baseURL: https://distribution.github.io/distribution
languageCode: en-us
title: CNCF Distribution
theme: hugo-geekdoc
markup:
goldmark:
renderer:
unsafe: true
pluralizeListTitles: false
enableRobotsTXT: true
taxonomies: [tags]
minify:
disableHTML: true
Geekdoc required configuration
pygmentsUseClasses: true
pygmentsCodeFences: true
disablePathToLower: true
params:
geekdocRepo: "https://github.com/distribution/distribution"
geekdocEditPath: edit/main/docs
geekdocLegalNotice: "https://www.linuxfoundation.org/legal/trademark-usage"
geekdocContentLicense:
name: CC BY 4.0
link: https://creativecommons.org/licenses/by/4.0/
Content About Architecture (`docs/content/about/architecture.md`)
draft: true
Architecture
Design
TODO(stevvooe): Discuss the architecture of the registry, internally and externally, in a few different deployment scenarios.
Eventual Consistency
NOTE: This section belongs somewhere, perhaps in a design document. We
are leaving this here so the information is not lost.
Running the registry on eventually consistent backends has been part of the
design from the beginning. This section covers some of the approaches to
dealing with this reality.
There are a few classes of issues that we need to worry about when
implementing something on top of the storage drivers:
- Read-After-Write consistency (see this article on
s3). - Write-Write Conflicts.
In reality, the registry must worry about these kinds of errors when doing the
following:
- Accepting data into a temporary upload file may not have latest data block
yet (read-after-write). - Moving uploaded data into its blob location (write-write race).
- Modifying the "current" manifest for given tag (write-write race).
- A whole slew of operations around deletes (read-after-write, delete-write
races, garbage collection, etc.).
The backend path layout employs a few techniques to avoid these problems:
- Large writes are done to private upload directories. This alleviates most
of the corruption potential under multiple writers by avoiding multiple
writers. - Constraints in storage driver implementations, such as support for writing
after the end of a file to extend it. - Digest verification to avoid data corruption.
- Manifest files are stored by digest and cannot change.
- All other non-content files (links, hashes, etc.) are written as an atomic
unit. Anything that requires additions and deletions is broken out into
separate "files". Last writer still wins.
Unfortunately, one must play this game when trying to build something like
this on top of eventually consistent storage systems. If we run into serious
problems, we can wrap the storagedrivers in a shared consistency layer but
that would increase complexity and hinder registry cluster performance.
Content About Compatibility (`docs/content/about/compatibility.md`)
keywords: registry, manifest, images, tags, repository, distribution, digest title: Registry compatibility
Synopsis
If a manifest is pulled by digest from a registry 2.3 with Docker Engine 1.9
and older, and the manifest was pushed with Docker Engine 1.10, a security check
causes the Engine to receive a manifest it cannot use and the pull fails.
Registry manifest support
Historically, the registry has supported a single manifest type
known as Schema 1.
With the move toward multiple architecture images, the distribution project
introduced two new manifest types: Schema 2 manifests and manifest lists. Registry
2.3 supports all three manifest types and sometimes performs an on-the-fly
transformation of a manifest before serving the JSON in the response, to
preserve compatibility with older versions of Docker Engine.
This conversion has some implications for pulling manifests by digest and this
document enumerates these implications.
Content Addressable Storage (CAS)
Manifests are stored and retrieved in the registry by keying off a digest
representing a hash of the contents. One of the advantages provided by CAS is
security: if the contents are changed, then the digest no longer matches.
This prevents any modification of the manifest by a MITM attack or an untrusted
third party.
When a manifest is stored by the registry, this digest is returned in the HTTP
response headers and, if events are configured, delivered within the event. The
manifest can either be retrieved by the tag, or this digest.
For registry versions 2.2.1 and below, the registry always stores and
serves Schema 1 manifests. Engine 1.10 first
attempts to send a Schema 2 manifest, falling back to sending a
Schema 1 type manifest when it detects that the registry does not
support the new version.
Registry v2.3
Manifest push with Docker 1.10
The Engine constructs a Schema 2 manifest which the
registry persists to disk.
When the manifest is pulled by digest or tag with Docker Engine 1.10, a
Schema 2 manifest is returned. Docker Engine 1.10
understands the new manifest format.
When the manifest is pulled by tag with Docker Engine 1.9 and older, the
manifest is converted on-the-fly to Schema 1 and sent in the
response. The Docker Engine 1.9 is compatible with this older format.
When the manifest is pulled by digest with Docker Engine 1.9 and older, the
same rewriting process does not happen in the registry. If it did,
the digest would no longer match the hash of the manifest and would violate the
constraints of CAS.
For this reason if a manifest is pulled by digest from a registry 2.3 with Docker
Engine 1.9 and older, and the manifest was pushed with Docker Engine 1.10, a
security check causes the Engine to receive a manifest it cannot use and the
pull fails.
Manifest push with Docker 1.9 and older
The Docker Engine constructs a Schema 1 manifest which the
registry persists to disk.
When the manifest is pulled by digest or tag with any Docker version, a
Schema 1 manifest is returned.
Content About Configuration (`docs/content/about/configuration.md`)
title: "Configuring a registry" keywords: registry, on-prem, images, tags, repository, distribution, configuration
The Registry configuration is based on a YAML file, detailed below. While it
comes with sane default values out of the box, you should review it exhaustively
before moving your systems to production.
Override specific configuration options
In a typical setup where you run your registry as a container, you can
specify a configuration variable from the environment by passing -e arguments
to your docker run stanza or from within a Dockerfile using the ENV
instruction.
To override a configuration option, create an environment variable namedREGISTRY_variable where variable is the name of the configuration option
and the _ (underscore) represents indention levels. For example, you can
configure the rootdirectory of the filesystem storage backend:
storage:
filesystem:
rootdirectory: /var/lib/registryTo override this value, set an environment variable like this:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhereThis variable overrides the /var/lib/registry value to the /somewhere
directory.
In order to override elements of a list, provide the index of the element
you wish to change as part of the path to that element. For example, to
configure the hosts list under letsencrypt:
http:
tls:
letsencrypt:
hosts: [myregistryaddress.org]The corresponding environment variable would be:
REGISTRY_HTTP_TLS_LETSENCRYPT_HOSTS_0=registry.example.comNote: Create a base configuration file with environment variables that can
be configured to tweak individual values. Overriding configuration sections
with environment variables is not recommended.
Disable traces export
Currently traces are set to https://localhost:4318/v1/traces by default.
You can control this by setting the environment variable OTEL_TRACES_EXPORTER
to either none or your trace collector.
Overriding the entire configuration file
If the default configuration is not a sound basis for your usage, or if you are
having issues overriding keys from the environment, you can specify an alternate
YAML configuration file by mounting it as a volume in the container.
Typically, create a new configuration file from scratch,named config.yml, then
specify it in the docker run command:
$ docker run -d -p 5000:5000 --restart=always --name registry \
-v `pwd`/config.yml:/etc/distribution/config.yml \
registry:3Use this
example YAML file
as a starting point.
List of configuration options
These are all configuration options for the registry. Some options in the list
are mutually exclusive. Read the detailed reference information about each
option before finalizing your configuration.
/* Detailed source-code truncated for AI context efficiency. */In some instances a configuration option is optional but it contains child
options marked as required. In these cases, you can omit the parent with
all its children. However, if the parent is included, you must also include all
the children marked required.
`version`
version: 0.1The version option is required. It specifies the configuration's version.
It is expected to remain a top-level field, to allow for a consistent version
check before parsing the remainder of the configuration file.
`log`
The log subsection configures the behavior of the logging system. The logging
system outputs everything to stderr. You can adjust the granularity and format
with this configuration section.
log:
accesslog:
disabled: true
level: debug
formatter: text
fields:
service: registry
environment: staging| Parameter | Required | Description |
|---|---|---|
level |
no | Sets the sensitivity of logging output. Permitted values are error, warn, info, and debug. The default is info. |
formatter |
no | This selects the format of logging output. The format primarily affects how keyed attributes for a log line are encoded. Options are text, json, and logstash. The default is text. |
fields |
no | A map of field names to values. These are added to every log line for the context. This is useful for identifying log messages source after being mixed in other systems. |
`accesslog`
accesslog:
disabled: trueWithin log, accesslog configures the behavior of the access logging
system. By default, the access logging system outputs to stdout in
Combined Log Format.
Access logging can be disabled by setting the boolean flag disabled to true.
`hooks`
hooks:
- type: mail
levels:
- panic
options:
smtp:
addr: smtp.sendhost.com:25
username: sendername
password: password
insecure: true
from: [email protected]
to:
- [email protected]The hooks subsection configures the logging hooks' behavior. This subsection
includes a sequence handler which you can use for sending mail, for example.
Refer to loglevel to configure the level of messages printed.
`loglevel`
DEPRECATED: Please use log instead.
loglevel: debugPermitted values are error, warn, info and debug. The default isinfo.
`storage`
/* Detailed source-code truncated for AI context efficiency. */The storage option is required and defines which storage backend is in
use. You must configure exactly one backend. If you configure more, the registry
returns an error. You can choose any of these backend storage drivers:
| Storage driver | Description |
|---|---|
filesystem |
Uses the local disk to store registry files. It is ideal for development and may be appropriate for some small-scale production applications. See the driver's reference documentation. |
azure |
Uses Microsoft Azure Blob Storage. See the driver's reference documentation. |
gcs |
Uses Google Cloud Storage. See the driver's reference documentation. |
s3 |
Uses Amazon Simple Storage Service (S3) and compatible Storage Services. See the driver's reference documentation. |
For testing only, you can use the inmemory storage
driver.
If you would like to run a registry from volatile memory, use thefilesystem driver
on a ramdisk.
If you are deploying a registry on Windows, a Windows volume mounted from the
host is not recommended. Instead, you can use a S3 or Azure backing
data-store. If you do use a Windows volume, the length of the PATH to
the mount point must be within the MAX_PATH limits (typically 255 characters),
or this error will occur:
mkdir /XXX protocol error and your registry will not function properly.`maintenance`
Currently, upload purging and read-only mode are the only maintenance
functions available.
`uploadpurging`
Upload purging is a background process that periodically removes orphaned files
from the upload directories of the registry. Upload purging is enabled by
default. To configure upload directory purging, the following parameters must
be set.
| Parameter | Required | Description |
|---|---|---|
enabled |
yes | Set to true to enable upload purging. Defaults to true. |
age |
yes | Upload directories which are older than this age will be deleted.Defaults to 168h (1 week). |
interval |
yes | The interval between upload directory purging. Defaults to 24h. |
dryrun |
yes | Set dryrun to true to obtain a summary of what directories will be deleted. Defaults to false. |
Note:
ageandintervalare strings containing a number with optional
fraction and a unit suffix. Some examples:45m,2h10m,168h.
`readonly`
If the readonly section under maintenance has enabled set to true,
clients will not be allowed to write to the registry. This mode is useful to
temporarily prevent writes to the backend storage so a garbage collection pass
can be run. Before running garbage collection, the registry should be
restarted with readonly's enabled set to true. After the garbage collection
pass finishes, the registry may be restarted again, this time with readonly
removed from the configuration (or set to false).
`delete`
Use the delete structure to enable the deletion of image blobs and manifests
by digest. It defaults to false, but it can be enabled by writing the following
on the configuration file:
delete:
enabled: true`cache`
Use the cache structure to enable caching of data accessed in the storage
backend. Currently, the only available cache provides fast access to layer
metadata, which uses the blobdescriptor field if configured.
You can set blobdescriptor field to redis or inmemory. If set to redis,a
Redis pool caches layer metadata. If set to inmemory, an in-memory map caches
layer metadata.
NOTE: Formerly,
blobdescriptorwas known aslayerinfo. While these
are equivalent,layerinfohas been deprecated.
If blobdescriptor is set to inmemory, the optional blobdescriptorsize
parameter sets a limit on the number of descriptors to store in the cache.
The default value is 10000. If this parameter is set to 0, the cache is allowed
to grow with no size limit.
`tag`
The tag subsection provides configuration to set concurrency limit for tag lookup.
When user calls into the registry to delete the manifest, which in turn then does a
lookup for all tags that reference the deleted manifest. To find the tag references,
the registry will iterate every tag in the repository and read it's link file to check
if it matches the deleted manifest (i.e. to see if uses the same sha256 digest).
So, the more tags in repository, the worse the performance will be (as there will
be more S3 API calls occurring for the tag directory lookups and tag file reads if
using S3 storage driver).
Therefore, add a single flag concurrencylimit to set concurrency limit to optimize tag
lookup performance under the tag section. When a value is not provided or equal to 0,GOMAXPROCS will be used.
tag:
concurrencylimit: 8`redirect`
The redirect subsection provides configuration for managing redirects from
content backends. For backends that support it, redirecting is enabled by
default. In certain deployment scenarios, you may decide to route all data
through the Registry, rather than redirecting to the backend. This may be more
efficient when using a backend that is not co-located or when a registry
instance is aggressively caching.
To disable redirects, add a single flag disable, set to true
under the redirect section:
redirect:
disable: true`auth`
auth:
silly:
realm: silly-realm
service: silly-service
token:
realm: token-realm
service: token-service
issuer: registry-token-issuer
rootcertbundle: /root/certs/bundle
jwks: /path/to/jwks
signingalgorithms:
- EdDSA
- HS256
- ES512
htpasswd:
realm: basic-realm
path: /path/to/htpasswdThe auth option is optional. Possible auth providers include:
You can configure only one authentication provider.
`silly`
The silly authentication provider is only appropriate for development. It simply checks
for the existence of the Authorization header in the HTTP request. It does not
check the header's value. If the header does not exist, the silly auth
responds with a challenge response, echoing back the realm, service, and scope
for which access was denied.
The following values are used to configure the response:
| Parameter | Required | Description |
|---|---|---|
realm |
yes | The realm in which the registry server authenticates. |
service |
yes | The service being authenticated. |
`token`
Token-based authentication allows you to decouple the authentication system from
the registry. It is an established authentication paradigm with a high degree of
security.
| Parameter | Required | Description |
|---|---|---|
realm |
yes | The realm in which the registry server authenticates. |
service |
yes | The service being authenticated. |
issuer |
yes | The name of the token issuer. The issuer inserts this into the token so it must match the value configured for the issuer. |
rootcertbundle |
yes | The absolute path to the root certificate bundle. This bundle contains the public part of the certificates used to sign authentication tokens. |
autoredirect |
no | When set to true, realm will be set to the Host header of the request as the domain and a path of /auth/token/(or specified by autoredirectpath), the realm URL Scheme will use X-Forwarded-Proto header if set, otherwise it will be set to https. |
autoredirectpath |
no | The path to redirect to if autoredirect is set to true, default: /auth/token/. |
signingalgorithms |
no | A list of token signing algorithms to use for verifying token signatures. If left empty the default list of signing algorithms is used. Please see below for allowed values and default. |
jwks |
no | The absolute path to the JSON Web Key Set (JWKS) file. The JWKS file contains the trusted keys used to verify the signature of authentication tokens. |
Available signingalgorithms:
- EdDSA
- HS256
- HS384
- HS512
- RS256
- RS384
- RS512
- ES256
- ES384
- ES512
- PS256
- PS384
- PS512
Default signingalgorithms:
- EdDSA
- HS256
- HS384
- HS512
- RS256
- RS384
- RS512
- ES256
- ES384
- ES512
- PS256
- PS384
- PS512
Additional notes on rootcertbundle:
- The public key of this certificate will be automatically added to the list of known keys.
- The public key will be identified by its JWK Thumbprint. See RFC 7638 and RFC 8037 for reference.
For more information about Token based authentication configuration, see the
specification.
`htpasswd`
The htpasswd authentication backed allows you to configure basic
authentication using an
Apache htpasswd file.
The only supported password format isbcrypt. Entries with other hash types
are ignored. The htpasswd file is loaded once, at startup. If the file is
invalid, the registry will display an error and will not start.
Warning: If the
htpasswdfile is missing, the file will be created and provisioned with a default user and automatically generated password.
The password will be printed to stdout.
Warning: Only use the
htpasswdauthentication scheme with TLS
configured, since basic authentication sends passwords as part of the HTTP
header.
| Parameter | Required | Description |
|---|---|---|
realm |
yes | The realm in which the registry server authenticates. |
path |
yes | The path to the htpasswd file to load at startup. |
`middleware`
The middleware structure is optional. Use this option to inject middleware at
named hook points. Each middleware must implement the same interface as the
object it is wrapping. For instance, a registry middleware must implement thedistribution.Namespace interface, while a repository middleware must implementdistribution.Repository, and a storage middleware must implementdriver.StorageDriver.
This is an example configuration of the cloudfront middleware, a storage
middleware:
middleware:
registry:
- name: ARegistryMiddleware
options:
foo: bar
repository:
- name: ARepositoryMiddleware
options:
foo: bar
storage:
- name: cloudfront
options:
baseurl: https://my.cloudfronted.domain.com/
privatekey: /path/to/pem
keypairid: cloudfrontkeypairid
duration: 3000s
ipfilteredby: awsregion
awsregion: us-east-1, use-east-2
updatefrequency: 12h
iprangesurl: https://ip-ranges.amazonaws.com/ip-ranges.jsonEach middleware entry has name and options entries. The name must
correspond to the name under which the middleware registers itself. Theoptions field is a map that details custom configuration required to
initialize the middleware. It is treated as a map[string]interface{}. As such,
it supports any interesting structures desired, leaving it up to the middleware
initialization function to best determine how to handle the specific
interpretation of the options.
`cloudfront`
| Parameter | Required | Description |
|---|---|---|
baseurl |
yes | The SCHEME://HOST[/PATH] at which Cloudfront is served. |
privatekey |
yes | The private key for Cloudfront, provided by AWS. |
keypairid |
yes | The key pair ID provided by AWS. |
duration |
no | An integer and unit for the duration of the Cloudfront session. Valid time units are ns, us (or µs), ms, s, m, or h. For example, 3000s is valid, but 3000 s is not. If you do not specify a duration or you specify an integer without a time unit, the duration defaults to 20m (20 minutes). |
ipfilteredby |
no | A string with the following value none, aws or awsregion. |
awsregion |
no | A comma separated string of AWS regions, only available when ipfilteredby is awsregion. For example, us-east-1, us-west-2 |
updatefrequency |
no | The frequency to update AWS IP regions, default: 12h |
iprangesurl |
no | The URL contains the AWS IP ranges information, default: https://ip-ranges.amazonaws.com/ip-ranges.json |
Value of ipfilteredby can be:
| Value | Description |
|---|---|
none |
default, do not filter by IP |
aws |
IP from AWS goes to S3 directly |
awsregion |
IP from certain AWS regions goes to S3 directly, use together with awsregion. |
`redirect`
You can use the redirect storage middleware to specify a custom URL to a
location of a proxy for the layer stored by the S3 storage driver.
| Parameter | Required | Description |
|---|---|---|
baseurl |
yes | SCHEME://HOST at which layers are served. Can also contain port. For example, https://example.com:5443. |
`catalog`
The catalog subsection provides configuration to limit the maximum number of
entries returned in a single response from the catalog API endpoint
(/v2/_catalog). When a client does not specify the n query parameter, at
most 100 entries are returned. When a client requests more than maxentries
via the n query parameter, the server rejects the request with a400 Bad Request response and a PAGINATION_NUMBER_INVALID error.
The catalog endpoint is designed for registry synchronization with search or
other API systems, and serving a request may put significant load on the
backend storage. It is strongly recommended to keep this endpoint behind
heightened privilege and avoid exposing it to the internet.
catalog:
maxentries: 1000| Parameter | Required | Description |
|---|---|---|
maxentries |
no | Overrides the maximum number of entries returned by the catalog endpoint, default: 1000 |
`tags`
The tags subsection provides configuration to limit the maximum number of tags
returned in a single response from the tags API endpoint. When a client requests
more than maxtags via the n query parameter, the server returns maxtags
results along with a Link header so the client can paginate to retrieve the
rest.
tags:
maxtags: 100| Parameter | Required | Description |
|---|---|---|
maxtags |
no | Overrides the maximum number of tags returned by the tags endpoint, default: 1000 |
`http`
http:
addr: localhost:5000
net: tcp
prefix: /my/nested/registry/
host: https://myregistryaddress.org:5000
secret: asecretforlocaldevelopment
relativeurls: false
draintimeout: 60s
tls:
certificate: /path/to/x509/public
key: /path/to/x509/private
clientcas:
- /path/to/ca.pem
- /path/to/another/ca.pem
clientauth: require-and-verify-client-cert
minimumtls: tls1.2
ciphersuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
letsencrypt:
cachefile: /path/to/cache-file
email: [email protected]
hosts: [myregistryaddress.org]
directoryurl: https://acme-v02.api.letsencrypt.org/directory
debug:
addr: localhost:5001
headers:
X-Content-Type-Options: [nosniff]
http2:
disabled: false
h2c:
enabled: falseThe http option details the configuration for the HTTP server that hosts the
registry.
| Parameter | Required | Description |
|---|---|---|
addr |
no | The address for which the server should accept connections. The form depends on a network type (see the net option). Use HOST:PORT for TCP and FILE for a UNIX socket. The addr field is only optional if socket-activation is used (in which case addr and net are ignored regardless of if they are specified). |
net |
no | The network used to create a listening socket. Known networks are unix and tcp. |
prefix |
no | If the server does not run at the root path, set this to the value of the prefix. The root path is the section before v2. It requires both preceding and trailing slashes, such as in the example /path/. |
host |
no | A fully-qualified URL for an externally-reachable address for the registry. If present, it is used when creating generated URLs. Otherwise, these URLs are derived from client requests. |
secret |
no | A random piece of data used to sign state that may be stored with the client to protect against tampering. For production environments you should generate a random piece of data using a cryptographically secure random generator. If you omit the secret, the registry will automatically generate a secret when it starts. If you are building a cluster of registries behind a load balancer, you MUST ensure the secret is the same for all registries. |
relativeurls |
no | If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. This option is not compatible with Docker 1.7 and earlier. |
draintimeout |
no | Amount of time to wait for HTTP connections to drain before shutting down after registry receives SIGTERM signal |
`tls`
The tls structure within http is optional. Use this to configure TLS
for the server. If you already have a web server running on
the same host as the registry, you may prefer to configure TLS on that web server
and proxy connections to the registry server.
| Parameter | Required | Description |
|---|---|---|
certificate |
yes | Absolute path to the x509 certificate file. |
key |
yes | Absolute path to the x509 private key file. |
clientcas |
no | An array of absolute paths to x509 CA files. |
clientauth |
no | Client certificate authentication mode. This setting determines how the server handles client certificates during the TLS handshake. If clientcas is not provided, TLS Client Authentication is disabled, and the mode is ignored. Allowed (request-client-cert, require-any-client-cert, verify-client-cert-if-given, require-and-verify-client-cert). Defaults to require-and-verify-client-cert |
minimumtls |
no | Minimum TLS version allowed (tls1.0, tls1.1, tls1.2, tls1.3). Defaults to tls1.2 |
ciphersuites |
no | Cipher suites allowed. Please see below for allowed values and default. |
Available cipher suites:
- TLS_RSA_WITH_RC4_128_SHA
- TLS_RSA_WITH_3DES_EDE_CBC_SHA
- TLS_RSA_WITH_AES_128_CBC_SHA
- TLS_RSA_WITH_AES_256_CBC_SHA
- TLS_RSA_WITH_AES_128_CBC_SHA256
- TLS_RSA_WITH_AES_128_GCM_SHA256
- TLS_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
- TLS_ECDHE_RSA_WITH_RC4_128_SHA
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
Default cipher suites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_AES_128_GCM_SHA256
- TLS_CHACHA20_POLY1305_SHA256
- TLS_AES_256_GCM_SHA384
`letsencrypt`
The letsencrypt structure within tls is optional. Use this to configure
TLS certificates provided by
Let's Encrypt.
NOTE: When using Let's Encrypt, ensure that the outward-facing address is
accessible on port443. The registry defaults to listening on port5000.
If you run the registry as a container, consider adding the flag-p 443:5000
to thedocker runcommand or using a similar setting in a cloud
configuration. You should also set thehostsoption to the list of hostnames
that are valid for this registry to avoid trying to get certificates for random
hostnames due to malicious clients connecting with bogus SNI hostnames. Please
ensure that you have theca-certificatespackage installed in order to verify
letsencrypt certificates.
| Parameter | Required | Description |
|---|---|---|
cachefile |
yes | Absolute path to a file where the Let's Encrypt agent can cache data. |
email |
yes | The email address used to register with Let's Encrypt. |
hosts |
no | The hostnames allowed for Let's Encrypt certificates. |
directoryurl |
no | The url to use for the ACME server. |
`debug`
The debug option is optional . Use it to configure a debug server that
can be helpful in diagnosing problems. The debug endpoint can be used for
monitoring registry metrics and health, as well as profiling. Sensitive
information may be available via the debug endpoint. Please be certain that
access to the debug endpoint is locked down in a production environment.
The debug endpoint should not be exposed publicly to the internet.
Instead, keep the debug endpoint private or enforce authentication for it.
The debug section takes a single required addr parameter, which specifies
the HOST:PORT on which the debug server should accept connections.
If configured, notification, redis, and proxy statistics are exposed
at /debug/vars in JSON format.
`prometheus`
prometheus:
enabled: true
path: /metricsThe prometheus option defines whether the prometheus metrics are enabled, as well
as the path to access the metrics.
The prometheus metrics cover storage, notification and proxy statistics.
| Parameter | Required | Description |
|---|---|---|
enabled |
no | Set true to enable the prometheus server |
path |
no | The path to access the metrics, /metrics by default |
The url to access the metrics is HOST:PORT/path, where HOST:PORT is defined
in addr under debug.
`headers`
The headers option is optional . Use it to specify headers that the HTTP
server should include in responses. This can be used for security headers such
as Strict-Transport-Security.
The headers option should contain an option for each header to include, where
the parameter name is the header's name, and the parameter value a list of the
header's payload values.
Including X-Content-Type-Options: [nosniff] is recommended, so that browsers
will not interpret content as HTML if they are directed to load a page from the
registry. This header is included in the example configuration file.
`http2`
The http2 structure within http is optional. Use this to control HTTP/2 over TLS
settings for the registry.
If tls is not configured this option is ignored. To enable HTTP/2 over non TLS connections use h2c instead.
| Parameter | Required | Description |
|---|---|---|
disabled |
no | If true, then http2 support is disabled. |
`h2c`
The h2c structure within http is optional. Use this to control H2C (HTTP/2 Cleartext)
settings for the registry.
Useful when deploying the registry behind a load balancer (e.g. Google Cloud Run)
| Parameter | Required | Description |
|---|---|---|
enabled |
no | If true, then h2c support is enabled. |
`notifications`
notifications:
events:
includereferences: true
endpoints:
- name: alistener
disabled: false
url: https://my.listener.com/event
headers: <http.Header>
timeout: 1s
threshold: 10
backoff: 1s
ignoredmediatypes:
- application/octet-stream
ignore:
mediatypes:
- application/octet-stream
actions:
- pullThe notifications option is optional and currently may contain a single
option, endpoints.
`endpoints`
The endpoints structure contains a list of named services (URLs) that can
accept event notifications.
| Parameter | Required | Description |
|---|---|---|
name |
yes | A human-readable name for the service. |
disabled |
no | If true, notifications are disabled for the service. |
url |
yes | The URL to which events should be published. |
headers |
yes | A list of static headers to add to each request. Each header's name is a key beneath headers, and each value is a list of payloads for that header name. Values must always be lists. |
timeout |
yes | A value for the HTTP timeout. A positive integer and an optional suffix indicating the unit of time, which may be ns, us, ms, s, m, or h. If you omit the unit of time, ns is used. |
threshold |
yes | An integer specifying how long to wait before backing off a failure. |
backoff |
yes | How long the system backs off before retrying after a failure. A positive integer and an optional suffix indicating the unit of time, which may be ns, us, ms, s, m, or h. If you omit the unit of time, ns is used. |
ignoredmediatypes |
no | A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
ignore |
no | Events with these mediatypes or actions are not published to the endpoint. |
`ignore`
| Parameter | Required | Description |
|---|---|---|
mediatypes |
no | A list of target media types to ignore. Events with these target media types are not published to the endpoint. |
actions |
no | A list of actions to ignore. Events with these actions are not published to the endpoint. |
The mediatypes and actions filters work independently. You can specify:
- Only
mediatypesto filter by media type. - Only
actionsto filter by action (e.g.,pull,push,delete,mount) - Both to filter events matching either condition (OR logic)
- Neither to receive all events
Common use case: Set mediatypes: [] with actions: [pull, delete, mount] to receive only push events regardless of media type.
`events`
The events structure configures the information provided in event notifications.
| Parameter | Required | Description |
|---|---|---|
includereferences |
no | If true, include reference information in manifest events. |
`redis`
Declare parameters for constructing the redis connections. Registry instances
may use the Redis instance for several applications. Currently, it caches
information about immutable blobs. Most of the redis options control
how the registry connects to the redis instance.
You must configure Redis with the allkeys-lru eviction policy, because
the registry does not set an expiration value on keys.
Under the hood distribution uses go-redis Go module for
Redis connectivity and its UniversalOptions
struct.
To use Redis Sentinel, set mastername to the name of the monitored Redis master
and addrs to the Sentinel endpoints. Setting mastername selects the
Sentinel-backed failover client; without it, multiple addresses select a Redis
Cluster client instead.
redis:
addrs:
- sentinel1.example.com:26379
- sentinel2.example.com:26379
- sentinel3.example.com:26379
mastername: mymasterThe equivalent environment variable for the master name isREGISTRY_REDIS_MASTERNAME. If authentication is required, use username andpassword for Redis, and sentinelusername and sentinelpassword for Sentinel.
You can optionally specify TLS configuration on top of the UniversalOptions settings.
Use these settings to configure Redis TLS:
| Parameter | Required | Description |
|---|---|---|
certificate |
no | Absolute path to the x509 client certificate file. Required for mTLS. |
key |
no | Absolute path to the x509 client private key file. Required for mTLS. |
rootcas |
no | An array of absolute paths to x509 CA files. |
Note: For server-side TLS only (e.g., AWS Elasticache), provide only rootcas. For mutual TLS (mTLS), provide both certificate and key along with optional rootcas.
# Server-side TLS only (validate server certificate)
redis:
tls:
rootcas:
- /path/to/ca-bundle.crt
addrs: [localhost:6379]
# Mutual TLS (client and server certificates)
redis:
tls:
certificate: /path/to/cert.crt
key: /path/to/key.pem
rootcas:
- /path/to/ca.pem
addrs: [localhost:6379]
password: asecret
db: 0
dialtimeout: 10ms
readtimeout: 10ms
writetimeout: 10ms
maxidleconns: 16
poolsize: 64
connmaxidletime: 300s`health`
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
file:
- file: /path/to/checked/file
interval: 10s
http:
- uri: http://server.to.check/must/return/200
headers:
Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==]
statuscode: 200
timeout: 3s
interval: 10s
threshold: 3
tcp:
- addr: redis-server.domain.com:6379
timeout: 3s
interval: 10s
threshold: 3The health option is optional, and contains preferences for a periodic
health check on the storage driver's backend storage, as well as optional
periodic checks on local files, HTTP URIs, and/or TCP servers. The results of
the health checks are available at the /debug/health endpoint on the debug
HTTP server if the debug HTTP server is enabled (see http section).
`storagedriver`
The storagedriver structure contains options for a health check on the
configured storage driver's backend storage. The health check is only active
when enabled is set to true.
| Parameter | Required | Description |
|---|---|---|
enabled |
yes | Set to true to enable storage driver health checks or false to disable them. |
interval |
no | How long to wait between repetitions of the storage driver health check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of ns, us, ms, s, m, or h. Defaults to 10s if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
threshold |
no | A positive integer which represents the number of times the check must fail before the state is marked as unhealthy. If not specified, a single failure marks the state as unhealthy. |
`file`
The file structure includes a list of paths to be periodically checked for the
existence of a file. If a file exists at the given path, the health check will
fail. You can use this mechanism to bring a registry out of rotation by creating
a file.
| Parameter | Required | Description |
|---|---|---|
file |
yes | The path to check for existence of a file. |
interval |
no | How long to wait before repeating the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of ns, us, ms, s, m, or h. Defaults to 10s if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
`http`
The http structure includes a list of HTTP URIs to periodically check withHEAD requests. If a HEAD request does not complete or returns an unexpected
status code, the health check will fail.
| Parameter | Required | Description |
|---|---|---|
uri |
yes | The URI to check. |
headers |
no | Static headers to add to each request. Each header's name is a key beneath headers, and each value is a list of payloads for that header name. Values must always be lists. |
statuscode |
no | The expected status code from the HTTP URI. Defaults to 200. |
timeout |
no | How long to wait before timing out the HTTP request. A positive integer and an optional suffix indicating the unit of time. The suffix is one of ns, us, ms, s, m, or h. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
interval |
no | How long to wait before repeating the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of ns, us, ms, s, m, or h. Defaults to 10s if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
threshold |
no | The number of times the check must fail before the state is marked as unhealthy. If this field is not specified, a single failure marks the state as unhealthy. |
`tcp`
The tcp structure includes a list of TCP addresses to periodically check using
TCP connection attempts. Addresses must include port numbers. If a connection
attempt fails, the health check will fail.
| Parameter | Required | Description |
|---|---|---|
addr |
yes | The TCP address and port to connect to. |
timeout |
no | How long to wait before timing out the TCP connection. A positive integer and an optional suffix indicating the unit of time. The suffix is one of ns, us, ms, s, m, or h. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
interval |
no | How long to wait between repetitions of the check. A positive integer and an optional suffix indicating the unit of time. The suffix is one of ns, us, ms, s, m, or h. Defaults to 10s if the value is omitted. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
threshold |
no | The number of times the check must fail before the state is marked as unhealthy. If this field is not specified, a single failure marks the state as unhealthy. |
`proxy`
proxy:
remoteurl: https://registry-1.docker.io
username: [username]
password: [password]
ttl: 168hThe proxy structure allows a registry to be configured as a pull-through cache
to an upstream registry such as Docker Hub. See
mirror
for more information. Pushing to a registry configured as a pull-through cache
is unsupported.
| Parameter | Required | Description |
|---|---|---|
remoteurl |
yes | The URL for the repository on Docker Hub. |
ttl |
no | Expire proxy cache configured in "storage" after this time. Cache 168h(7 days) by default, set to 0 to disable cache expiration, The suffix is one of ns, us, ms, s, m, or h. If you specify a value but omit the suffix, the value is interpreted as a number of nanoseconds. |
To enable pulling private repositories (e.g. batman/robin), specify one of the
following authentication methods for the pull-through cache to authenticate with
the upstream registry via the v2 Distribution registry authentication
scheme.]
`username` and `password`
The username and password used to authenticate with the upstream registry to
access the private repositories.
`exec`
Run a custom exec-based Docker credential helper
to retrieve the credentials to authenticate with the upstream registry.
| Parameter | Required | Description |
|---|---|---|
command |
yes | The command to execute. |
lifetime |
no | The expiry period of the credentials. The credentials returned by the command is reused through the configured lifetime, then the command will be re-executed to retrieve new credentials. If set to zero, the command will be executed for every request. If not set, the command will only be executed once. |
Note: These private repositories are stored in the proxy cache's storage.
Take appropriate measures to protect access to the proxy cache.
`validation`
validation:
disabled: falseUse these settings to configure what validation the registry performs on content.
Validation is performed when content is uploaded to the registry. Changing these
settings will not validate content that has already been accepting into the registry.
`disabled`
The disabled flag disables the other options in the validation
section. They are enabled by default. This option deprecates the enabled flag.
`manifests`
Use the manifests subsection to configure validation of manifests. Ifdisabled is false, the validation allows nothing.
`urls`
validation:
manifests:
urls:
allow:
- ^https?://([^/]+\.)*example\.com/
deny:
- ^https?://www\.example\.com/The allow and deny options are each a list of
regular expressions that restrict the URLs in
pushed manifests.
If allow is unset, pushing a manifest containing URLs fails.
If allow is set, pushing a manifest succeeds only if all URLs match
one of the allow regular expressions and one of the following holds:
denyis unset.denyis set but no URLs within the manifest match any of thedenyregular
expressions.
`indexes`
By default the registry will validate that all platform images exist when an image
index is uploaded to the registry. Disabling this validatation is experimental
because other tooling that uses the registry may expect the image index to be complete.
validation:
manifests:
indexes:
platforms: [all|none|list]
platformlist:
- os: linux
architecture: amd64Use these settings to configure what validation the registry performs on image
index manifests uploaded to the registry.
`platforms`
Set platforms to all (the default) to validate all platform images exist.
The registry will validate that the images referenced by the index exist in the
registry before accepting the image index.
Set platforms to none to disable all validation that images exist when an
image index manifest is uploaded. This allows image lists to be uploaded to the
registry without their associated images. This setting is experimental because
other tooling that uses the registry may expect the image index to be complete.
Set platforms to list to selectively validate the existence of platforms
within image index manifests. This setting is experimental because other tooling
that uses the registry may expect the image index to be complete.
`platformlist`
When platforms is set to list, set platformlist to an array of
platforms to validate. If a platform is included in this the array and in the images
contained within an index, the registry will validate that the platform specific image
exists in the registry before accepting the index. The registry will not validate the
existence of platform specific images in the index that do not appear in theplatformlist array.
This parameter does not validate that the configured platforms are included in every
index. If an image index does not include one of the platform specific images configured
in the platformlist array, it may still be accepted by the registry.
Each platform is a map with two keys, os and architecture, as defined in the
OCI Image Index specification.
Example: Development configuration
You can use this simple example for local development:
version: 0.1
log:
level: debug
storage:
filesystem:
rootdirectory: /var/lib/registry
http:
addr: localhost:5000
secret: asecretforlocaldevelopment
debug:
addr: localhost:5001This example configures the registry instance to run on port 5000, binding tolocalhost, with the debug server enabled. Registry data is stored in the/var/lib/registry directory. Logging is set to debug mode, which is the most
verbose.
See
config-example.yml
for another simple configuration. Both examples are generally useful for local
development.
Example: Middleware configuration
This example configures Amazon Cloudfront
as the storage middleware in a registry. Middleware allows the registry to serve
layers via a content delivery network (CDN). This reduces requests to the
storage layer.
Cloudfront requires the S3 storage driver.
This is the configuration expressed in YAML:
middleware:
storage:
- name: cloudfront
disabled: false
options:
baseurl: http://d111111abcdef8.cloudfront.net
privatekey: /path/to/asecret.pem
keypairid: asecret
duration: 60sSee the configuration reference for Cloudfront for more
information about configuration options.
{{< hint type=note >}}
Cloudfront keys exist separately from other AWS keys. See
the documentation on AWS credentials
for more information.
{{< /hint >}}
Content About Deploying (`docs/content/about/deploying.md`)
keywords: registry, on-prem, images, tags, repository, distribution, deployment title: Deploy a registry server
Before you can deploy a registry, you need to install Docker on the host.
A registry is an instance of the registry image, and runs within Docker.
This topic provides basic information about deploying and configuring a
registry. For an exhaustive list of configuration options, see the
configuration reference.
If you have an air-gapped datacenter, see
Considerations for air-gapped registries.
Run a local registry
Use a command like the following to start the registry container:
$ docker run -d -p 5000:5000 --restart=always --name registry registry:3The registry is now ready to use.
Warning: These first few examples show registry configurations that are
only appropriate for testing. A production-ready registry must be protected by
TLS and should ideally use an access-control mechanism. Keep reading and then
continue to the configuration guide to deploy a
production-ready registry.
Note: The default configuration
is designed for development. As such, the log level is set todebug. In
addition, the registry uses OpenTelemetry
for logs and trace. OpenTelemetry integration is configured using standard
environment variables,
and will by default attempt to export telemetry traces to an OTLP collector atlocalhost:4318. If this is not desired, telemetry can be disabled by adding-e OTEL_TRACES_EXPORTER=noneto thedocker runcommand above.
Copy an image from Docker Hub to your registry
You can pull an image from Docker Hub and push it to your registry. The
following example pulls the ubuntu:16.04 image from Docker Hub and re-tags it
as my-ubuntu, then pushes it to the local registry. Finally, theubuntu:16.04 and my-ubuntu images are deleted locally and themy-ubuntu image is pulled from the local registry.
Pull the
ubuntu:16.04image from Docker Hub.console$ docker pull ubuntu:16.04Tag the image as
localhost:5000/my-ubuntu. This creates an additional tag
for the existing image. When the first part of the tag is a hostname and
port, Docker interprets this as the location of a registry, when pushing.console$ docker tag ubuntu:16.04 localhost:5000/my-ubuntuPush the image to the local registry running at
localhost:5000:console$ docker push localhost:5000/my-ubuntuRemove the locally-cached
ubuntu:16.04andlocalhost:5000/my-ubuntu
images, so that you can test pulling the image from your registry. This
does not remove thelocalhost:5000/my-ubuntuimage from your registry.console$ docker image remove ubuntu:16.04 $ docker image remove localhost:5000/my-ubuntuPull the
localhost:5000/my-ubuntuimage from your local registry.console$ docker pull localhost:5000/my-ubuntu
Stop a local registry
To stop the registry, use the same docker container stop command as with any other
container.
$ docker container stop registryTo remove the container, use docker container rm.
$ docker container stop registry && docker container rm -v registryBasic configuration
To configure the container, you can pass additional or modified options to thedocker run command.
The following sections provide basic guidelines for configuring your registry.
For more details, see the registry configuration reference.
Start the registry automatically
If you want to use the registry as part of your permanent infrastructure, you
should set it to restart automatically when Docker restarts or if it exits.
This example uses the --restart always flag to set a restart policy for the
registry.
$ docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
registry:3Customize the published port
If you are already using port 5000, or you want to run multiple local
registries to separate areas of concern, you can customize the registry's
port settings. This example runs the registry on port 5001 and also names itregistry-test. Remember, the first part of the -p value is the host port
and the second part is the port within the container. Within the container, the
registry listens on port 5000 by default.
$ docker run -d \
-p 5001:5000 \
--name registry-test \
registry:3If you want to change the port the registry listens on within the container, you
can use the environment variable REGISTRY_HTTP_ADDR to change it. This command
causes the registry to listen on port 5001 within the container:
$ docker run -d \
-e REGISTRY_HTTP_ADDR=0.0.0.0:5001 \
-p 5001:5001 \
--name registry-test \
registry:3Storage customization
Customize the storage location
By default, your registry data is persisted as a docker volume
on the host filesystem. If you want to store your registry contents at a specific
location on your host filesystem, such as if you have an SSD or SAN mounted into
a particular directory, you might decide to use a bind mount instead. A bind mount
is more dependent on the filesystem layout of the Docker host, but more performant
in many situations. The following example bind-mounts the host directory/mnt/registry into the registry container at /var/lib/registry/.
$ docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
-v /mnt/registry:/var/lib/registry \
registry:3Customize the storage back-end
By default, the registry stores its data on the local filesystem, whether you
use a bind mount or a volume. You can store the registry data in an Amazon S3
bucket, Google Cloud Platform, or on another storage back-end by using
storage drivers. For more information, see
storage configuration options.
Run an externally-accessible registry
Running a registry only accessible on localhost has limited usefulness. In
order to make your registry accessible to external hosts, you must first secure
it using TLS.
This example is extended in Run the registry as a
service below.
Get a certificate
These examples assume the following:
- Your registry URL is
https://myregistry.domain.com/. - Your DNS, routing, and firewall settings allow access to the registry's host
on port 443. - You have already obtained a certificate from a certificate authority (CA).
If you have been issued an intermediate certificate instead, see
use an intermediate certificate.
Create a
certsdirectory.console$ mkdir -p certsCopy the
.crtand.keyfiles from the CA into thecertsdirectory.
The following steps assume that the files are nameddomain.crtanddomain.key.Stop the registry if it is currently running.
console$ docker container stop registryRestart the registry, directing it to use the TLS certificate. This command
bind-mounts thecerts/directory into the container at/certs/, and sets
environment variables that tell the container where to find thedomain.crt
anddomain.keyfile. The registry runs on port 443, the default HTTPS port.console$ docker run -d \ --restart=always \ --name registry \ -v "$(pwd)"/certs:/certs \ -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ -p 443:443 \ registry:3Docker clients can now pull from and push to your registry using its
external address. The following commands demonstrate this:console$ docker pull ubuntu:16.04 $ docker tag ubuntu:16.04 myregistry.domain.com/my-ubuntu $ docker push myregistry.domain.com/my-ubuntu $ docker pull myregistry.domain.com/my-ubuntu
Use an intermediate certificate
A certificate issuer may supply you with an intermediate certificate. In this
case, you must concatenate your certificate with the intermediate certificate to
form a certificate bundle. You can do this using the cat command:
cat domain.crt intermediate-certificates.pem > certs/domain.crtYou can use the certificate bundle just as you use the domain.crt file in
the previous example.
Support for Let's Encrypt
The registry supports using Let's Encrypt to automatically obtain a
browser-trusted certificate. For more information on Let's Encrypt, see
https://letsencrypt.org/how-it-works/
and the relevant section of the
registry configuration.
Use an insecure registry (testing only)
It is possible to use a self-signed certificate, or to use our registry
insecurely. Unless you have set up verification for your self-signed
certificate, this is for testing only. See run an insecure registry.
Run the registry as a service
Swarm services provide several advantages over
standalone containers. They use a declarative model, which means that you define
the desired state and Docker works to keep your service in that state. Services
provide automatic load balancing scaling, and the ability to control the
distribution of your service, among other advantages. Services also allow you to
store sensitive data such as TLS certificates in
secrets.
The storage back-end you use determines whether you use a fully scaled service
or a service with either only a single node or a node constraint.
If you use a distributed storage driver, such as Amazon S3, you can use a
fully replicated service. Each worker can write to the storage back-end
without causing write conflicts.If you use a local bind mount or volume, each worker node writes to its
own storage location, which means that each registry contains a different
data set. You can solve this problem by using a single-replica service and a
node constraint to ensure that only a single worker is writing to the bind
mount.
The following example starts a registry as a single-replica service, which is
accessible on any swarm node on port 80. It assumes you are using the same
TLS certificates as in the previous examples.
First, save the TLS certificate and key as secrets:
$ docker secret create domain.crt certs/domain.crt
$ docker secret create domain.key certs/domain.keyNext, add a label to the node where you want to run the registry.
To get the node's name, use docker node ls. Substitute your node's name fornode1 below.
$ docker node update --label-add registry=true node1Next, create the service, granting it access to the two secrets and constraining
it to only run on nodes with the label registry=true. Besides the constraint,
you are also specifying that only a single replica should run at a time. The
example bind-mounts /mnt/registry on the swarm node to /var/lib/registry/
within the container. Bind mounts rely on the pre-existing source directory,
so be sure /mnt/registry exists on node1. You might need to create it before
running the following docker service create command.
By default, secrets are mounted into a service at /run/secrets/<secret-name>.
$ docker service create \
--name registry \
--secret domain.crt \
--secret domain.key \
--constraint 'node.labels.registry==true' \
--mount type=bind,src=/mnt/registry,dst=/var/lib/registry \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/run/secrets/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/run/secrets/domain.key \
--publish published=443,target=443 \
--replicas 1 \
registry:3You can access the service on port 443 of any swarm node. Docker sends the
requests to the node which is running the service.
Load balancing considerations
One may want to use a load balancer to distribute load, terminate TLS or
provide high availability. While a full load balancing setup is outside the
scope of this document, there are a few considerations that can make the process
smoother.
The most important aspect is that a load balanced cluster of registries must
share the same resources. For the current version of the registry, this means
the following must be the same:
- Storage Driver
- HTTP Secret
- Redis Cache (if configured)
Differences in any of the above cause problems serving requests.
As an example, if you're using the filesystem driver, all registry instances
must have access to the same filesystem root, on
the same machine. For other drivers, such as S3 or Azure, they should be
accessing the same resource and share an identical configuration.
The HTTP Secret coordinates uploads, so also must be the same across
instances. Configuring different redis instances works (at the time
of writing), but is not optimal if the instances are not shared, because
more requests are directed to the backend.
Important/Required HTTP-Headers
Getting the headers correct is very important. For all responses to any
request under the "/v2/" url space, the Docker-Distribution-API-Version
header should be set to the value "registry/2.0", even for a 4xx response.
This header allows the docker engine to quickly resolve authentication realms
and fallback to version 1 registries, if necessary. Confirming this is setup
correctly can help avoid problems with fallback.
In the same train of thought, you must make sure you are properly sending theX-Forwarded-Proto, X-Forwarded-For, and Host headers to their "client-side"
values. Failure to do so usually makes the registry issue redirects to internal
hostnames or downgrading from https to http.
A properly secured registry should return 401 when the "/v2/" endpoint is hit
without credentials. The response should include a WWW-Authenticate
challenge, providing guidance on how to authenticate, such as with basic auth
or a token service. If the load balancer has health checks, it is recommended
to configure it to consider a 401 response as healthy and any other as down.
This secures your registry by ensuring that configuration problems with
authentication don't accidentally expose an unprotected registry. If you're
using a less sophisticated load balancer that doesn't allow one to change
the healthy response code, health checks can be directed at "/", which always
returns a 200 OK response.
Restricting access
Except for registries running on secure local networks, registries should always
implement access restrictions.
Native basic auth
The simplest way to achieve access restriction is through basic authentication
(this is very similar to other web servers' basic authentication mechanism).
This example uses native basic authentication using htpasswd to store the
secrets.
{{< hint type=warning >}}
You cannot use authentication with authentication schemes that send
credentials as clear text. You must
configure TLS first for
authentication to work.
{{< /hint >}}
{{< hint type=warning >}}
The distribution registry only supports htpasswd credentials in
bcrypt format, so if you omit the -B option when generating the credential
using htpasswd, all authentication attempts will fail.
{{< /hint >}}
Create a password file with one entry for the user
testuser, with passwordtestpassword:console$ mkdir auth $ docker run \ --entrypoint htpasswd \ httpd:2 -Bbn testuser testpassword > auth/htpasswdOn Windows, make sure the output file is correctly encoded:
powershelldocker run --rm --entrypoint htpasswd httpd:2 -Bbn testuser testpassword | Set-Content -Encoding ASCII auth/htpasswdStop the registry.
console$ docker container stop registryStart the registry with basic authentication.
console$ docker run -d \ -p 5000:5000 \ --restart=always \ --name registry \ -v "$(pwd)"/auth:/auth \ -e "REGISTRY_AUTH=htpasswd" \ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ -v "$(pwd)"/certs:/certs \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ registry:3Try to pull an image from the registry, or push an image to the registry.
These commands fail.Log in to the registry.
console$ docker login myregistrydomain.com:5000Provide the username and password from the first step.
Test that you can now pull an image from the registry or push an image to
the registry.
{{< hint type=note title="X509 errors" >}}
X509 errors usually indicate that you are attempting to use
a self-signed certificate without configuring the Docker daemon correctly.
See run an insecure registry.
{{< /hint >}}
More advanced authentication
You may want to leverage more advanced basic auth implementations by using a
proxy in front of the registry. See the recipes list.
The registry also supports delegated authentication which redirects users to a
specific trusted token server. This approach is more complicated to set up, and
only makes sense if you need to fully configure ACLs and need more control over
the registry's integration into your global authorization and authentication
systems. Refer to the following background information and
configuration information here.
This approach requires you to implement your own authentication system or
leverage a third-party implementation.
Deploy your registry using a Compose file
If your registry invocation is advanced, it may be easier to use a Docker
compose file to deploy it, rather than relying on a specific docker run
invocation. Use the following example docker-compose.yml as a template.
services:
registry:
restart: always
image: registry:3
ports:
- 5000:5000
environment:
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
REGISTRY_HTTP_TLS_KEY: /certs/domain.key
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
volumes:
- /path/data:/var/lib/registry
- /path/certs:/certs
- /path/auth:/auth{{< hint type=warning >}}
Replace /path with the directory which contains the certs/ and auth/
directories.
{{< /hint >}}
Start your registry by issuing the following command in the directory containing
the docker-compose.yml file:
$ docker compose up -dConsiderations for air-gapped registries
You can run a registry in an environment with no internet connectivity.
However, if you rely on any images which are not local, you need to consider the
following:
You may need to build your local registry's data volume on a connected
host where you can rundocker pullto get any images which are available
remotely, and then migrate the registry's data volume to the air-gapped
network.Certain images, such as the official Microsoft Windows base images, are not
distributable. This means that when you push an image based on one of these
images to your private registry, the non-distributable layers are not
pushed, but are always fetched from their authorized location. This is fine
for internet-connected hosts, but not in an air-gapped set-up.You can configure the Docker daemon to allow pushing non-distributable layers
to private registries.
This is only useful in air-gapped set-ups in the presence of
non-distributable images, or in extremely bandwidth-limited situations.
You are responsible for ensuring that you are in compliance with the terms of
use for non-distributable layers.Edit the
daemon.jsonfile, which is located in/etc/docker/on Linux
hosts andC:\ProgramData\docker\config\daemon.jsonon Windows Server.
Assuming the file was previously empty, add the following contents:json{ "allow-nondistributable-artifacts": ["myregistrydomain.com:5000"] }The value is an array of registry addresses, separated by commas.
Save and exit the file.
Restart Docker.
Restart the registry if it does not start automatically.
When you push images to the registries in the list, their
non-distributable layers are pushed to the registry.
{{< hint type=warning >}}
Non-distributable artifacts typically have restrictions on
how and where they can be distributed and shared. Only use this feature
to push artifacts to private registries and ensure that you are in
compliance with any terms that cover redistributing non-distributable
artifacts.
{{< /hint >}}
Next steps
More specific and advanced information is available in the following sections:
- Configuration reference
- Working with notifications
- Advanced "recipes"
- Registry API
- Storage driver model
- Token authentication
Content About Garbage Collection (`docs/content/about/garbage-collection.md`)
keywords: registry, garbage, images, tags, repository, distribution title: Garbage collection
As of v2.4.0 a garbage collector command is included within the registry binary.
This document describes what this command does and how and why it should be used.
About garbage collection
In the context of the registry, garbage collection is the process of
removing blobs from the filesystem when they are no longer referenced by a
manifest. Blobs can include both layers and manifests.
Registry data can occupy considerable amounts of disk space. In addition,
garbage collection can be a security consideration, when it is desirable to ensure
that certain layers no longer exist on the filesystem.
Garbage collection in practice
Filesystem layers are stored by their content address in the Registry. This
has many advantages, one of which is that data is stored once and referred to by manifests.
See here for more details.
Layers are therefore shared amongst manifests; each manifest maintains a reference
to the layer. As long as a layer is referenced by one manifest, it cannot be garbage
collected.
Manifests and layers can be deleted with the registry API (refer to the API
documentation here and
here for details). This API removes references
to the target and makes them eligible for garbage collection. It also makes them
unable to be read via the API.
If a layer is deleted, it is removed from the filesystem when garbage collection
is run. If a manifest is deleted the layers to which it refers are removed from
the filesystem if no other manifests refers to them.
Example
In this example manifest A references two layers: a and b. Manifest B references
layers a and c. In this state, nothing is eligible for garbage collection:
A -----> a <----- B
\--> b |
c <--/Manifest B is deleted via the API:
A -----> a B
\--> b
cIn this state layer c no longer has a reference and is eligible for garbage
collection. Layer a had one reference removed but not garbage
collected as it is still referenced by manifest A. The blob representing
manifest B is eligible for garbage collection.
After garbage collection has been run, manifest A and its blobs remain.
A -----> a
\--> bMore details about garbage collection
Garbage collection runs in two phases. First, in the 'mark' phase, the process
scans all the manifests in the registry. From these manifests, it constructs a
set of content address digests. This set is the 'mark set' and denotes the set
of blobs to not delete. Secondly, in the 'sweep' phase, the process scans all
the blobs and if a blob's content address digest is not in the mark set, the
process deletes it.
Note: You should ensure that the registry is in read-only mode or not running at
all. If you were to upload an image while garbage collection is running, there is the
risk that the image's layers are mistakenly deleted leading to a corrupted image.
This type of garbage collection is known as stop-the-world garbage collection.
Run garbage collection
Garbage collection can be run as follows
bin/registry garbage-collect [--dry-run] [--delete-untagged] [--quiet] /path/to/config.yml
The garbage-collect command accepts a --dry-run parameter, which prints the progress
of the mark and sweep phases without removing any data. Running with a log level of info
gives a clear indication of items eligible for deletion.
The config.yml file should be in the following format:
version: 0.1
storage:
filesystem:
rootdirectory: /registry/dataSample output from a dry run garbage collection with registry log level set to info
hello-world
hello-world: marking manifest sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf
hello-world: marking blob sha256:03f4658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb
hello-world: marking blob sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
hello-world: marking configuration sha256:690ed74de00f99a7d00a98a5ad855ac4febd66412be132438f9b8dbd300a937d
ubuntu
4 blobs marked, 5 blobs eligible for deletion
blob eligible for deletion: sha256:28e09fddaacbfc8a13f82871d9d66141a6ed9ca526cb9ed295ef545ab4559b81
blob eligible for deletion: sha256:7e15ce58ccb2181a8fced7709e9893206f0937cc9543bc0c8178ea1cf4d7e7b5
blob eligible for deletion: sha256:87192bdbe00f8f2a62527f36bb4c7c7f4eaf9307e4b87e8334fb6abec1765bcb
blob eligible for deletion: sha256:b549a9959a664038fc35c155a95742cf12297672ca0ae35735ec027d55bf4e97
blob eligible for deletion: sha256:f251d679a7c61455f06d793e43c06786d7766c88b8c24edf242b2c08e3c3f599The --delete-untagged option can be used to delete manifests that are not currently referenced by a tag.
The --quiet option suppresses any output from being printed.
Content About Glossary (`docs/content/about/glossary.md`)
draft: true
Glossary
This page contains definitions for distribution related terms.
Blob
-
A blob is any kind of content that is stored by a Registry under a content-addressable identifier (a "digest").text
[Layers](#layer) are a good example of "blobs". </dd> <dt id="image"><h4>Image</h4></dt> <dd> An image is a named set of immutable data from which a container can be created. An image is represented by a json file called a [manifest](#manifest), and is conceptually a set of [layers](#layer). Image names indicate the location where they can be pulled from and pushed to, as they usually start with a [registry](#registry) domain name and port. </dd> <dt id="layer"><h4>Layer</h4></dt> <dd> A layer is a tar archive bundling partial content from a filesystem. Layers from an [image](#image) are usually extracted in order on top of each other to make up a root filesystem from which containers run out. </dd> <dt id="manifest"><h4>Manifest</h4></dt> <dd>A manifest is the JSON representation of an image.</dd> <dt id="namespace"><h4>Namespace</h4></dt> <dd>A namespace is a collection of repositories with a common name prefix. The namespace with an empty prefix is considered the Global Namespace. </dd> <dt id="registry"><h4>Registry</h4></dt> <dd>A registry is a service that let you store and deliver [images](#images) and other content. </dd> <dt id="registry"><h4>Repository</h4></dt> <dd> A repository is a set of data containing all versions of a given image. </dd> <dt id="scope"><h4>Scope</h4></dt> <dd>A scope is the portion of a namespace onto which a given authorization token is granted.</dd> <dt id="tag"><h4>Tag</h4></dt> <dd>A tag is conceptually a "version" of a [named image](#image). Example: `docker pull myimage:latest` instructs docker to pull the image "myimage" in version "latest". </dd>
Content About Help (`docs/content/about/help.md`)
keywords: registry, on-prem, images, tags, repository, distribution, help, 101, TL;DR title: Get help
If you need help, or just want to chat about development, you can reach us on the #distribution channel in the CNCF Slack.
If you want to report a bug:
- be sure to first read about how to contribute.
- you can then do so on the GitHub project bugtracker.
Content About Insecure (`docs/content/about/insecure.md`)
keywords: registry, on-prem, images, tags, repository, distribution, insecure title: Test an insecure registry
While it's highly recommended to secure your registry using a TLS certificate
issued by a known CA, you can choose to use self-signed certificates, or use
your registry over an unencrypted HTTP connection. Either of these choices
involves security trade-offs and additional configuration steps.
Deploy a plain HTTP registry
{{< hint type=warning >}}
It's not possible to use an insecure registry with basic authentication.
{{< /hint >}}
This procedure configures Docker to entirely disregard security for your
registry. This is very insecure and is not recommended. It exposes your
registry to trivial man-in-the-middle (MITM) attacks. Only use this solution for
isolated testing or in a tightly controlled, air-gapped environment.
Edit the
daemon.jsonfile, whose default location is/etc/docker/daemon.jsonon Linux orC:\ProgramData\docker\config\daemon.jsonon Windows Server. If you use
Docker Desktop for Mac or Docker Desktop for Windows, click the Docker icon, choose
Preferences (Mac) or Settings (Windows), and choose Docker Engine.If the
daemon.jsonfile does not exist, create it. Assuming there are no
other settings in the file, it should have the following contents:json{ "insecure-registries" : ["myregistrydomain.com:5000"] }Substitute the address of your insecure registry for the one in the example.
With insecure registries enabled, Docker goes through the following steps:
First, try using HTTPS.
If HTTPS is available but the certificate is invalid, ignore the error
about the certificate.If HTTPS is not available, fall back to HTTP.
Restart Docker for the changes to take effect.
Repeat these steps on every Engine host that wants to access your registry.
Use self-signed certificates
{{< hint type=warning >}}
Using this along with basic authentication requires to also trust the certificate into the OS cert store for some versions of docker (see below)
{{< /hint >}}
This is more secure than the insecure registry solution.
Generate your own certificate:
console$ mkdir -p certs $ openssl req \ -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \ -addext "subjectAltName = DNS:myregistry.domain.com" \ -x509 -days 365 -out certs/domain.crtBe sure to use the name
myregistry.domain.comas a CN.Use the result to start your registry with TLS enabled.
Instruct every Docker daemon to trust that certificate. The way to do this
depends on your OS.Linux: Copy the
domain.crtfile to/etc/docker/certs.d/myregistrydomain.com:5000/ca.crton every Docker
host. You do not need to restart Docker.Windows Server:
Open Windows Explorer, right-click the
domain.crt
file, and choose Install certificate. When prompted, select the following
options:| Store location | local machine |
| Place all certificates in the following store | selected |Click Browser and select Trusted Root Certificate Authorities.
Click Finish. Restart Docker.
Docker Desktop for Mac: Follow the instructions in
Adding custom CA certificates.
Restart Docker.Docker Desktop for Windows: Follow the instructions in
Adding custom CA certificates.
Restart Docker.
Troubleshoot insecure registry
This section lists some common failures and how to recover from them.
Failing...
Failing to configure the Engine daemon and trying to pull from a registry that is not using
TLS results in the following message:
FATA[0000] Error response from daemon: v1 ping attempt failed with error:
Get https://myregistrydomain.com:5000/v1/_ping: tls: oversized record received with length 20527.
If this private registry supports only HTTP or HTTPS with an unknown CA certificate, add
`--insecure-registry myregistrydomain.com:5000` to the daemon's arguments.
In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag;
simply place the CA certificate at /etc/docker/certs.d/myregistrydomain.com:5000/ca.crtDocker still complains about the certificate when using authentication?
When using authentication, some versions of Docker also require you to trust the
certificate at the OS level.
Ubuntu
$ cp certs/domain.crt /usr/local/share/ca-certificates/myregistrydomain.com.crt
update-ca-certificatesRed Hat Enterprise Linux
$ cp certs/domain.crt /etc/pki/ca-trust/source/anchors/myregistrydomain.com.crt
update-ca-trustOracle Linux
$ update-ca-trust enableRestart Docker for the changes to take effect.
Windows
Open Windows Explorer, right-click the certificate, and choose
Install certificate.
Then, select the following options:
- Store location: local machine
- Check place all certificates in the following store
- Click Browser, and select Trusted Root Certificate Authorities
- Click Finish
Learn more about managing TLS certificates.
After adding the CA certificate to Windows, restart Docker Desktop for Windows.
Content About Notifications (`docs/content/about/notifications.md`)
keywords: registry, on-prem, images, tags, repository, distribution, notifications, advanced title: Work with notifications
The Registry supports sending webhook notifications in response to events
happening within the registry. Notifications are sent in response to manifest
pushes and pulls and layer pushes and pulls. These actions are serialized into
events. The events are queued into a registry-internal broadcast system which
queues and dispatches events to Endpoints.
Endpoints
Notifications are sent to endpoints via HTTP requests. Each configured
endpoint has isolated queues, retry configuration and http targets within each
instance of a registry. When an action happens within the registry, it is
converted into an event which is dropped into an inmemory queue. When the
event reaches the end of the queue, an http request is made to the endpoint
until the request succeeds. The events are sent serially to each endpoint but
order is not guaranteed.
Configuration
To set up a registry instance to send notifications to endpoints, one must add
them to the configuration. A simple example follows:
notifications:
endpoints:
- name: alistener
url: https://mylistener.example.com/event
headers:
Authorization: [Bearer <your token, if needed>]
timeout: 500ms
threshold: 5
backoff: 1sThe above would configure the registry with an endpoint to send events tohttps://mylistener.example.com/event, with the header "Authorization: Bearer
<your token, if needed>". The request would timeout after 500 milliseconds. If
5 failures happen consecutively, the registry backs off for 1 second before
trying again.
For details on the fields, see the configuration documentation.
A properly configured endpoint should lead to a log message from the registry
upon startup:
INFO[0000] configuring endpoint alistener (https://mylistener.example.com/event), timeout=500ms, headers=map[Authorization:[Bearer <your token if needed>]] app.id=812bfeb2-62d6-43cf-b0c6-152f541618a3 environment=development service=registryEvents
Events have a well-defined JSON structure and are sent as the body of
notification requests. One or more events are sent in a structure called an
envelope. Each event has a unique ID that can be used to uniquely identify incoming
requests, if required. Along with that, an action is provided with a
target, identifying the object mutated during the event.
The fields available in an event are described below.
| Field | Type | Description |
|---|---|---|
| id | string | ID provides a unique identifier for the event. |
| timestamp | Time | Timestamp is the time at which the event occurred. |
| action | string | Action indicates what action encompasses the provided event. |
| target | distribution.Descriptor | Target uniquely describes the target of the event. |
| length | int | Length in bytes of content. Same as Size field in Descriptor. |
| repository | string | Repository identifies the named repository. |
| fromRepository | string | FromRepository identifies the named repository which a blob was mounted from if appropriate. |
| url | string | URL provides a direct link to the content. |
| tag | string | Tag identifies a tag name in tag events. |
| request | RequestRecord | Request covers the request that generated the event. |
| actor | ActorRecord. | Actor specifies the agent that initiated the event. For most situations, this could be from the authorization context of the request. |
| source | SourceRecord | Source identifies the registry node that generated the event. Put differently, while the actor "initiates" the event, the source "generates" it. |
The following is an example of a JSON event, sent in response to the pull of a
manifest:
{
"events": [
{
"id": "320678d8-ca14-430f-8bb6-4ca139cd83f7",
"timestamp": "2016-03-09T14:44:26.402973972-08:00",
"action": "pull",
"target": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
"size": 708,
"length": 708,
"repository": "hello-world",
"url": "http://192.168.100.227:5000/v2/hello-world/manifests/sha256:fea8895f450959fa676bcc1df0611ea93823a735a01205fd8622846041d0c7cf",
"tag": "latest"
},
"request": {
"id": "6df24a34-0959-4923-81ca-14f09767db19",
"addr": "192.168.64.11:42961",
"host": "192.168.100.227:5000",
"method": "GET",
"useragent": "curl/7.38.0"
},
"actor": {},
"source": {
"addr": "xtal.local:5000",
"instanceID": "a53db899-3b4b-4a62-a067-8dd013beaca4"
}
}
]
}The target struct of events which are sent when manifests and blobs are deleted
contains a subset of the data contained in Get and Put events. Specifically,
only the digest and repository are sent.
{
"target": {
"digest": "sha256:d89e1bee20d9cb344674e213b581f14fbd8e70274ecf9d10c514bab78a307845",
"repository": "library/test"
}
}Note: As of version 2.1, the
lengthfield for event targets
is being deprecated for thesizefield, bringing the target in line with
common nomenclature. Both will continue to be set for the foreseeable
future. Newer code should favorsizebut accept either.
Envelope
The envelope contains one or more events, with the following json structure:
{
"events": [ "..." ]
}While events may be sent in the same envelope, the set of events within that
envelope have no implied relationship. For example, the registry may choose to
group unrelated events and send them in the same envelope to reduce the total
number of requests.
The full package has the mediatype
"application/vnd.docker.distribution.events.v2+json", which is set on the
request coming to an endpoint.
An example of a full event may look as follows:
/* Detailed source-code truncated for AI context efficiency. */Responses
The registry is fairly accepting of the response codes from endpoints. If an
endpoint responds with any 2xx or 3xx response code (after following
redirects), the message is considered to have been delivered, and is discarded.
In turn, it is recommended that endpoints are accepting of incoming responses,
as well. While the format of event envelopes are standardized by media type,
any "pickyness" about validation may cause the queue to backup on the
registry.
Monitoring
The state of the endpoints are reported via the debug/vars http interface,
usually configured to http://localhost:5001/debug/vars. Information such as
configuration and metrics are available by endpoint.
The following provides an example of a few endpoints that have experienced
several failures and have since recovered:
{
"notifications": {
"endpoints": [
{
"name": "local-5003",
"url": "http://localhost:5003/callback",
"Headers": {
"Authorization": [
"Bearer \u003can example token\u003e"
]
},
"Timeout": 1000000000,
"Threshold": 10,
"Backoff": 1000000000,
"Metrics": {
"Pending": 76,
"Events": 76,
"Successes": 0,
"Failures": 0,
"Errors": 46,
"Statuses": {
}
}
},
{
"name": "local-8083",
"url": "http://localhost:8083/callback",
"Headers": null,
"Timeout": 1000000000,
"Threshold": 10,
"Backoff": 1000000000,
"Metrics": {
"Pending": 0,
"Events": 76,
"Successes": 76,
"Failures": 0,
"Errors": 28,
"Statuses": {
"202 Accepted": 76
}
}
}
]
}
}If using notification as part of a larger application, it is critical to
monitor the size ("Pending" above) of the endpoint queues. If failures or
queue sizes are increasing, it can indicate a larger problem.
The logs are also a valuable resource for monitoring problems. A failing
endpoint leads to messages similar to the following:
ERRO[0340] retryingsink: error writing events: httpSink{http://localhost:5003/callback}: error posting: Post http://localhost:5003/callback: dial tcp 127.0.0.1:5003: connection refused, retrying
WARN[0340] httpSink{http://localhost:5003/callback} encountered too many errors, backing offThe above indicates that several errors caused a backoff and the registry
waits before retrying.
Considerations
Currently, the queues are inmemory, so endpoints should be reasonably
reliable. They are designed to make a best-effort to send the messages but if
an instance is lost, messages may be dropped. If an endpoint goes down, care
should be taken to ensure that the registry instance is not terminated before
the endpoint comes back up or messages are lost.
This can be mitigated by running endpoints in close proximity to the registry
instances. One could run an endpoint that pages to disk and then forwards a
request to provide better durability.
The notification system is designed around a series of interchangeable sinks
which can be wired up to achieve interesting behavior. If this system doesn't
provide acceptable guarantees, adding a transactional Sink to the registry
is a possibility, although it may have an effect on request service time.
See the
godoc
for more information.
Content Recipes Apache (`docs/content/recipes/apache.md`)
keywords: registry, on-prem, images, tags, repository, distribution, authentication, proxy, apache, httpd, TLS, recipe, advanced title: Authenticate proxy with apache
Use-case
People already relying on an apache proxy to authenticate their users to other services might want to leverage it and have Registry communications tunneled through the same pipeline.
Usually, that includes enterprise setups using LDAP/AD on the backend and a SSO mechanism fronting their internal http portal.
Alternatives
If you just want authentication for your registry, and are happy maintaining users access separately, you should really consider sticking with the native basic auth registry feature.
Solution
With the method presented here, you implement basic authentication for docker engines in a reverse proxy that sits in front of your registry.
While we use a simple htpasswd file as an example, any other apache authentication backend should be fairly easy to implement once you are done with the example.
We also implement push restriction (to a limited user group) for the sake of the example. Again, you should modify this to fit your mileage.
Gotchas
While this model gives you the ability to use whatever authentication backend you want through the secondary authentication mechanism implemented inside your proxy, it also requires that you move TLS termination from the Registry to the proxy itself.
Furthermore, introducing an extra http layer in your communication pipeline adds complexity when deploying, maintaining, and debugging.
Setting things up
Read again the requirements.
Ready?
Run the following script:
/* Detailed source-code truncated for AI context efficiency. */Starting and stopping
Now, start your stack:
$ docker compose up -dLog in with a "push" authorized user (using testuserpush and testpasswordpush), then tag and push your first image:
$ docker login myregistrydomain.com:5043
$ docker tag ubuntu myregistrydomain.com:5043/test
$ docker push myregistrydomain.com:5043/testNow, log in with a "pull-only" user (using testuser and testpassword), then pull back the image:
$ docker login myregistrydomain.com:5043
$ docker pull myregistrydomain.com:5043/testVerify that the "pull-only" can NOT push:
$ docker push myregistrydomain.com:5043/testContent Recipes Mirror (`docs/content/recipes/mirror.md`)
keywords: registry, on-prem, images, tags, repository, distribution, mirror, Hub, recipe, advanced title: Registry as a pull through cache
Use-case
If you have multiple consumers of containers running in your environment, such as
multiple physical or virtual machines using containers, or a Kubernetes cluster,
each consumer fetches an images it doesn't have locally, from the external registry.
You can run a local registry mirror and point all your consumers
there, to avoid this extra internet traffic.
Alternatives
Alternatively, if the set of images you are using is well delimited, you can
simply pull them manually and push them to a simple, local, private registry.
Furthermore, if your images are all built in-house, not using the Hub at all and
relying entirely on your local registry is the simplest scenario.
Gotcha
It's currently possible to mirror only one upstream registry at a time.
The URL of a pull-through registry mirror must be the root of a domain.
No path components other than an optional trailing slash (/) are allowed.
The following table shows examples of allowed and disallowed mirror URLs.
| URL | Allowed |
|---|---|
https://mirror.company.example |
Yes |
https://mirror.company.example/ |
Yes |
https://mirror.company.example/foo |
No |
https://mirror.company.example#bar |
No |
https://mirror.company.example?baz=1 |
No |
Note
Mirrors of Docker Hub are still subject to Docker's fair usage policy.
Solution
The Registry can be configured as a pull through cache. In this mode a Registry
responds to all normal docker pull requests but stores all content locally.
How does it work?
The first time you request an image from your local registry mirror, it pulls
the image from the public Docker registry and stores it locally before handing
it back to you. On subsequent requests, the local registry mirror is able to
serve the image from its own storage.
What if the content changes on the Hub?
When a pull is attempted with a tag, the Registry checks the remote to
ensure if it has the latest version of the requested content. Otherwise, it
fetches and caches the latest content.
What about my disk?
In environments with high churn rates, stale data can build up in the cache.
When running as a pull through cache the Registry periodically removes old
content to save disk space. Subsequent requests for removed content causes a
remote fetch and local re-caching.
To ensure best performance and guarantee correctness the Registry cache should
be configured to use the filesystem driver for storage.
Run a Registry as a pull-through cache
The easiest way to run a registry as a pull through cache is to run the official
Registry image.
At least, you need to specify proxy.remoteurl within /etc/distribution/config.yml
as described in the following subsection.
Multiple registry caches can be deployed over the same back-end, but each
instance in a registry cache cluster is stateless, so it maintains its own
cache.
Note that concurrent inflight pulls will make multiple requests.
Note
Service accounts included in the Team plan are limited to 5,000 pulls per day.
See Service Accounts for more details.
Configure the cache
To configure a Registry to run as a pull through cache, the addition of aproxy section is required to the config file.
To access private images on the Docker Hub, a username and password can
be supplied.
proxy:
remoteurl: https://registry-1.docker.io
username: [username]
password: [password]
ttl: 168hWarning: If you specify a username and password, it's very important to
understand that private resources that this user has access to Docker Hub is
made available on your mirror. You must secure your mirror by
implementing authentication if you expect these resources to stay private!
Warning: For the scheduler to clean up old entries,
deletemust
be enabled in the registry configuration. See
Registry Configuration for more details.
Configure the Docker daemon
Either pass the --registry-mirror option when starting dockerd manually,
or edit /etc/docker/daemon.json
and add the registry-mirrors key and value, to make the change persistent.
{
"registry-mirrors": ["https://mirror.company.example"]
}Note
The mirror URL must be the root of the domain.
Note
Currently Docker daemon supports only mirrors of Docker Hub.
It is not possible to run the Docker daemon against a pull through cache with another upstream registry.
Save the file and reload Docker for the change to take effect.
Some log messages that appear to be errors are actually informational messages.
Check the
levelfield to determine whether
the message is warning you about an error or is giving you information.
For example, this log message is informational:conftime="2017-06-02T15:47:37Z" level=info msg="error statting local store, serving from upstream: unknown blob" go.version=go1.7.4It's telling you that the file doesn't exist yet in the local cache and is
being pulled from upstream.
Content Recipes Nginx (`docs/content/recipes/nginx.md`)
keywords: registry, on-prem, images, tags, repository, distribution, nginx, proxy, authentication, TLS, recipe, advanced title: Authenticate proxy with nginx
Use-case
People already relying on a nginx proxy to authenticate their users to other
services might want to leverage it and have Registry communications tunneled
through the same pipeline.
Usually, that includes enterprise setups using LDAP/AD on the backend and a SSO
mechanism fronting their internal http portal.
Alternatives
If you just want authentication for your registry, and are happy maintaining
users access separately, you should really consider sticking with the native
basic auth registry feature.
Solution
With the method presented here, you implement basic authentication for docker
engines in a reverse proxy that sits in front of your registry.
While we use a simple htpasswd file as an example, any other nginx
authentication backend should be fairly easy to implement once you are done with
the example.
We also implement push restriction (to a limited user group) for the sake of the
example. Again, you should modify this to fit your mileage.
Gotchas
While this model gives you the ability to use whatever authentication backend
you want through the secondary authentication mechanism implemented inside your
proxy, it also requires that you move TLS termination from the Registry to the
proxy itself.
Note: It is not recommended to bind your registry to
localhost:5000without
authentication. This creates a potential loophole in your registry security.
As a result, anyone who can log on to the server where your registry is running
can push images without authentication.
Furthermore, introducing an extra http layer in your communication pipeline
makes it more complex to deploy, maintain, and debug. Make sure the extra
complexity is required.
For instance, Amazon's Elastic Load Balancer (ELB) in HTTPS mode already sets
the following client header:
X-Real-IP
X-Forwarded-For
X-Forwarded-ProtoSo if you have an Nginx instance sitting behind it, remove these lines from the
example config below:
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;Otherwise Nginx resets the ELB's values, and the requests are not routed
properly. For more information, see
#970.
Setting things up
Review the requirements, then follow these steps.
Create the required directories
console$ mkdir -p auth dataCreate the main nginx configuration. Paste this code block into a new file called
auth/nginx.conf:text
/* Detailed source-code truncated for AI context efficiency. */
3. Create a password file `auth/nginx.htpasswd` for "testuser" and "testpassword".
```console
$ docker run --rm --entrypoint htpasswd httpd -Bbn testuser testpassword > auth/nginx.htpasswdNote: If you do not want to use
bcrypt, you can omit the-Bparameter.
Copy your certificate files to the
auth/directory.console$ cp domain.crt auth $ cp domain.key authCreate the compose file. Paste the following YAML into a new file called
docker-compose.yml.yamlservices: nginx: # Note : Only nginx:alpine supports bcrypt. # If you don't need to use bcrypt, you can use a different tag. # Ref. https://github.com/nginxinc/docker-nginx/issues/29 image: "nginx:alpine" ports: - 5043:443 depends_on: - registry volumes: - ./auth:/etc/nginx/conf.d - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro registry: image: registry:3 volumes: - ./data:/var/lib/registry
Starting and stopping
Now, start your stack:
$ docker compose up -dLogin with a "push" authorized user (using testuser and testpassword), then
tag and push your first image:
$ docker login -u=testuser -p=testpassword [email protected] myregistrydomain.com:5043
$ docker tag ubuntu myregistrydomain.com:5043/test
$ docker push myregistrydomain.com:5043/test
$ docker pull myregistrydomain.com:5043/testContent Recipes Osx Setup Guide (`docs/content/recipes/osx-setup-guide.md`)
keywords: registry, on-prem, images, tags, repository, distribution, macOS, recipe, advanced title: macOS setup guide
Use-case
This is useful if you intend to run a registry server natively on macOS.
Alternatives
You can start a VM on macOS, and deploy your registry normally as a container using Docker inside that VM.
Solution
Using the method described here, you install and compile your own from the git repository and run it as an macOS agent.
Gotchas
Production services operation on macOS is out of scope of this document. Be sure you understand well these aspects before considering going to production with this.
Setup golang on your machine
If you know, safely skip to the next section.
If you don't, the TLDR is:
$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
$ source ~/.gvm/scripts/gvm
$ gvm install go1.4.2
$ gvm use go1.4.2If you want to understand, you should read How to Write Go Code.
Checkout the source tree
$ mkdir -p $GOPATH/src/github.com/distribution
$ git clone https://github.com/distribution/distribution.git $GOPATH/src/github.com/distribution/distribution
$ cd $GOPATH/src/github.com/distribution/distributionBuild the binary
$ GOPATH=$(PWD)/Godeps/_workspace:$GOPATH make binaries
$ sudo mkdir -p /usr/local/libexec
$ sudo cp bin/registry /usr/local/libexec/registrySetup
Copy the registry configuration file in place:
$ mkdir /Users/Shared/Registry
$ cp docs/content/recipes/osx/config.yml /Users/Shared/Registry/config.ymlModify ports if needed
MacOS runs an Airplay receiver on port 5000 by default, which is the same port as the registry server. You can either disable the Airplay receiver in System Settings… > General > AirDrop & Handoff > AirPlay Receiver, or change the listening ports in the config file that you have just copied to /Users/Shared/Registry/config.yml.
Run the registry under launchd
Copy the registry plist into place:
$ plutil -lint docs/content/recipes/osx/com.docker.registry.plist
$ cp docs/content/recipes/osx/com.docker.registry.plist ~/Library/LaunchAgents/
$ chmod 644 ~/Library/LaunchAgents/com.docker.registry.plistStart the registry:
$ launchctl load ~/Library/LaunchAgents/com.docker.registry.plistRestart the registry service
$ launchctl stop com.docker.registry
$ launchctl start com.docker.registryUnload the registry service
$ launchctl unload ~/Library/LaunchAgents/com.docker.registry.plistContent Recipes Systemd (`docs/content/recipes/systemd.md`)
keywords: registry, on-prem, systemd, socket-activated, recipe, advanced title: Start registry via systemd
Use-case
Using systemd to manage containers can make service discovery and maintenance easier
by managing all services in the same way. Additionally, when using Podman, systemd
can start the registry with socket-activation, providing additional security options:
- Run as non-root and expose on a low-numbered socket (< 1024)
- Run with
--network=none
Docker
When deploying the registry via Docker, a simple service file can be used to manage
the registry:
registry.service
[Unit]
Description=Distribution registry
After=docker.service
Requires=docker.service
[Service]
#TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop %N
ExecStartPre=-/usr/bin/docker rm %N
ExecStart=/usr/bin/docker run --name %N \
-v registry:/var/lib/registry \
-p 5000:5000 \
registry:3
[Install]
WantedBy=multi-user.targetIn this case, the registry will store images in the named-volume registry.
Note that the container is destroyed on restart instead of using --rm or
destroy on stop. This is done to make accessing docker logs ... easier in
the case of issues.
Podman
Podman offers tighter integration with systemd than Docker does, and supports
socket-activation of containers.
Create service file
podman create --name registry --network=none -v registry:/var/lib/registry registry:3
podman generate systemd --name --new registry > registry.serviceCreate socket file
registry.socket
[Unit]
Description=Distribution registry
[Socket]
ListenStream=5000
[Install]
WantedBy=sockets.targetInstallation
Installation can be either rootful or rootless. For Docker, rootless configurations
often include additional setup steps that are beyond the scope of this recipe, whereas
for Podman, rootless containers generally work out of the box.
Rootful
Run as root:
- Copy registry.service (and registry.socket if relevant) to /etc/systemd/service/
- Run
systemctl daemon-reload - Enable the service:
- When using socket activation:
systemctl enable registry.socket - When not using socket activation:
systemctl enable registry.service
- When using socket activation:
- Start the service:
- When using socket activation:
systemctl start registry.socket - When not using socket activation:
systemctl start registry.service
- When using socket activation:
Rootless
Run as the target user:
- Copy registry.service (and registry.socket if relevant) to ~/.config/systemd/user/
- Run
systemctl --user daemon-reload - Enable the service:
- When using socket activation:
systemctl --user enable registry.socket - When not using socket activation:
systemctl --user enable registry.service
- When using socket activation:
- Start the service:
- When using socket activation:
systemctl --user start registry.socket - When not using socket activation:
systemctl --user start registry.service
- When using socket activation:
Note: To have rootless services start on boot, it may be necessary to enable linger
via loginctl enable-linger $USER.
Content Spec Api (`docs/content/spec/api.md`)
title: "HTTP API V2"
keywords: registry, on-prem, images, tags, repository, distribution, api, advanced
aliases:
- /reference/api/registry_api/
Introduction
The Docker Registry HTTP API is the protocol to facilitate distribution of
images to the docker engine. It interacts with instances of the docker
registry, which is a service to manage information about docker images and
enable their distribution. The specification covers the operation of version 2
of this API, known as Docker Registry HTTP API V2.
While the V1 registry protocol is usable, there are several problems with the
architecture that have led to this new version. The main driver of this
specification is a set of changes to the Docker image format, covered in
docker/docker#8093.
The new, self-contained image manifest simplifies image definition and improves
security. This specification will build on that work, leveraging new properties
of the manifest format to improve performance, reduce bandwidth usage and
decrease the likelihood of backend corruption.
For relevant details and history leading up to this specification, please see
the following issues:
Scope
This specification covers the URL layout and protocols of the interaction
between docker registry and docker core. This will affect the docker core
registry API and the rewrite of docker-registry. Docker registry
implementations may implement other API endpoints, but they are not covered by
this specification.
This includes the following features:
- Namespace-oriented URI Layout
- PUSH/PULL registry server for V2 image manifest format
- Resumable layer PUSH support
- V2 Client library implementation
While authentication and authorization support will influence this
specification, details of the protocol will be left to a future specification.
Relevant header definitions and error codes are present to provide an
indication of what a client may encounter.
Use Cases
For the most part, the use cases of the former registry API apply to the new
version. Differentiating use cases are covered below.
Image Verification
A docker engine instance would like to run verified image named
"library/ubuntu", with the tag "latest". The engine contacts the registry,
requesting the manifest for "library/ubuntu:latest". An untrusted registry
returns a manifest. Before proceeding to download the individual layers, the
engine verifies the manifest's signature, ensuring that the content was
produced from a trusted source and no tampering has occurred. After each layer
is downloaded, the engine verifies the digest of the layer, ensuring that the
content matches that specified by the manifest.
Resumable Push
Company X's build servers lose connectivity to docker registry before
completing an image layer transfer. After connectivity returns, the build
server attempts to re-upload the image. The registry notifies the build server
that the upload has already been partially attempted. The build server
responds by only sending the remaining data to complete the image file.
Resumable Pull
Company X is having more connectivity problems but this time in their
deployment datacenter. When downloading an image, the connection is
interrupted before completion. The client keeps the partial data and uses httpRange requests to avoid downloading repeated data.
Layer Upload De-duplication
Company Y's build system creates two identical docker layers from build
processes A and B. Build process A completes uploading the layer before B.
When process B attempts to upload the layer, the registry indicates that its
not necessary because the layer is already known.
If process A and B upload the same layer at the same time, both operations
will proceed and the first to complete will be stored in the registry (Note:
we may modify this to prevent dogpile with some locking mechanism).
Changes
The V2 specification has been written to work as a living document, specifying
only what is certain and leaving what is not specified open or to future
changes. Only non-conflicting additions should be made to the API and accepted
changes should avoid preventing future changes from happening.
This section should be updated when changes are made to the specification,
indicating what is different. Optionally, we may start marking parts of the
specification to correspond with the versions enumerated here.
Each set of changes is given a letter corresponding to a set of modifications
that were applied to the baseline specification. These are merely for
reference and shouldn't be used outside the specification other than to
identify a set of modifications.
- l
- text
<li>Document TOOMANYREQUESTS error code.</li> - k
- text
<li>Document use of Accept and Content-Type headers in manifests endpoint.</li> - j
- text
<li>Add ability to mount blobs across repositories.</li> - i
- text
<li>Clarified expected behavior response to manifest HEAD request.</li> - h
- text
<li>All mention of tarsum removed.</li> - g
- text
<li>Clarify behavior of pagination behavior with unspecified parameters.</li> - f
- text
<li>Specify the delete API for layers and manifests.</li> - e
- text
<li>Added support for listing registry contents.</li> <li>Added pagination to tags API.</li> <li>Added common approach to support pagination.</li> - d
- text
<li>Allow repository name components to be one character.</li> <li>Clarified that single component names are allowed.</li> - c
- text
<li>Added section covering digest format.</li> <li>Added more clarification that manifest cannot be deleted by tag.</li> - b
- text
<li>Added capability of doing streaming upload to PATCH blob upload.</li> <li>Updated PUT blob upload to no longer take final chunk, now requires entire data or no data.</li> <li>Removed `416 Requested Range Not Satisfiable` response status from PUT blob upload.</li> - a
- text
<li>Added support for immutable manifest references in manifest endpoints.</li> <li>Deleting a manifest by tag has been deprecated.</li> <li>Specified `Docker-Content-Digest` header for appropriate entities.</li> <li>Added error code for unsupported operations.</li>
Overview
This section covers client flows and details of the API endpoints. The URI
layout of the new API is structured to support a rich authentication and
authorization model by leveraging namespaces. All endpoints will be prefixed
by the API version and the repository name:
/v2/<name>/For example, an API endpoint that will work with the library/ubuntu
repository, the URI prefix will be:
/v2/library/ubuntu/This scheme provides rich access control over various operations and methods
using the URI prefix and http methods that can be controlled in variety of
ways.
Classically, repository names have always been two path components where each
path component is less than 30 characters. The V2 registry API does not
enforce this. The rules for a repository name are as follows:
- A repository name is broken up into path components. A component of a
repository name must be at least one lowercase, alpha-numeric characters,
optionally separated by periods, dashes or underscores. More strictly, it
must match the regular expression[a-z0-9]+(?:[._-][a-z0-9]+)*. - If a repository name has two or more path components, they must be
separated by a forward slash ("/"). - The total length of a repository name, including slashes, must be less than
256 characters.
These name requirements only apply to the registry API and should accept a
superset of what is supported by other docker ecosystem components.
All endpoints should support aggressive http caching, compression and range
headers, where appropriate. The new API attempts to leverage HTTP semantics
where possible but may break from standards to implement targeted features.
For detail on individual endpoints, please see the Detail
section.
Errors
Actionable failure conditions, covered in detail in their relevant sections,
are reported as part of 4xx responses, in a json response body. One or more
errors will be returned in the following format:
{
"errors": [
{
"code": <error identifier>,
"message": <message describing condition>,
"detail": <unstructured>
},
...
]
}The code field will be a unique identifier, all caps with underscores by
convention. The message field will be a human readable string. The optionaldetail field may contain arbitrary json data providing information the
client can use to resolve the issue.
While the client can take action on certain error codes, the registry may add
new error codes over time. All client implementations should treat unknown
error codes as UNKNOWN, allowing future error codes to be added without
breaking API compatibility. For the purposes of the specification error codes
will only be added and never removed.
For a complete account of all error codes, please see the Errors
section.
API Version Check
A minimal endpoint, mounted at /v2/ will provide version support information
based on its response statuses. The request format is as follows:
GET /v2/If a 200 OK response is returned, the registry implements the V2(.1)
registry API and the client may proceed safely with other V2 operations.
Optionally, the response may contain information about the supported paths in
the response body. The client should be prepared to ignore this data.
If a 401 Unauthorized response is returned, the client should take action
based on the contents of the "WWW-Authenticate" header and try the endpoint
again. Depending on access control setup, the client may still have to
authenticate against different resources, even if this check succeeds.
If 404 Not Found response status, or other unexpected status, is returned,
the client should proceed with the assumption that the registry does not
implement V2 of the API.
When a 200 OK or 401 Unauthorized response is returned, the
"Docker-Distribution-API-Version" header should be set to "registry/2.0".
Clients may require this header value to determine if the endpoint serves this
API. When this header is omitted, clients may fallback to an older API version.
Content Digests
This API design is driven heavily by content addressability.
The core of this design is the concept of a content addressable identifier. It
uniquely identifies content by taking a collision-resistant hash of the bytes.
Such an identifier can be independently calculated and verified by selection
of a common algorithm. If such an identifier can be communicated in a secure
manner, one can retrieve the content from an insecure source, calculate it
independently and be certain that the correct content was obtained. Put simply,
the identifier is a property of the content.
To disambiguate from other concepts, we call this identifier a digest. A
digest is a serialized hash result, consisting of a algorithm and hex
portion. The algorithm identifies the methodology used to calculate the
digest. The hex portion is the hex-encoded result of the hash.
We define a digest string to match the following grammar:
digest := algorithm ":" hex
algorithm := /[A-Za-z0-9_+.-]+/
hex := /[A-Fa-f0-9]+/Some examples of digests include the following:
| digest | description |
|---|---|
| sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b | Common sha256 based digest |
While the algorithm does allow one to implement a wide variety of
algorithms, compliant implementations should use sha256. Heavy processing of
input before calculating a hash is discouraged to avoid degrading the
uniqueness of the digest but some canonicalization may be performed to
ensure consistent identifiers.
Let's use a simple example in pseudo-code to demonstrate a digest calculation:
let C = 'a small string'
let B = sha256(C)
let D = 'sha256:' + EncodeHex(B)
let ID(C) = DAbove, we have bytestring C passed into a function, SHA256, that returns a
bytestring B, which is the hash of C. D gets the algorithm concatenated
with the hex encoding of B. We then define the identifier of C to ID(C)
as equal to D. A digest can be verified by independently calculating D and
comparing it with identifier ID(C).
Digest Header
To provide verification of http content, any response may include aDocker-Content-Digest header. This will include the digest of the target
entity returned in the response. For blobs, this is the entire blob content. For
manifests, this is the manifest body without the signature content, also known
as the JWS payload. Note that the commonly used canonicalization for digest
calculation may be dependent on the mediatype of the content, such as with
manifests.
The client may choose to ignore the header or may verify it to ensure content
integrity and transport security. This is most important when fetching by a
digest. To ensure security, the content should be verified against the digest
used to fetch the content. At times, the returned digest may differ from that
used to initiate a request. Such digests are considered to be from different
domains, meaning they have different values for algorithm. In such a case,
the client may choose to verify the digests in both domains or ignore the
server's digest. To maintain security, the client must always verify the
content against the digest used to fetch the content.
IMPORTANT: If a digest is used to fetch content, the client should use
the same digest used to fetch the content to verify it. The headerDocker-Content-Digestshould not be trusted over the "local" digest.
Pulling An Image
An "image" is a combination of a JSON manifest and individual layer files. The
process of pulling an image centers around retrieving these two components.
The first step in pulling an image is to retrieve the manifest. For reference,
the relevant manifest fields for the registry are the following:
| field | description |
|---|---|
| name | The name of the image. |
| tag | The tag for this version of the image. |
| fsLayers | A list of layer d |