DISTRIBUTION Documentation

TypeScript repository by @docker. Docker Compose & container deployment.

0 stars TypeScript TypeScript 145 files · ~157,912 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy DISTRIBUTION on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name distribution -p 5000:5000 --restart always docker/distribution:latest

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

  1. 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

  1. Update the .mailmap files.

  2. Update the version file: https://github.com/distribution/distribution/blob/master/version/version.go

  3. Create 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.

  1. Push the signed tag

  2. Create a new release.
    In the case of a release candidate, tick the pre-release checkbox. Use
    the generate release notes from the release tool

  3. Update the registry binary in the distribution library image repo by running the update script and opening a pull request.

  4. Update the official image. Add the new version in the official images repo by appending a new version to the registry/registry file 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 release 2.3.1

2.3.1 (new)

2.3.0 -> 2.3.0 can be removed

2 -> 2.3.1

2.3 -> 2.3.1

  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.

shell
# install required packages from package.json
npm install

# run the build script to build required assets
npm run build

# build release tarball
npm run pack

See 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:


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:

  1. 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.
  2. 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.
  3. 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 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 use attribute_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:

c
// 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

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:

go
import "google.golang.org/grpc"

Note: If you are trying to access grpc-go from China, see the
FAQ below.

Learn more

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:

console
$ 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 replace feature of go mod to create aliases for golang.org packages. In your project's directory:

    sh
    go mod edit -replace=google.golang.org/grpc=github.com/grpc/grpc-go@latest
    go mod tidy
    go mod vendor
    go build -mod=vendor

    Again, 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 using
go get google.golang.org/grpc.

How to turn on logging

The default logger is controlled by environment variables. Turn everything on
like this:

console
$ export GRPC_GO_LOG_VERBOSITY_LEVEL=99
$ export GRPC_GO_LOG_SEVERITY_LEVEL=info

The 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:

  1. mis-configured transport credentials, connection failed on handshaking
  2. bytes disrupted, possibly by a proxy in between
  3. server shutdown
  4. 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

bash
go get cloud.google.com/go/auth@latest

Usage

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

bash
go get cloud.google.com/go/iam

Stability

The stability of this module is indicated by SemVer.

However, a v1+ module may have breaking changes in two scenarios:

  • Packages with alpha or beta in 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:

go
client, err := storage.NewClient(ctx)
if err != nil {
	log.Fatal(err)
}
go
// 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:

go
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:

go
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:

go
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:

go
f.AllowUnexportedFields()

...and disabled with:

go
f.DisallowUnexportedFields()

Other types:

Other useful APIs:

go
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 used SecureJoin. 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_PATH and 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:

go
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
    root and 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 how chroot(2) operates on file paths. Note that
    these symlinks will not be expanded lexically (filepath.Clean is not
    called on the input before processing).

  • Non-existent path components are unaffected by SecureJoin (similar to
    filepath.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 that
readlink is inside the root path):

go
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:

go
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:

go
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:

go
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:

go
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:

go
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 © 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.

go
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 called
container_actions and use labels to specify the type of action.

go
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.

go
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.

go
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:

go
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 © 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

go
// 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, and
io.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 underlying
http.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 a
http.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 to
http.ResponseWriter methods, and even calls happening after the wrapped
ServeHTTP 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 underlying
http.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 inside
http.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

text
BenchmarkBaseline-8      	   20000	     94912 ns/op
BenchmarkCaptureMetrics-8	   20000	     95461 ns/op

As 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 the
LogSink 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:

text
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:

text
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:

text
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:

  1. Dave basically proposes doing away with the notion of a logging API in favor
    of fmt.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.

  1. 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 and
ToSlogHandler 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, then
ToSlogHandler 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
    through slog.Logger, but may be wrong in other cases. That's because a
    logr.Sink does 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.LevelWarning as
    used by slog.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 SlogSink and the resulting program
    counter is passed to the slog.Handler.
  • Names added via Logger.WithName are gathered and recorded in an additional
    attribute with logger as key and the names separated by slash as value.
  • Logger.Error is turned into a log record with slog.LevelError as level
    and an additional attribute with err as 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, then
slog.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 and
FromContext for logr.Logger value.

When NewContextWithSlogLogger is followed by FromContext, the latter will
automatically convert the slog.Logger to a
logr.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 a
slog.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 type
map[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 the
WithName 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":

  1. Figure out what the error actually is, as you'd write in a TL;DR style,
    and use that as a message.

  2. 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) becomes logger.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) becomes logger.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", and
10 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 the
LogSink 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

sh
go get github.com/google/uuid

Documentation

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:

Other handlers are documented on the Gorilla
website
.

Example

A simple example using handlers.LoggingHandler and handlers.CompressHandler:

go
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.Handler interface so it is compatible with the standard http.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

With a correctly configured Go toolchain:

sh
go get -u github.com/gorilla/mux

Examples

Let's start registering a couple of URL paths and handlers:

go
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:

go
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():

go
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:

go
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:

go
r.PathPrefix("/products/")

...or HTTP methods:

go
r.Methods("GET", "POST")

...or URL schemes:

go
r.Schemes("https")

...or header values:

go
r.Headers("X-Requested-With", "XMLHttpRequest")

...or query values:

go
r.Queries("key", "value")

...or to use a custom matcher function:

go
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:

go
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:

go
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:

go
r := mux.NewRouter()
s := r.Host("www.example.com").Subrouter()

Then register routes in the subrouter:

go
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:

go
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": calling
PathPrefix("/static/").Handler(...) means that the handler will be passed any
request that matches "/static/*". This makes it easy to serve static files with mux:

go
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.

text
/* 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:

go
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:

go
url, err := r.Get("article").URL("category", "technology", "id", "42")

...and the result will be a url.URL with the following path:

text
"/articles/technology/42"

This also works for host and query value variables:

go
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:

go
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:

go
// "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:

go
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:

go
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:

go
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:

text
/* 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:

go
type MiddlewareFunc func(http.Handler) http.Handler

Typically, 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:

go
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():

go
r := mux.NewRouter()
r.HandleFunc("/", handler)
r.Use(loggingMiddleware)

A more complex authentication middleware, which maps session token to users, could be written as:

go
// 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)
        }
    })
}
go
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-Methods header 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 OPTIONS method 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:

go
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:

bash
curl localhost:8080/foo -v

Would look like:

bash
*   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
foo

Testing 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:

go
// 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:

go
// 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.

go
// 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:

go
// 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:

go
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:

text
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:

go
> 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 = 2

In 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:

go
> 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:

go
> 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/snappy offering 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 nounsafe tag to disable all use of the "unsafe" package.
  • Use the noasm tag to disable all assembly across packages.

Use the links above for more information on each.

changelog

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.

text
See changes to v1.14.x
  • Feb 22, 2022 (v1.14.4)

    • flate: Fix rare huffman only (-2) corruption. #503
    • zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in #502
    • zip: don't read data descriptor early by @saracen in #501 #501
    • huff0: Use static decompression buffer up to 30% faster #499 #500
  • Feb 17, 2022 (v1.14.3)

    • flate: Improve fastest levels compression speed ~10% more throughput. #482 #489 #490 #491 #494 #478
    • flate: Faster decompression speed, ~5-10%. #483
    • s2: Faster compression with Go v1.18 and amd64 microarch level 3+. #484 #486
  • Jan 25, 2022 (v1.14.2)

    • zstd: improve header decoder by @dsnet #476
    • zstd: Add bigger default blocks #469
    • zstd: Remove unused decompression buffer #470
    • zstd: Fix logically dead code by @ningmingxiao #472
    • flate: Improve level 7-9 #471 #473
    • zstd: Add noasm tag for xxhash #475
  • Jan 11, 2022 (v1.14.1)

    See changes to v1.13.x

  • Aug 30, 2021 (v1.13.5)

    • gz/zlib/flate: Alias stdlib errors #425
    • s2: Add block support to commandline tools #413
    • zstd: pooledZipWriter should return Writers to the same pool #426
    • Removed golang/snappy as external dependency for tests #421
  • Aug 12, 2021 (v1.13.4)

  • Aug 3, 2021 (v1.13.3)

    • zstd: Improve Best compression #404
    • zstd: Fix WriteTo error forwarding #411
    • gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. #406
    • s2sx: Fix max size error #399
    • zstd: Add optional stream content size on reset #401
    • zstd: use SpeedBestCompression for level >= 10 #410
  • 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)

    • deflate: Better/faster Huffman encoding #374
    • deflate: Allocate less for history. #375
    • zstd: Forward read errors #373
  • Apr 27, 2021 (v1.12.2)

    • zstd: Improve better/best compression #360 #364 #365
    • zstd: Add helpers to compress/decompress zstd inside zip files #363
    • deflate: Improve level 5+6 compression #367
    • s2: Improve better/best compression #358 #359
    • s2: Load after checking src limit on amd64. #362
    • s2sx: Limit max executable size #368
  • 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)

    • zstd: Big speedup on small dictionary encodes #344 #345
    • zstd: Add WithLowerEncoderMem encoder option #336
    • deflate: Improve entropy compression #338
    • s2: Clean up and minor performance improvement in best #341
  • Mar 5, 2021 (v1.11.12)

  • Mar 1, 2021 (v1.11.9)

    • s2: Add ARM64 decompression assembly. Around 2x output speed. #324
    • s2: Improve "better" speed and efficiency. #325
    • s2: Fix binaries.
  • Feb 25, 2021 (v1.11.8)

    • s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
    • s2: Add AMD64 assembly for better mode. 25-50% faster. #315
    • s2: Less upfront decoder allocation. #322
    • zstd: Faster "compression" of incompressible data. #314
    • zip: Fix zip64 headers. #313
  • Jan 14, 2021 (v1.11.7)

    • Use Bytes() interface to get bytes across packages. #309
    • s2: Add 'best' compression option. #310
    • s2: Add ReaderMaxBlockSize, changes s2.NewReader signature to include varargs. #311
    • s2: Fix crash on small better buffers. #308
    • s2: Clean up decoder. #312
  • Jan 7, 2021 (v1.11.6)

    • zstd: Make decoder allocations smaller #306
    • zstd: Free Decoder resources when Reset is called with a nil io.Reader #305
  • Dec 20, 2020 (v1.11.4)

    • zstd: Add Best compression mode #304
    • Add header decoder #299
    • s2: Add uncompressed stream option #297
    • Simplify/speed up small blocks with known max size. #300
    • zstd: Always reset literal dict encoder #303
  • Nov 15, 2020 (v1.11.3)

    • inflate: 10-15% faster decompression #293
    • zstd: Tweak DecodeAll default allocation #295
  • 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)

    • zstd: Fix extra block when compressing with ReadFrom. #278
    • huff0: Also populate compression table when reading decoding table. #275
  • June 23, 2020 (v1.10.10)

    • zstd: Skip entropy compression in fastest mode when no matches. #270
  • June 16, 2020 (v1.10.9):

    • zstd: API change for specifying dictionaries. See #268
    • zip: update CreateHeaderRaw to handle zip64 fields. #266
    • Fuzzit tests removed. The service has been purchased and is no longer available.
  • 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)

    • zstd: Reduce allocations while decoding. #258, #252
    • zstd: Stricter decompression checks.
  • 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)

    • s2: Use S2 encoder in pure Go mode for Snappy output as well. #245
    • s2: Fix pure Go block encoder. #244
    • zstd: Added "better compression" mode. #240
    • zstd: Improve speed of fastest compression mode by 5-10% #241
    • zstd: Skip creating encoders when not needed. #238
  • Feb 27, 2020: (v1.10.2)

    • Close to 50% speedup in inflate (gzip/zip decompression). #236 #234 #232
    • Reduce deflate level 1-6 memory usage up to 59%. #227
  • Feb 18, 2020: (v1.10.1)

    • Fix zstd crash when resetting multiple times without sending data. #226
    • deflate: Fix dictionary use on level 1-6. #224
    • Remove deflate writer reference when closing. #224
  • Feb 4, 2020: (v1.10.0)

    • Add optional dictionary to stateless deflate. Breaking change, send nil for 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

  • 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) to s2c and s2d commands

  • Sep 16, 2019: (v1.8.4) Add s2c and s2d commandline 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

  • Aug 4, 2019: Faster zstd compression. #143 #144

  • Aug 4, 2019: Faster zstd decompression. #145 #143 #142

  • 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:

go
// 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):

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:

text
$ go get github.com/mitchellh/mapstructure

Usage & 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:

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:

go
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:

go
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:

go
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.

  1. 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:

    go
    import (
        _ "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.

  2. Even though digest.Digest may be assemblable as a string, always verify your input with digest.Parse or use Digest.Validate when accepting untrusted input.
    While there are measures to avoid common problems, this will ensure you have valid digests in the rest of your application.

  3. 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 © 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

text
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

go
var Stderr io.Writer = os.Stderr

Stderr is the io.Writer to which executed commands write standard error.

go
var Stdout io.Writer = os.Stdout

Stdout is the io.Writer to which executed commands write standard output.

func OpenFile

go
func OpenFile(path string) error

OpenFile opens new browser window for the file path.

func OpenReader

go
func OpenReader(r io.Reader) error

OpenReader consumes the contents of r and presents the
results in a new browser window.

func OpenURL

go
func OpenURL(url string) error

OpenURL 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, _ratio based 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

bash
go get github.com/prometheus/otlptranslator

Quick Start

go
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

go
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_ratio

Label Translation

go
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_symbols

Unit Translation

go
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

go
// 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.

go
fs, err := procfs.NewFS("/proc")
stats, err := fs.Stat()

Some sub-packages such as blockdevice, require access to both the proc and sys filesystems.

go
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.

bash
rm -rf testdata/fixtures
make test

Next, 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 using
git 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:

json lines
{"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:

bash
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=9009

To ensure this behaviour even if a TTY is attached, set your formatter as follows:

go
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:

go
logrus.SetReportCaller(true)

This adds the caller as 'method' like so:

json
{"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"}
bash
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin

Note 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:

bash
go test -bench=ReportCaller

Case-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:

go
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:

go
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:

go
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:

go
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 the
printf-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 the
request_id and user_ip in the context of a request. Instead of writing
logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip}) on
every line, you can create a logrus.Entry to pass around instead:

go
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, in
init:

go
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.

go
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:

go
// 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:

  1. time. The timestamp when the entry was created.
  2. msg. The logging message passed to {Info,Warn,Error,Fatal,Panic} after
    the AddFields call. E.g. Failed to send event.
  3. 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:

go
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 to true. To force no colored output even if there is a TTY set the
      DisableColors field to true.
    • 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 set ForceColors (or CLICOLOR_FORCE=1) to enable colors through the wrapper.
    • When colors are enabled, levels are truncated to 4 characters by default. To disable
      truncation set the DisableLevelTruncation field to true.
    • 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 PadLevelText field to true enables this behavior, by adding padding to the level text.
  • logrus.JSONFormatter
    logs fields as JSON.

Third-party logging formatters:

You can define your formatter by implementing the Formatter interface,
requiring a Format method. Format takes an *Entry. entry.Data is a
Fields type (map[string]any) with all your fields as well as the
default ones (see Entries section above):

go
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.

go
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:

go
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.NewLocal and test.NewGlobal) which basically just adds the test hook
  • a test logger (test.NewNullLogger) that just records log messages (and does not output any):
go
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.

go
// ...
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:

    1. logger.Out is protected by locks.

    2. logger.Out is an os.File handler opened with O_APPEND flag, 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 mean app 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 is
APPNAME VERB NOUN --ADJECTIVE
or
APPNAME 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:

text
hugo server --port=1313

In this command we are telling Git to clone the url bare.

text
git clone URL --bare

Commands

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.

More about cobra.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.

text
go get -u github.com/spf13/cobra@latest

Next, include Cobra in your application:

go
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:

text
go install github.com/spf13/cobra-cli@latest

For 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:

text
go get github.com/spf13/pflag

Run tests by running:

text
go test github.com/spf13/pflag

Usage

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.

go
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.

go
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.

go
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

go
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

go
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.

go
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.

go
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.

go
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:

go
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

text
--flag    // boolean flags, or flags with no option default values
--flag x  // only on flags without a default value
--flag=x

Unlike 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

text
// 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"
-abcs1234

Flag 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

go
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

go
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.

go
// 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".

go
// 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.

go
// 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:

go
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:

text
-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

go
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:

bash
go test /your/tests -run ^YourTest -v --your-test-pflags

will 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()

go
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:

text
go get go.yaml.in/yaml/v2

API 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

go
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:

text
--- 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
  - 4

Overview (`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 are true/false only.
  • Supports octals encoded and decoded as 0777 per YAML 1.1, rather than
    0o777 as specified in YAML 1.2, because most parsers still use the old
    format.
    Octals in the 0o777 format 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:

bash
go get go.yaml.in/yaml/v3

API 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

go
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:

text
--- 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
  - 4

License

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

bash
go get cloud.google.com/go/compute/metadata

Go 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:

text
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

go
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 *
    • READONLY
    • READWRITE
  • Key
    • DUMP
    • MIGRATE
    • OBJECT
    • RESTORE
    • WAIT
  • Scripting
    • FCALL / FCALL_RO *
    • FUNCTION *
    • SCRIPT DEBUG
    • SCRIPT KILL
  • Server
    • BGSAVE
    • BGWRITEAOF
    • CLIENT *
    • CONFIG *
    • DEBUG *
    • LASTSAVE
    • MONITOR
    • ROLE
    • SAVE
    • SHUTDOWN
    • SLAVEOF
    • SLOWLOG
    • SYNC

&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:

text
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
    func New() *Digest

The Digest type implements hash.Hash64. Its key methods are:

text
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64

The 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:

text
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:

text
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 or
NewSigner. 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. The
jose-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


GoReference

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 the
MIGRATION_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
of jwt-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

  1. To install the jwt package, you first need to have
    Go installed, then you can use the command
    below to add jwt-go as a dependency in your Go program.
sh
go get -u github.com/golang-jwt/jwt/v5
  1. Import it in your code:
go
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:

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 using
    alg=none will only be accepted if the constant
    jwt.UnsafeAllowNoneSignatureType is 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 from
main. You can find all the releases on the project releases
page
.

BREAKING CHANGES: A full list of breaking changes is available in
VERSION_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 a
jwt.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 and
Compress4X 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 the
Scratch 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 the
io.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:

go
// 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.

go
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.

  • file is the input file.
  • out is the compressor used. zskp is this package. zstd is the Datadog cgo library. gzstd/gzkp is gzip standard and this library.
  • level is the compression level used. For zskp level 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best".
  • insize/outsize is the input/output size.
  • millis is the number of milliseconds used for compression.
  • mb/s is megabytes (2^20 bytes) per second.
text
/* 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:

go
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:

go
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:

  1. Reads input and splits the input into blocks.
  2. Decompression of literals.
  3. Decompression of sequences.
  4. 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.

text
/* 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`)

See .


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

Try the Redis Cloud

Dive in developer tutorials

Join the Redis community

Work at Redis

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

Installation

go-redis supports 2 last Go versions and requires a Go version with
modules support. So make sure to initialize a Go
module:

shell
go mod init github.com/my/repo

Then install go-redis/v9:

shell
go get github.com/redis/go-redis/v9

Quickstart

go
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:

go
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.

go
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:

go
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:

go
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:

go
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:

go
// 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:

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/:

shell
ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src
cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/

Lastly, run:

shell
go test

Another option is to run your specific tests with an already running redis. The example below, tests
against a redis running on port 9999.:

shell
REDIS_PORT=9999 go test <your options>

See also

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

golang
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 detect
container.name, k8s.pod.name and k8s.namespace.name. When using this detector,
you should use this in your Pod Spec to set these using
OTEL_RESOURCE_ATTRIBUTES:

yaml
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:

golang
...
// 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:

text
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 in
syscall_${GOOS}.go.

types files

For each OS, there is a hand-written Go file at ${GOOS}/types.go (or
types_${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 to
ztypes_${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:

  1. Construct the set of common code that is identical in all architecture-specific files.
  2. Write this common code to the merged file.
  3. 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.

bash
go get github.com/Azure/azure-sdk-for-go/sdk/azcore

General 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:

sh
go get -u github.com/Azure/azure-sdk-for-go/sdk/azidentity

Prerequisites

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):

Examples

Authenticate with DefaultAzureCredential

This example demonstrates authenticating a client from the armresources module with DefaultAzureCredential.

go
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.

go
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:

go
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


Apache License

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_CREDENTIALS environment 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.:

golang
projectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
opts := []mexporter.Option{
    mexporter.WithProjectID(projectID),
}

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.

console
export OTEL_GO_X_RESOURCE=true

Disable experimental resource semantic conventions.

console
unset OTEL_GO_X_RESOURCE

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/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

bash
az storage account create --name MyStorageAccount --resource-group MyResourceGroup --location westus --sku Standard_LRS

Install the package

Install the Azure Blob Storage client module for Go with go get:

bash
go get github.com/Azure/azure-sdk-for-go/sdk/storage/azblob

If you plan to authenticate with Azure Active Directory (recommended), also install the azidentity module.

bash
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity

Authenticate 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.

go
// 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 err

Learn 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

go
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 error

Download a blob

go
// 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 error

Enumerate blobs

go
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.

go
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:

text
func Sum64(b []byte) uint64
func Sum64String(s string) uint64
type Digest struct{ ... }
    func New() *Digest

The Digest type implements hash.Hash64. Its key methods are:

text
func (*Digest) Write([]byte) (int, error)
func (*Digest) WriteString(string) (int, error)
func (*Digest) Sum64() uint64

The 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:

text
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

bash
go get github.com/redis/go-redis/extra/redisotel/v9

Usage

Tracing is enabled by adding a hook:

go
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.inflight
  • otel.sdk.exporter.metric_data_point.exported
  • otel.sdk.metric_reader.collection.duration
  • otel.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.created
  • otel.sdk.processor.log.queue.capacity
  • otel.sdk.processor.log.queue.size
  • otel.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.

console
export OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE=200

Disable metric export batching.

console
unset OTEL_GO_X_METRIC_EXPORT_BATCH_SIZE

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/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:

From this directory run the following command:

sh
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.inflight
  • otel.sdk.exporter.log.exported
  • otel.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.inflight
  • otel.sdk.exporter.metric_data_point.exported
  • otel.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.inflight
  • otel.sdk.exporter.span.exported
  • otel.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.inflight
  • otel.sdk.exporter.log.exported
  • otel.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.inflight
  • otel.sdk.exporter.log.exported
  • otel.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.inflight
  • otel.sdk.exporter.span.exported
  • otel.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

sh
docker run -d -p 5000:5000 --name registry registry:3

Pull (or build) some image from the hub

sh
docker pull ubuntu

Tag the image so that it points to your registry

sh
docker image tag ubuntu localhost:5000/myfirstimage

Push it

sh
docker push localhost:5000/myfirstimage

Pull it back

sh
docker pull localhost:5000/myfirstimage

Now stop your registry and remove all data

sh
docker container stop registry && docker container rm -v registry

Next

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 tags 2.8 and 3.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 ubuntu instructs docker to pull an image named ubuntu from Docker Hub. This is simply a shortcut for the longer docker pull docker.io/library/ubuntu command
  • docker pull myregistrydomain:port/foo/bar instructs docker to contact the registry located at myregistrydomain:port to find the image foo/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.crt and domain.key, for the CN myregistrydomain.com
  • be sure you have stopped and removed any previously running registry (typically docker container stop registry && docker container rm -v registry)

The List


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 the
factory.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:

Writing new storage drivers

To create a valid storage driver, one must implement the
storagedriver.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 in
storagedriver/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:

text
docker run -d -p 5000:5000 --restart always --name registry distribution/distribution:edge

NOTE: 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

text
{
     "insecure-registries": ["host.docker.internal:5000"]
}

Now you are ready to use it:

text
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 the
filesystem storage driver run the following command:

text
docker run -d -p 5000:5000 -v $PWD/FS/PATH:/var/lib/registry --restart always --name registry distribution/distribution:edge

Custom configuration

If you don't wan to use the default configuration file, you can supply
your own custom configuration file as follows:

text
docker run -d -p 5000:5000 -v $PWD/PATH/TO/config.yml:/etc/distribution/config.yml --restart always --name registry distribution/distribution:edge

Communication

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:

  1. Read-After-Write consistency (see this article on
    s3
    ).
  2. Write-Write Conflicts.

In reality, the registry must worry about these kinds of errors when doing the
following:

  1. Accepting data into a temporary upload file may not have latest data block
    yet (read-after-write).
  2. Moving uploaded data into its blob location (write-write race).
  3. Modifying the "current" manifest for given tag (write-write race).
  4. 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:

  1. Large writes are done to private upload directories. This alleviates most
    of the corruption potential under multiple writers by avoiding multiple
    writers.
  2. Constraints in storage driver implementations, such as support for writing
    after the end of a file to extend it.
  3. Digest verification to avoid data corruption.
  4. Manifest files are stored by digest and cannot change.
  5. 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 named
REGISTRY_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:

yaml
storage:
  filesystem:
    rootdirectory: /var/lib/registry

To override this value, set an environment variable like this:

sh
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhere

This 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:

yaml
http:
  tls:
    letsencrypt:
      hosts: [myregistryaddress.org]

The corresponding environment variable would be:

sh
REGISTRY_HTTP_TLS_LETSENCRYPT_HOSTS_0=registry.example.com

Note: 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:

bash
$ docker run -d -p 5000:5000 --restart=always --name registry \
             -v `pwd`/config.yml:/etc/distribution/config.yml \
             registry:3

Use 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.

text
/* 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`

yaml
version: 0.1

The 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.

yaml
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`

yaml
accesslog:
  disabled: true

Within 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`

yaml
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.

yaml
loglevel: debug

Permitted values are error, warn, info and debug. The default is
info.

`storage`

text
/* 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 the
filesystem 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:

text
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: age and interval are 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:

yaml
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, blobdescriptor was known as layerinfo. While these
are equivalent, layerinfo has 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.

yaml
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:

yaml
redirect:
  disable: true

`auth`

yaml
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/htpasswd

The 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 is
bcrypt. 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 htpasswd file 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 htpasswd authentication 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 the
distribution.Namespace interface, while a repository middleware must implement
distribution.Repository, and a storage middleware must implement
driver.StorageDriver.

This is an example configuration of the cloudfront middleware, a storage
middleware:

yaml
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.json

Each middleware entry has name and options entries. The name must
correspond to the name under which the middleware registers itself. The
options 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 a
400 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.

yaml
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.

yaml
tags: 
  maxtags: 100
Parameter Required Description
maxtags no Overrides the maximum number of tags returned by the tags endpoint, default: 1000

`http`

yaml
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: false

The 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 port 443. The registry defaults to listening on port 5000.
If you run the registry as a container, consider adding the flag -p 443:5000
to the docker run command or using a similar setting in a cloud
configuration. You should also set the hosts option 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 the ca-certificates package 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`

yaml
prometheus:
  enabled: true
  path: /metrics

The 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`

yaml
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:
           - pull

The 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 mediatypes to filter by media type.
  • Only actions to 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.

yaml
redis:
  addrs:
    - sentinel1.example.com:26379
    - sentinel2.example.com:26379
    - sentinel3.example.com:26379
  mastername: mymaster

The equivalent environment variable for the master name is
REGISTRY_REDIS_MASTERNAME. If authentication is required, use username and
password 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.

yaml
# 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`

yaml
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: 3

The 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 with
HEAD 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`

yaml
proxy:
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
  ttl: 168h

The 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`

yaml
validation:
  disabled: false

Use 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. If
disabled is false, the validation allows nothing.

`urls`

yaml
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:

  1. deny is unset.
  2. deny is set but no URLs within the manifest match any of the deny regular
    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.

yaml
validation:
  manifests:
    indexes:
      platforms: [all|none|list]
      platformlist:
      - os: linux
        architecture: amd64

Use 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 the
platformlist 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:

yaml
version: 0.1
log:
  level: debug
storage:
    filesystem:
        rootdirectory: /var/lib/registry
http:
    addr: localhost:5000
    secret: asecretforlocaldevelopment
    debug:
        addr: localhost:5001

This example configures the registry instance to run on port 5000, binding to
localhost, 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:

yaml
middleware:
  storage:
  - name: cloudfront
    disabled: false
    options:
      baseurl: http://d111111abcdef8.cloudfront.net
      privatekey: /path/to/asecret.pem
      keypairid: asecret
      duration: 60s

See 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:

console
$ docker run -d -p 5000:5000 --restart=always --name registry registry:3

The 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 to debug. 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 at
localhost:4318. If this is not desired, telemetry can be disabled by adding
-e OTEL_TRACES_EXPORTER=none to the docker run command 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, the
ubuntu:16.04 and my-ubuntu images are deleted locally and the
my-ubuntu image is pulled from the local registry.

  1. Pull the ubuntu:16.04 image from Docker Hub.

    console
    $ docker pull ubuntu:16.04
  2. Tag 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-ubuntu
  3. Push the image to the local registry running at localhost:5000:

    console
    $ docker push localhost:5000/my-ubuntu
  4. Remove the locally-cached ubuntu:16.04 and localhost:5000/my-ubuntu
    images, so that you can test pulling the image from your registry. This
    does not remove the localhost:5000/my-ubuntu image from your registry.

    console
    $ docker image remove ubuntu:16.04
    $ docker image remove localhost:5000/my-ubuntu
  5. Pull the localhost:5000/my-ubuntu image 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.

console
$ docker container stop registry

To remove the container, use docker container rm.

console
$ docker container stop registry && docker container rm -v registry

Basic configuration

To configure the container, you can pass additional or modified options to the
docker 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.

console
$ docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  registry:3

Customize 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 it
registry-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.

console
$ docker run -d \
  -p 5001:5000 \
  --name registry-test \
  registry:3

If 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:

console
$ docker run -d \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:5001 \
  -p 5001:5001 \
  --name registry-test \
  registry:3

Storage 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/.

console
$ docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v /mnt/registry:/var/lib/registry \
  registry:3

Customize 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.

  1. Create a certs directory.

    console
    $ mkdir -p certs

    Copy the .crt and .key files from the CA into the certs directory.
    The following steps assume that the files are named domain.crt and
    domain.key.

  2. Stop the registry if it is currently running.

    console
    $ docker container stop registry
  3. Restart the registry, directing it to use the TLS certificate. This command
    bind-mounts the certs/ directory into the container at /certs/, and sets
    environment variables that tell the container where to find the domain.crt
    and domain.key file. 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:3
  4. Docker 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:

console
cat domain.crt intermediate-certificates.pem > certs/domain.crt

You 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:

console
$ docker secret create domain.crt certs/domain.crt

$ docker secret create domain.key certs/domain.key

Next, 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 for
node1 below.

console
$ docker node update --label-add registry=true node1

Next, 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>.

console
$ 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:3

You 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 the
X-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 >}}

  1. Create a password file with one entry for the user testuser, with password
    testpassword:

    console
    $ mkdir auth
    $ docker run \
      --entrypoint htpasswd \
      httpd:2 -Bbn testuser testpassword > auth/htpasswd

    On Windows, make sure the output file is correctly encoded:

    powershell
    docker run --rm --entrypoint htpasswd httpd:2 -Bbn testuser testpassword | Set-Content -Encoding ASCII auth/htpasswd
  2. Stop the registry.

    console
    $ docker container stop registry
  3. Start 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:3
  4. Try to pull an image from the registry, or push an image to the registry.
    These commands fail.

  5. Log in to the registry.

    console
    $ docker login myregistrydomain.com:5000

    Provide 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.

yaml
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:

console
$ docker compose up -d

Considerations 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 run docker pull to 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.

    1. Edit the daemon.json file, which is located in /etc/docker/ on Linux
      hosts and C:\ProgramData\docker\config\daemon.json on 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.

    2. Restart Docker.

    3. Restart the registry if it does not start automatically.

    4. 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:


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:

text
A -----> a <----- B
    \--> b     |
         c <--/

Manifest B is deleted via the API:

text
A -----> a     B
    \--> b
         c

In 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.

text
A -----> a
    \--> b

More 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:

yaml
version: 0.1
storage:
  filesystem:
    rootdirectory: /registry/data

Sample output from a dry run garbage collection with registry log level set to info

text
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:f251d679a7c61455f06d793e43c06786d7766c88b8c24edf242b2c08e3c3f599

The --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:


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.

  1. Edit the daemon.json file, whose default location is
    /etc/docker/daemon.json on Linux or
    C:\ProgramData\docker\config\daemon.json on 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.json file 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.

  2. 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.

  1. 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.crt

    Be sure to use the name myregistry.domain.com as a CN.

  2. Use the result to start your registry with TLS enabled.

  3. Instruct every Docker daemon to trust that certificate. The way to do this
    depends on your OS.

    • Linux: Copy the domain.crt file to
      /etc/docker/certs.d/myregistrydomain.com:5000/ca.crt on every Docker
      host. You do not need to restart Docker.

    • Windows Server:

      1. 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 |

      2. Click Browser and select Trusted Root Certificate Authorities.

      3. 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:

none
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.crt

Docker 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

console
$ cp certs/domain.crt /usr/local/share/ca-certificates/myregistrydomain.com.crt
update-ca-certificates

Red Hat Enterprise Linux

console
$ cp certs/domain.crt /etc/pki/ca-trust/source/anchors/myregistrydomain.com.crt
update-ca-trust

Oracle Linux

console
$ update-ca-trust enable

Restart 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:

yaml
notifications:
  endpoints:
    - name: alistener
      url: https://mylistener.example.com/event
      headers:
        Authorization: [Bearer <your token, if needed>]
      timeout: 500ms
      threshold: 5
      backoff: 1s

The above would configure the registry with an endpoint to send events to
https://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:

text
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=registry

Events

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:

json
{
  "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.

json
{
  "target": {
    "digest": "sha256:d89e1bee20d9cb344674e213b581f14fbd8e70274ecf9d10c514bab78a307845",
    "repository": "library/test"
  }
}

Note: As of version 2.1, the length field for event targets
is being deprecated for the size field, bringing the target in line with
common nomenclature. Both will continue to be set for the foreseeable
future. Newer code should favor size but accept either.

Envelope

The envelope contains one or more events, with the following json structure:

json
{
  "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:

text
/* 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:

json
{
  "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:

none
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 off

The 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:

text
/* Detailed source-code truncated for AI context efficiency. */

Starting and stopping

Now, start your stack:

console
$ docker compose up -d

Log in with a "push" authorized user (using testuserpush and testpasswordpush), then tag and push your first image:

console
$ docker login myregistrydomain.com:5043
$ docker tag ubuntu myregistrydomain.com:5043/test
$ docker push myregistrydomain.com:5043/test

Now, log in with a "pull-only" user (using testuser and testpassword), then pull back the image:

console
$ docker login myregistrydomain.com:5043
$ docker pull myregistrydomain.com:5043/test

Verify that the "pull-only" can NOT push:

console
$ docker push myregistrydomain.com:5043/test

Content 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 a
proxy section is required to the config file.

To access private images on the Docker Hub, a username and password can
be supplied.

yaml
proxy:
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
  ttl: 168h

Warning: 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, delete must
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.

json
{
  "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 level field to determine whether
the message is warning you about an error or is giving you information.
For example, this log message is informational:

conf
time="2017-06-02T15:47:37Z" level=info msg="error statting local store, serving from upstream: unknown blob" go.version=go1.7.4

It'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:5000 without
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:

none
X-Real-IP
X-Forwarded-For
X-Forwarded-Proto

So if you have an Nginx instance sitting behind it, remove these lines from the
example config below:

none
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.

  1. Create the required directories

    console
    $ mkdir -p auth data
  2. Create 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. */

text
3. Create a password file `auth/nginx.htpasswd` for "testuser" and "testpassword".

   ```console
   $ docker run --rm --entrypoint htpasswd httpd -Bbn testuser testpassword > auth/nginx.htpasswd

Note: If you do not want to use bcrypt, you can omit the -B parameter.

  1. Copy your certificate files to the auth/ directory.

    console
    $ cp domain.crt auth
    $ cp domain.key auth
  2. Create the compose file. Paste the following YAML into a new file called docker-compose.yml.

    yaml
    services:
        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:

consonle
$ docker compose up -d

Login with a "push" authorized user (using testuser and testpassword), then
tag and push your first image:

console
$ 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/test

Content 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:

console
$ 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.2

If you want to understand, you should read How to Write Go Code.

Checkout the source tree

console
$ 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/distribution

Build the binary

console
$ GOPATH=$(PWD)/Godeps/_workspace:$GOPATH make binaries
$ sudo mkdir -p /usr/local/libexec
$ sudo cp bin/registry /usr/local/libexec/registry

Setup

Copy the registry configuration file in place:

console
$ mkdir /Users/Shared/Registry
$ cp docs/content/recipes/osx/config.yml /Users/Shared/Registry/config.yml

Modify 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:

console
$ 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.plist

Start the registry:

console
$ launchctl load ~/Library/LaunchAgents/com.docker.registry.plist

Restart the registry service

console
$ launchctl stop com.docker.registry
$ launchctl start com.docker.registry

Unload the registry service

console
$ launchctl unload ~/Library/LaunchAgents/com.docker.registry.plist

Content 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

ini
[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.target

In 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

sh
podman create --name registry --network=none -v registry:/var/lib/registry registry:3
podman generate systemd --name --new registry > registry.service

Create socket file

registry.socket

ini
[Unit]
Description=Distribution registry

[Socket]
ListenStream=5000

[Install]
WantedBy=sockets.target

Installation

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
  • Start the service:
    • When using socket activation: systemctl start registry.socket
    • When not using socket activation: systemctl start registry.service

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
  • Start the service:
    • When using socket activation: systemctl --user start registry.socket
    • When not using socket activation: systemctl --user start registry.service

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 http
Range 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:

none
/v2/<name>/

For example, an API endpoint that will work with the library/ubuntu
repository, the URI prefix will be:

text
/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:

  1. 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]+)*.
  2. If a repository name has two or more path components, they must be
    separated by a forward slash ("/").
  3. 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:

none
{
        "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 optional
detail 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:

none
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:

text
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:

text
let C = 'a small string'
let B = sha256(C)
let D = 'sha256:' + EncodeHex(B)
let ID(C) = D

Above, 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 a
Docker-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 header
Docker-Content-Digest should 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