Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2ea9bc90b | |||
| 44fdac11f5 | |||
| 893e52cf4b | |||
| 62eae52c2a | |||
| 2012fbf111 | |||
| 42d1c02750 | |||
| 3967b7d28e | |||
| 0b924e51fc | |||
| 6288e8b1ac | |||
| 1e9575e81a | |||
| c98e9c47ca | |||
| a6f6b5fa34 | |||
| 8437cfefae | |||
| 68a5ca859f | |||
| f9d091f4b1 | |||
| e9b8231d6a | |||
| 8a64739631 | |||
| a555c853b0 | |||
| 260ba1a8a2 | |||
| f63cb8b97e | |||
| c1492eabde | |||
| 48e6b44379 | |||
| bfcd17b5b7 | |||
| 8279b718ea | |||
| 644c003606 | |||
| 0d17280a30 | |||
| eedfe50a99 | |||
| f3dd1ee6c1 | |||
| c7cf60f657 | |||
| 1d37fb3027 | |||
| 0793f96394 | |||
| b639ea8b89 | |||
| 063e3dd329 | |||
| 0168626037 | |||
| 00ea8bdc41 | |||
| e3a9a92b14 | |||
| 6da4ee40c7 | |||
| ab733b5564 | |||
| f0df35096d | |||
| f485f66943 | |||
| 746c553574 | |||
| 2945ba4f7a | |||
| 032e485e1c | |||
| 88de81ff21 | |||
| 706ca7985b | |||
| e0d47b1c0b | |||
| 54b529feae | |||
| c88e6432ec | |||
| f291a49ba5 | |||
| 78fcd905c6 | |||
| 12e2f94eba | |||
| 00755d7dba | |||
| 8264f5be8d | |||
| 9780f41efe | |||
| 4fbdf3f362 | |||
| 1ff45aac40 | |||
| bb03b9d3c2 | |||
| ed71df1b9f | |||
| ee20fa1ec4 | |||
| ffe40dc6b6 | |||
| 7ab2d19a1e | |||
| 4630fe0075 | |||
| fbbf1be52d | |||
| 3de2cc6efd | |||
| 234036d105 | |||
| 0c442dc179 | |||
| 6b48c78672 | |||
| 370c28948e | |||
| dc017bdda3 | |||
| feb6f439e3 | |||
| 8bc4062fc0 | |||
| 84cc7d87cc | |||
| c1c3d3b3aa | |||
| 048a846146 | |||
| 33dacda24f | |||
| fcc05e5ea1 | |||
| 58061d25f6 | |||
| 55b2abb0ca | |||
| 4c3b87d922 | |||
| e77605c83d | |||
| 0196098721 | |||
| 6ebf765040 | |||
| f508ce9db7 | |||
| 897293c7c7 | |||
| 2c04354315 | |||
| 9c8a91d22b | |||
| ff945151ef | |||
| 4571d90f20 | |||
| 55c4c88966 | |||
| f33a69f6ee | |||
| d3cb89ee53 | |||
| 433014bcfb | |||
| 61cb016851 | |||
| 53c4602909 | |||
| 830d6595e7 | |||
| 13048444cc | |||
| 3e293e6bd1 | |||
| 41b3ea7e47 | |||
| d6eeeb6259 | |||
| 3e157d5293 | |||
| 1fdf84b8e9 | |||
| 376b99c6d6 | |||
| 0de4e6e9a7 | |||
| 3c87f01b18 | |||
| de40c2b172 | |||
| d513e46bfc | |||
| 2b74b90efb | |||
| 05343b36a2 | |||
| f90db254d7 | |||
| 0dcfdde336 | |||
| 03cd1dc50a | |||
| 42811a7eb9 | |||
| be966aa194 | |||
| b22fe0fb14 | |||
| 4eb050071e | |||
| 08c4fdfa7a | |||
| 6aa1b37c8d | |||
| e82920d76d | |||
| 82123939f7 |
@ -4,13 +4,13 @@ jobs:
|
||||
|
||||
lint:
|
||||
working_directory: /work
|
||||
docker: [{image: 'docker:19.03-git'}]
|
||||
docker: [{image: 'docker:20.10-git'}]
|
||||
environment:
|
||||
DOCKER_BUILDKIT: 1
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 19.03.12
|
||||
version: 20.10.6
|
||||
reusable: true
|
||||
exclusive: false
|
||||
- run:
|
||||
@ -39,14 +39,15 @@ jobs:
|
||||
|
||||
cross:
|
||||
working_directory: /work
|
||||
docker: [{image: 'docker:19.03-git'}]
|
||||
docker: [{image: 'docker:20.10-git'}]
|
||||
environment:
|
||||
DOCKER_BUILDKIT: 1
|
||||
BUILDX_VERSION: "v0.5.1"
|
||||
parallelism: 3
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 19.03.12
|
||||
version: 20.10.6
|
||||
reusable: true
|
||||
exclusive: false
|
||||
- run:
|
||||
@ -55,33 +56,26 @@ jobs:
|
||||
- run:
|
||||
name: "Docker info"
|
||||
command: docker info
|
||||
- run:
|
||||
name: "Cross - build image"
|
||||
command: |
|
||||
docker build --progress=plain -f dockerfiles/Dockerfile.cross --tag cli-builder:$CIRCLE_BUILD_NUM .
|
||||
- run:
|
||||
name: "Cross"
|
||||
command: |
|
||||
name=cross-$CIRCLE_BUILD_NUM-$CIRCLE_NODE_INDEX
|
||||
docker run \
|
||||
-e CROSS_GROUP=$CIRCLE_NODE_INDEX \
|
||||
--name $name cli-builder:$CIRCLE_BUILD_NUM \
|
||||
make cross
|
||||
docker cp \
|
||||
$name:/go/src/github.com/docker/cli/build \
|
||||
/work/build
|
||||
- run: apk add make curl
|
||||
- run: mkdir -vp ~/.docker/cli-plugins/
|
||||
- run: curl -fsSL --output ~/.docker/cli-plugins/docker-buildx https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-amd64
|
||||
- run: chmod a+x ~/.docker/cli-plugins/docker-buildx
|
||||
- run: docker buildx version
|
||||
- run: docker context create buildctx
|
||||
- run: docker buildx create --use buildctx && docker buildx inspect --bootstrap
|
||||
- run: GROUP_INDEX=$CIRCLE_NODE_INDEX GROUP_TOTAL=$CIRCLE_NODE_TOTAL docker buildx bake cross --progress=plain
|
||||
- store_artifacts:
|
||||
path: /work/build
|
||||
|
||||
test:
|
||||
working_directory: /work
|
||||
docker: [{image: 'docker:19.03-git'}]
|
||||
docker: [{image: 'docker:20.10-git'}]
|
||||
environment:
|
||||
DOCKER_BUILDKIT: 1
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 19.03.12
|
||||
version: 20.10.6
|
||||
reusable: true
|
||||
exclusive: false
|
||||
- run:
|
||||
@ -122,13 +116,13 @@ jobs:
|
||||
|
||||
validate:
|
||||
working_directory: /work
|
||||
docker: [{image: 'docker:19.03-git'}]
|
||||
docker: [{image: 'docker:20.10-git'}]
|
||||
environment:
|
||||
DOCKER_BUILDKIT: 1
|
||||
steps:
|
||||
- checkout
|
||||
- setup_remote_docker:
|
||||
version: 19.03.12
|
||||
version: 20.10.6
|
||||
reusable: true
|
||||
exclusive: false
|
||||
- run:
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
.circleci
|
||||
.dockerignore
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
appveyor.yml
|
||||
|
||||
3
.gitignore
vendored
@ -8,8 +8,7 @@
|
||||
Thumbs.db
|
||||
.editorconfig
|
||||
/build/
|
||||
cli/winresources/rsrc_386.syso
|
||||
cli/winresources/rsrc_amd64.syso
|
||||
cli/winresources/rsrc_*.syso
|
||||
/man/man1/
|
||||
/man/man5/
|
||||
/man/man8/
|
||||
|
||||
61
Dockerfile
Normal file
@ -0,0 +1,61 @@
|
||||
# syntax=docker/dockerfile:1.3
|
||||
|
||||
ARG BASE_VARIANT=alpine
|
||||
ARG GO_VERSION=1.16.8
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-${BASE_VARIANT} AS gostable
|
||||
FROM --platform=$BUILDPLATFORM golang:1.17rc1-${BASE_VARIANT} AS golatest
|
||||
|
||||
FROM gostable AS go-linux
|
||||
FROM gostable AS go-darwin
|
||||
FROM gostable AS go-windows-amd64
|
||||
FROM gostable AS go-windows-386
|
||||
FROM gostable AS go-windows-arm
|
||||
FROM golatest AS go-windows-arm64
|
||||
FROM go-windows-${TARGETARCH} AS go-windows
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx@sha256:620d36a9d7f1e3b102a5c7e8eff12081ac363828b3a44390f24fa8da2d49383d AS xx
|
||||
|
||||
FROM go-${TARGETOS} AS build-base-alpine
|
||||
COPY --from=xx / /
|
||||
RUN apk add --no-cache clang lld llvm file git
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
|
||||
FROM build-base-alpine AS build-alpine
|
||||
ARG TARGETPLATFORM
|
||||
# gcc is installed for libgcc only
|
||||
RUN xx-apk add --no-cache musl-dev gcc
|
||||
|
||||
FROM go-${TARGETOS} AS build-base-buster
|
||||
COPY --from=xx / /
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y clang lld file
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
|
||||
FROM build-base-buster AS build-buster
|
||||
ARG TARGETPLATFORM
|
||||
RUN xx-apt install --no-install-recommends -y libc6-dev libgcc-8-dev
|
||||
|
||||
FROM build-${BASE_VARIANT} AS build
|
||||
# GO_LINKMODE defines if static or dynamic binary should be produced
|
||||
ARG GO_LINKMODE=static
|
||||
# GO_BUILDTAGS defines additional build tags
|
||||
ARG GO_BUILDTAGS
|
||||
# GO_STRIP strips debugging symbols if set
|
||||
ARG GO_STRIP
|
||||
# CGO_ENABLED manually sets if cgo is used
|
||||
ARG CGO_ENABLED
|
||||
# VERSION sets the version for the produced binary
|
||||
ARG VERSION
|
||||
RUN --mount=ro --mount=type=cache,target=/root/.cache \
|
||||
--mount=from=dockercore/golang-cross:xx-sdk-extras,target=/xx-sdk,src=/xx-sdk \
|
||||
--mount=type=tmpfs,target=cli/winresources \
|
||||
xx-go --wrap && \
|
||||
# export GOCACHE=$(go env GOCACHE)/$(xx-info)$([ -f /etc/alpine-release ] && echo "alpine") && \
|
||||
TARGET=/out ./scripts/build/binary && \
|
||||
xx-verify $([ "$GO_LINKMODE" = "static" ] && echo "--static") /out/docker
|
||||
|
||||
FROM build-base-${BASE_VARIANT} AS dev
|
||||
COPY . .
|
||||
|
||||
FROM scratch AS binary
|
||||
COPY --from=build /out .
|
||||
6
Jenkinsfile
vendored
@ -1,6 +1,6 @@
|
||||
pipeline {
|
||||
agent {
|
||||
label "linux && x86_64"
|
||||
label "amd64 && ubuntu-1804 && overlay2"
|
||||
}
|
||||
|
||||
options {
|
||||
@ -21,9 +21,9 @@ pipeline {
|
||||
make -f docker.Makefile test-e2e-non-experimental"
|
||||
}
|
||||
}
|
||||
stage("e2e (non-experimental) - 18.09 engine") {
|
||||
stage("e2e (non-experimental) - 19.03 engine") {
|
||||
steps {
|
||||
sh "E2E_ENGINE_VERSION=18.09-dind \
|
||||
sh "E2E_ENGINE_VERSION=19.03-dind \
|
||||
E2E_UNIQUE_ID=clie2e${BUILD_NUMBER} \
|
||||
IMAGE_TAG=clie2e${BUILD_NUMBER} \
|
||||
make -f docker.Makefile test-e2e-non-experimental"
|
||||
|
||||
17
Makefile
@ -30,8 +30,7 @@ lint: ## run all the lint tools
|
||||
gometalinter --config gometalinter.json ./...
|
||||
|
||||
.PHONY: binary
|
||||
binary: ## build executable for Linux
|
||||
@echo "WARNING: binary creates a Linux executable. Use cross for macOS or Windows."
|
||||
binary:
|
||||
./scripts/build/binary
|
||||
|
||||
.PHONY: plugins
|
||||
@ -39,28 +38,20 @@ plugins: ## build example CLI plugins
|
||||
./scripts/build/plugins
|
||||
|
||||
.PHONY: cross
|
||||
cross: ## build executable for macOS and Windows
|
||||
./scripts/build/cross
|
||||
|
||||
.PHONY: binary-windows
|
||||
binary-windows: ## build executable for Windows
|
||||
./scripts/build/windows
|
||||
cross:
|
||||
./scripts/build/binary
|
||||
|
||||
.PHONY: plugins-windows
|
||||
plugins-windows: ## build example CLI plugins for Windows
|
||||
./scripts/build/plugins-windows
|
||||
|
||||
.PHONY: binary-osx
|
||||
binary-osx: ## build executable for macOS
|
||||
./scripts/build/osx
|
||||
|
||||
.PHONY: plugins-osx
|
||||
plugins-osx: ## build example CLI plugins for macOS
|
||||
./scripts/build/plugins-osx
|
||||
|
||||
.PHONY: dynbinary
|
||||
dynbinary: ## build dynamically linked binary
|
||||
./scripts/build/dynbinary
|
||||
GO_LINKMODE=dynamic ./scripts/build/binary
|
||||
|
||||
vendor: vendor.conf ## check that vendor matches vendor.conf
|
||||
rm -rf vendor
|
||||
|
||||
25
README.md
@ -12,18 +12,31 @@ Development
|
||||
|
||||
`docker/cli` is developed using Docker.
|
||||
|
||||
Build a linux binary:
|
||||
Build CLI from source:
|
||||
|
||||
```
|
||||
$ make -f docker.Makefile binary
|
||||
$ docker buildx bake
|
||||
```
|
||||
|
||||
Build binaries for all supported platforms:
|
||||
|
||||
```
|
||||
$ make -f docker.Makefile cross
|
||||
$ docker buildx bake cross
|
||||
```
|
||||
|
||||
Build for a specific platform:
|
||||
|
||||
```
|
||||
$ docker buildx bake --set binary.platform=linux/arm64
|
||||
```
|
||||
|
||||
Build dynamic binary for glibc or musl:
|
||||
|
||||
```
|
||||
$ USE_GLIBC=1 docker buildx bake dynbinary
|
||||
```
|
||||
|
||||
|
||||
Run all linting:
|
||||
|
||||
```
|
||||
@ -44,12 +57,6 @@ Start an interactive development environment:
|
||||
$ make -f docker.Makefile shell
|
||||
```
|
||||
|
||||
In the development environment you can run many tasks, including build binaries:
|
||||
|
||||
```
|
||||
$ make binary
|
||||
```
|
||||
|
||||
Legal
|
||||
=====
|
||||
*Brought to you courtesy of our legal counsel. For more context,
|
||||
|
||||
@ -4,7 +4,7 @@ clone_folder: c:\gopath\src\github.com\docker\cli
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
GOVERSION: 1.13.15
|
||||
GOVERSION: 1.16.8
|
||||
DEPVERSION: v0.4.1
|
||||
|
||||
install:
|
||||
|
||||
@ -255,7 +255,7 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize
|
||||
if tlsconfig.IsErrEncryptedKey(err) {
|
||||
passRetriever := passphrase.PromptRetrieverWithInOut(cli.In(), cli.Out(), nil)
|
||||
newClient := func(password string) (client.APIClient, error) {
|
||||
cli.dockerEndpoint.TLSPassword = password
|
||||
cli.dockerEndpoint.TLSPassword = password //nolint: staticcheck // SA1019: cli.dockerEndpoint.TLSPassword is deprecated
|
||||
return newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile)
|
||||
}
|
||||
cli.client, err = getClientWithPassword(passRetriever, newClient)
|
||||
|
||||
@ -6,7 +6,6 @@ import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
@ -80,24 +79,6 @@ func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
|
||||
assert.Check(t, is.Equal(customVersion, apiclient.ClientVersion()))
|
||||
}
|
||||
|
||||
func TestNewAPIClientFromFlagsWithHttpProxyEnv(t *testing.T) {
|
||||
defer env.Patch(t, "HTTP_PROXY", "http://proxy.acme.com:1234")()
|
||||
defer env.Patch(t, "DOCKER_HOST", "tcp://docker.acme.com:2376")()
|
||||
|
||||
opts := &flags.CommonOptions{}
|
||||
configFile := &configfile.ConfigFile{}
|
||||
apiclient, err := NewAPIClientFromFlags(opts, configFile)
|
||||
assert.NilError(t, err)
|
||||
transport, ok := apiclient.HTTPClient().Transport.(*http.Transport)
|
||||
assert.Assert(t, ok)
|
||||
assert.Assert(t, transport.Proxy != nil)
|
||||
request, err := http.NewRequest(http.MethodGet, "tcp://docker.acme.com:2376", nil)
|
||||
assert.NilError(t, err)
|
||||
url, err := transport.Proxy(request)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal("http://proxy.acme.com:1234", url.String()))
|
||||
}
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
pingFunc func() (types.Ping, error)
|
||||
|
||||
@ -97,7 +97,8 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
|
||||
}
|
||||
|
||||
if opts.proxy && !c.Config.Tty {
|
||||
sigc := ForwardAllSignals(ctx, dockerCli, opts.container)
|
||||
sigc := notfiyAllSignals()
|
||||
go ForwardAllSignals(ctx, dockerCli, opts.container, sigc)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ type fakeClient struct {
|
||||
containerExportFunc func(string) (io.ReadCloser, error)
|
||||
containerExecResizeFunc func(id string, options types.ResizeOptions) error
|
||||
containerRemoveFunc func(ctx context.Context, container string, options types.ContainerRemoveOptions) error
|
||||
containerKillFunc func(ctx context.Context, container, signal string) error
|
||||
Version string
|
||||
}
|
||||
|
||||
@ -154,3 +155,10 @@ func (f *fakeClient) ContainerExecResize(_ context.Context, id string, options t
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeClient) ContainerKill(ctx context.Context, container, signal string) error {
|
||||
if f.containerKillFunc != nil {
|
||||
return f.containerKillFunc(ctx, container, signal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -133,7 +133,7 @@ func TestCreateContainerImagePullPolicy(t *testing.T) {
|
||||
return ioutil.NopCloser(strings.NewReader("")), nil
|
||||
},
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{IndexServerAddress: "http://indexserver"}, nil
|
||||
return types.Info{IndexServerAddress: "https://indexserver.example.com"}, nil
|
||||
},
|
||||
}
|
||||
cli := test.NewFakeCli(client)
|
||||
|
||||
@ -131,7 +131,8 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
|
||||
return runStartContainerErr(err)
|
||||
}
|
||||
if opts.sigProxy {
|
||||
sigc := ForwardAllSignals(ctx, dockerCli, createResponse.ID)
|
||||
sigc := notfiyAllSignals()
|
||||
go ForwardAllSignals(ctx, dockerCli, createResponse.ID, sigc)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
|
||||
61
cli/command/container/signals.go
Normal file
@ -0,0 +1,61 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
|
||||
"github.com/docker/cli/cli/command"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ForwardAllSignals forwards signals to the container
|
||||
//
|
||||
// The channel you pass in must already be setup to receive any signals you want to forward.
|
||||
func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string, sigc <-chan os.Signal) {
|
||||
var (
|
||||
s os.Signal
|
||||
ok bool
|
||||
)
|
||||
for {
|
||||
select {
|
||||
case s, ok = <-sigc:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
||||
continue
|
||||
}
|
||||
|
||||
// In go1.14+, the go runtime issues SIGURG as an interrupt to support pre-emptable system calls on Linux.
|
||||
// Since we can't forward that along we'll check that here.
|
||||
if isRuntimeSig(s) {
|
||||
continue
|
||||
}
|
||||
var sig string
|
||||
for sigStr, sigN := range signal.SignalMap {
|
||||
if sigN == s {
|
||||
sig = sigStr
|
||||
break
|
||||
}
|
||||
}
|
||||
if sig == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
|
||||
logrus.Debugf("Error sending signal: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func notfiyAllSignals() chan os.Signal {
|
||||
sigc := make(chan os.Signal, 128)
|
||||
gosignal.Notify(sigc)
|
||||
return sigc
|
||||
}
|
||||
48
cli/command/container/signals_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
)
|
||||
|
||||
func TestForwardSignals(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
called := make(chan struct{})
|
||||
client := &fakeClient{containerKillFunc: func(ctx context.Context, container, signal string) error {
|
||||
close(called)
|
||||
return nil
|
||||
}}
|
||||
|
||||
cli := test.NewFakeCli(client)
|
||||
sigc := make(chan os.Signal)
|
||||
defer close(sigc)
|
||||
|
||||
go ForwardAllSignals(ctx, cli, t.Name(), sigc)
|
||||
|
||||
timer := time.NewTimer(30 * time.Second)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
t.Fatal("timeout waiting to send signal")
|
||||
case sigc <- signal.SignalMap["TERM"]:
|
||||
}
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
timer.Reset(30 * time.Second)
|
||||
|
||||
select {
|
||||
case <-called:
|
||||
case <-timer.C:
|
||||
t.Fatal("timeout waiting for signal to be processed")
|
||||
}
|
||||
|
||||
}
|
||||
13
cli/command/container/signals_unix.go
Normal file
@ -0,0 +1,13 @@
|
||||
// +build !windows
|
||||
|
||||
package container
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func isRuntimeSig(s os.Signal) bool {
|
||||
return s == unix.SIGURG
|
||||
}
|
||||
59
cli/command/container/signals_unix_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
// +build !windows
|
||||
|
||||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/cli/internal/test"
|
||||
"golang.org/x/sys/unix"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestIgnoredSignals(t *testing.T) {
|
||||
ignoredSignals := []syscall.Signal{unix.SIGPIPE, unix.SIGCHLD, unix.SIGURG}
|
||||
|
||||
for _, s := range ignoredSignals {
|
||||
t.Run(unix.SignalName(s), func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
var called bool
|
||||
client := &fakeClient{containerKillFunc: func(ctx context.Context, container, signal string) error {
|
||||
called = true
|
||||
return nil
|
||||
}}
|
||||
|
||||
cli := test.NewFakeCli(client)
|
||||
sigc := make(chan os.Signal)
|
||||
defer close(sigc)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
ForwardAllSignals(ctx, cli, t.Name(), sigc)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
timer := time.NewTimer(30 * time.Second)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
t.Fatal("timeout waiting to send signal")
|
||||
case sigc <- s:
|
||||
case <-done:
|
||||
}
|
||||
|
||||
// cancel the context so ForwardAllSignals will exit after it has processed the signal we sent.
|
||||
// This is how we know the signal was actually processed and are not introducing a flakey test.
|
||||
cancel()
|
||||
<-done
|
||||
|
||||
assert.Assert(t, !called, "kill was called")
|
||||
})
|
||||
}
|
||||
}
|
||||
7
cli/command/container/signals_windows.go
Normal file
@ -0,0 +1,7 @@
|
||||
package container
|
||||
|
||||
import "os"
|
||||
|
||||
func isRuntimeSig(_ os.Signal) bool {
|
||||
return false
|
||||
}
|
||||
@ -74,7 +74,8 @@ func runStart(dockerCli command.Cli, opts *startOptions) error {
|
||||
|
||||
// We always use c.ID instead of container to maintain consistency during `docker start`
|
||||
if !c.Config.Tty {
|
||||
sigc := ForwardAllSignals(ctx, dockerCli, c.ID)
|
||||
sigc := notfiyAllSignals()
|
||||
go ForwardAllSignals(ctx, dockerCli, c.ID, sigc)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
|
||||
@ -95,32 +95,3 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForwardAllSignals forwards signals to the container
|
||||
func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string) chan os.Signal {
|
||||
sigc := make(chan os.Signal, 128)
|
||||
signal.CatchAll(sigc)
|
||||
go func() {
|
||||
for s := range sigc {
|
||||
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
||||
continue
|
||||
}
|
||||
var sig string
|
||||
for sigStr, sigN := range signal.SignalMap {
|
||||
if sigN == s {
|
||||
sig = sigStr
|
||||
break
|
||||
}
|
||||
}
|
||||
if sig == "" {
|
||||
fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
|
||||
logrus.Debugf("Error sending signal: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return sigc
|
||||
}
|
||||
|
||||
@ -62,8 +62,11 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||
&opts.DefaultStackOrchestrator,
|
||||
"default-stack-orchestrator", "",
|
||||
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
|
||||
flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil)
|
||||
flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
|
||||
flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
|
||||
flags.SetAnnotation("kubernetes", "kubernetes", nil)
|
||||
flags.SetAnnotation("kubernetes", "deprecated", nil)
|
||||
flags.StringVar(&opts.From, "from", "", "create context from a named context")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ func validateTestKubeEndpoint(t *testing.T, s store.Reader, name string) {
|
||||
kubeMeta := ctxMetadata.Endpoints[kubernetes.KubernetesEndpoint].(kubernetes.EndpointMeta)
|
||||
kubeEP, err := kubeMeta.WithTLSData(s, name)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, "https://someserver", kubeEP.Host)
|
||||
assert.Equal(t, "https://someserver.example.com", kubeEP.Host)
|
||||
assert.Equal(t, "the-ca", string(kubeEP.TLSData.CA))
|
||||
assert.Equal(t, "the-cert", string(kubeEP.TLSData.Cert))
|
||||
assert.Equal(t, "the-key", string(kubeEP.TLSData.Key))
|
||||
@ -287,7 +287,7 @@ func TestCreateFromContext(t *testing.T) {
|
||||
assert.Equal(t, newContextTyped.Description, c.expectedDescription)
|
||||
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
|
||||
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
|
||||
assert.Equal(t, kubeEndpoint.Host, "https://someserver")
|
||||
assert.Equal(t, kubeEndpoint.Host, "https://someserver.example.com")
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -361,7 +361,7 @@ func TestCreateFromCurrent(t *testing.T) {
|
||||
assert.Equal(t, newContextTyped.Description, c.expectedDescription)
|
||||
assert.Equal(t, newContextTyped.StackOrchestrator, c.expectedOrchestrator)
|
||||
assert.Equal(t, dockerEndpoint.Host, "tcp://42.42.42.42:2375")
|
||||
assert.Equal(t, kubeEndpoint.Host, "https://someserver")
|
||||
assert.Equal(t, kubeEndpoint.Host, "https://someserver.example.com")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +46,8 @@ func newExportCommand(dockerCli command.Cli) *cobra.Command {
|
||||
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(&opts.Kubeconfig, "kubeconfig", false, "Export as a kubeconfig file")
|
||||
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
|
||||
flags.SetAnnotation("kubeconfig", "deprecated", nil)
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ func createTestContextWithKubeAndSwarm(t *testing.T, cli command.Cli, name strin
|
||||
DefaultStackOrchestrator: orchestrator,
|
||||
Description: "description of " + name,
|
||||
Kubernetes: map[string]string{keyFrom: "default"},
|
||||
Docker: map[string]string{keyHost: "https://someswarmserver"},
|
||||
Docker: map[string]string{keyHost: "https://someswarmserver.example.com"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
4
cli/command/context/testdata/inspect.golden
vendored
@ -7,11 +7,11 @@
|
||||
},
|
||||
"Endpoints": {
|
||||
"docker": {
|
||||
"Host": "https://someswarmserver",
|
||||
"Host": "https://someswarmserver.example.com",
|
||||
"SkipTLSVerify": false
|
||||
},
|
||||
"kubernetes": {
|
||||
"Host": "https://someserver",
|
||||
"Host": "https://someserver.example.com",
|
||||
"SkipTLSVerify": false,
|
||||
"DefaultNamespace": "default"
|
||||
}
|
||||
|
||||
10
cli/command/context/testdata/list.golden
vendored
@ -1,5 +1,5 @@
|
||||
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
|
||||
current * description of current https://someswarmserver https://someserver (default) all
|
||||
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
|
||||
other description of other https://someswarmserver https://someserver (default) all
|
||||
unset description of unset https://someswarmserver https://someserver (default)
|
||||
NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
|
||||
current * description of current https://someswarmserver.example.com https://someserver.example.com (default) all
|
||||
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
|
||||
other description of other https://someswarmserver.example.com https://someserver.example.com (default) all
|
||||
unset description of unset https://someswarmserver.example.com https://someserver.example.com (default)
|
||||
|
||||
2
cli/command/context/testdata/test-kubeconfig
vendored
@ -2,7 +2,7 @@ apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: dGhlLWNh
|
||||
server: https://someserver
|
||||
server: https://someserver.example.com
|
||||
name: test-cluster
|
||||
contexts:
|
||||
- context:
|
||||
|
||||
@ -61,8 +61,11 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
|
||||
&opts.DefaultStackOrchestrator,
|
||||
"default-stack-orchestrator", "",
|
||||
"Default orchestrator for stack operations to use with this context (swarm|kubernetes|all)")
|
||||
flags.SetAnnotation("default-stack-orchestrator", "deprecated", nil)
|
||||
flags.StringToStringVar(&opts.Docker, "docker", nil, "set the docker endpoint")
|
||||
flags.StringToStringVar(&opts.Kubernetes, "kubernetes", nil, "set the kubernetes endpoint")
|
||||
flags.SetAnnotation("kubernetes", "kubernetes", nil)
|
||||
flags.SetAnnotation("kubernetes", "deprecated", nil)
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ func runBuildBuildKit(dockerCli command.Cli, options buildOptions) error {
|
||||
if options.dockerfileFromStdin() {
|
||||
return errStdinConflict
|
||||
}
|
||||
rc, isArchive, err := build.DetectArchiveReader(os.Stdin)
|
||||
rc, isArchive, err := build.DetectArchiveReader(dockerCli.In())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -98,7 +98,7 @@ func runBuildBuildKit(dockerCli command.Cli, options buildOptions) error {
|
||||
case isLocalDir(options.context):
|
||||
contextDir = options.context
|
||||
if options.dockerfileFromStdin() {
|
||||
dockerfileReader = os.Stdin
|
||||
dockerfileReader = dockerCli.In()
|
||||
} else if options.dockerfileName != "" {
|
||||
dockerfileName = filepath.Base(options.dockerfileName)
|
||||
dockerfileDir = filepath.Dir(options.dockerfileName)
|
||||
|
||||
@ -15,17 +15,17 @@ import (
|
||||
)
|
||||
|
||||
func TestENVTrustServer(t *testing.T) {
|
||||
defer env.PatchAll(t, map[string]string{"DOCKER_CONTENT_TRUST_SERVER": "https://notary-test.com:5000"})()
|
||||
defer env.PatchAll(t, map[string]string{"DOCKER_CONTENT_TRUST_SERVER": "https://notary-test.example.com:5000"})()
|
||||
indexInfo := ®istrytypes.IndexInfo{Name: "testserver"}
|
||||
output, err := trust.Server(indexInfo)
|
||||
expectedStr := "https://notary-test.com:5000"
|
||||
expectedStr := "https://notary-test.example.com:5000"
|
||||
if err != nil || output != expectedStr {
|
||||
t.Fatalf("Expected server to be %s, got %s", expectedStr, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPENVTrustServer(t *testing.T) {
|
||||
defer env.PatchAll(t, map[string]string{"DOCKER_CONTENT_TRUST_SERVER": "http://notary-test.com:5000"})()
|
||||
defer env.PatchAll(t, map[string]string{"DOCKER_CONTENT_TRUST_SERVER": "http://notary-test.example.com:5000"})()
|
||||
indexInfo := ®istrytypes.IndexInfo{Name: "testserver"}
|
||||
_, err := trust.Server(indexInfo)
|
||||
if err == nil {
|
||||
|
||||
@ -66,11 +66,11 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", indexServer, err)
|
||||
}
|
||||
err = ConfigureAuth(cli, "", "", authConfig, isDefaultRegistry)
|
||||
err = ConfigureAuth(cli, "", "", &authConfig, isDefaultRegistry)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return EncodeAuthToBase64(*authConfig)
|
||||
return EncodeAuthToBase64(authConfig)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ func ResolveAuthConfig(ctx context.Context, cli Cli, index *registrytypes.IndexI
|
||||
|
||||
// GetDefaultAuthConfig gets the default auth config given a serverAddress
|
||||
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
|
||||
func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (*types.AuthConfig, error) {
|
||||
func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
|
||||
if !isDefaultRegistry {
|
||||
serverAddress = registry.ConvertToHostname(serverAddress)
|
||||
}
|
||||
@ -98,13 +98,15 @@ func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, is
|
||||
if checkCredStore {
|
||||
authconfig, err = cli.ConfigFile().GetAuthConfig(serverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return types.AuthConfig{
|
||||
ServerAddress: serverAddress,
|
||||
}, err
|
||||
}
|
||||
}
|
||||
authconfig.ServerAddress = serverAddress
|
||||
authconfig.IdentityToken = ""
|
||||
res := types.AuthConfig(authconfig)
|
||||
return &res, nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ConfigureAuth handles prompting of user's username and password if needed
|
||||
|
||||
@ -111,24 +111,22 @@ func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint: gocycl
|
||||
serverAddress = authServer
|
||||
}
|
||||
|
||||
var err error
|
||||
var authConfig *types.AuthConfig
|
||||
var response registrytypes.AuthenticateOKBody
|
||||
isDefaultRegistry := serverAddress == authServer
|
||||
authConfig, err = command.GetDefaultAuthConfig(dockerCli, opts.user == "" && opts.password == "", serverAddress, isDefaultRegistry)
|
||||
authConfig, err := command.GetDefaultAuthConfig(dockerCli, opts.user == "" && opts.password == "", serverAddress, isDefaultRegistry)
|
||||
if err == nil && authConfig.Username != "" && authConfig.Password != "" {
|
||||
response, err = loginWithCredStoreCreds(ctx, dockerCli, authConfig)
|
||||
response, err = loginWithCredStoreCreds(ctx, dockerCli, &authConfig)
|
||||
}
|
||||
if err != nil || authConfig.Username == "" || authConfig.Password == "" {
|
||||
err = command.ConfigureAuth(dockerCli, opts.user, opts.password, authConfig, isDefaultRegistry)
|
||||
err = command.ConfigureAuth(dockerCli, opts.user, opts.password, &authConfig, isDefaultRegistry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
response, err = clnt.RegistryLogin(ctx, *authConfig)
|
||||
response, err = clnt.RegistryLogin(ctx, authConfig)
|
||||
if err != nil && client.IsErrConnectionFailed(err) {
|
||||
// If the server isn't responding (yet) attempt to login purely client side
|
||||
response, err = loginClientSide(ctx, *authConfig)
|
||||
response, err = loginClientSide(ctx, authConfig)
|
||||
}
|
||||
// If we (still) have an error, give up
|
||||
if err != nil {
|
||||
@ -151,7 +149,7 @@ func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint: gocycl
|
||||
}
|
||||
}
|
||||
|
||||
if err := creds.Store(configtypes.AuthConfig(*authConfig)); err != nil {
|
||||
if err := creds.Store(configtypes.AuthConfig(authConfig)); err != nil {
|
||||
return errors.Errorf("Error saving credentials: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@ -66,10 +66,10 @@ func TestElectAuthServer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedAuthServer: "https://foo.bar",
|
||||
expectedAuthServer: "https://foo.example.com",
|
||||
expectedWarning: "",
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{IndexServerAddress: "https://foo.bar"}, nil
|
||||
return types.Info{IndexServerAddress: "https://foo.example.com"}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -145,7 +145,21 @@ func TestGetDefaultAuthConfig(t *testing.T) {
|
||||
assert.Check(t, is.Equal(tc.expectedErr, err.Error()))
|
||||
} else {
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.DeepEqual(tc.expectedAuthConfig, *authconfig))
|
||||
assert.Check(t, is.DeepEqual(tc.expectedAuthConfig, authconfig))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDefaultAuthConfig_HelperError(t *testing.T) {
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
errBuf := new(bytes.Buffer)
|
||||
cli.SetErr(errBuf)
|
||||
cli.ConfigFile().CredentialsStore = "fake-does-not-exist"
|
||||
serverAddress := "test-server-address"
|
||||
expectedAuthConfig := types.AuthConfig{
|
||||
ServerAddress: serverAddress,
|
||||
}
|
||||
authconfig, err := GetDefaultAuthConfig(cli, true, serverAddress, serverAddress == "https://index.docker.io/v1/")
|
||||
assert.Check(t, is.DeepEqual(expectedAuthConfig, authconfig))
|
||||
assert.Check(t, is.ErrorContains(err, "docker-credential-fake-does-not-exist"))
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ func updateConfigFromDefaults(defaultUpdateConfig *api.UpdateConfig) *swarm.Upda
|
||||
}
|
||||
|
||||
func (opts updateOptions) updateConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
|
||||
if !anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio) {
|
||||
if !anyChanged(flags, flagUpdateParallelism, flagUpdateDelay, flagUpdateMonitor, flagUpdateFailureAction, flagUpdateMaxFailureRatio, flagUpdateOrder) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ func (opts updateOptions) updateConfig(flags *pflag.FlagSet) *swarm.UpdateConfig
|
||||
}
|
||||
|
||||
func (opts updateOptions) rollbackConfig(flags *pflag.FlagSet) *swarm.UpdateConfig {
|
||||
if !anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio) {
|
||||
if !anyChanged(flags, flagRollbackParallelism, flagRollbackDelay, flagRollbackMonitor, flagRollbackFailureAction, flagRollbackMaxFailureRatio, flagRollbackOrder) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -289,6 +289,22 @@ func TestToServiceUpdateRollback(t *testing.T) {
|
||||
assert.Check(t, is.DeepEqual(service.RollbackConfig, expected.RollbackConfig))
|
||||
}
|
||||
|
||||
func TestToServiceUpdateRollbackOrder(t *testing.T) {
|
||||
flags := newCreateCommand(nil).Flags()
|
||||
flags.Set("update-order", "start-first")
|
||||
flags.Set("rollback-order", "start-first")
|
||||
|
||||
o := newServiceOptions()
|
||||
o.mode = "replicated"
|
||||
o.update = updateOptions{order: "start-first"}
|
||||
o.rollback = updateOptions{order: "start-first"}
|
||||
|
||||
service, err := o.ToService(context.Background(), &fakeClient{}, flags)
|
||||
assert.NilError(t, err)
|
||||
assert.Check(t, is.Equal(service.UpdateConfig.Order, o.update.order))
|
||||
assert.Check(t, is.Equal(service.RollbackConfig.Order, o.rollback.order))
|
||||
}
|
||||
|
||||
func TestToServiceMaxReplicasGlobalModeConflict(t *testing.T) {
|
||||
opt := serviceOptions{
|
||||
mode: "global",
|
||||
|
||||
@ -99,6 +99,7 @@ func ServiceProgress(ctx context.Context, client client.APIClient, serviceID str
|
||||
convergedAt time.Time
|
||||
monitor = 5 * time.Second
|
||||
rollback bool
|
||||
message *progress.Progress
|
||||
)
|
||||
|
||||
for {
|
||||
@ -140,8 +141,9 @@ func ServiceProgress(ctx context.Context, client client.APIClient, serviceID str
|
||||
return fmt.Errorf("service rollback paused: %s", service.UpdateStatus.Message)
|
||||
case swarm.UpdateStateRollbackCompleted:
|
||||
if !converged {
|
||||
return fmt.Errorf("service rolled back: %s", service.UpdateStatus.Message)
|
||||
message = &progress.Progress{ID: "rollback", Message: service.UpdateStatus.Message}
|
||||
}
|
||||
rollback = true
|
||||
}
|
||||
}
|
||||
if converged && time.Since(convergedAt) >= monitor {
|
||||
@ -149,7 +151,9 @@ func ServiceProgress(ctx context.Context, client client.APIClient, serviceID str
|
||||
ID: "verify",
|
||||
Action: "Service converged",
|
||||
})
|
||||
|
||||
if message != nil {
|
||||
progressOut.WriteProgress(*message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -69,7 +69,9 @@ func NewStackCommand(dockerCli command.Cli) *cobra.Command {
|
||||
flags := cmd.PersistentFlags()
|
||||
flags.String("kubeconfig", "", "Kubernetes config file")
|
||||
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
|
||||
flags.SetAnnotation("kubeconfig", "deprecated", nil)
|
||||
flags.String("orchestrator", "", "Orchestrator to use (swarm|kubernetes|all)")
|
||||
flags.SetAnnotation("orchestrator", "deprecated", nil)
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ func NewOptions(flags *flag.FlagSet, orchestrator command.Orchestrator) Options
|
||||
func AddNamespaceFlag(flags *flag.FlagSet) {
|
||||
flags.String("namespace", "", "Kubernetes namespace to use")
|
||||
flags.SetAnnotation("namespace", "kubernetes", nil)
|
||||
flags.SetAnnotation("namespace", "deprecated", nil)
|
||||
}
|
||||
|
||||
// WrapCli wraps command.Cli with kubernetes specifics
|
||||
|
||||
@ -30,8 +30,10 @@ func newListCommand(dockerCli command.Cli, common *commonOptions) *cobra.Command
|
||||
flags.StringVar(&opts.Format, "format", "", "Pretty-print stacks using a Go template")
|
||||
flags.StringSliceVar(&opts.Namespaces, "namespace", []string{}, "Kubernetes namespaces to use")
|
||||
flags.SetAnnotation("namespace", "kubernetes", nil)
|
||||
flags.SetAnnotation("namespace", "deprecated", nil)
|
||||
flags.BoolVarP(&opts.AllNamespaces, "all-namespaces", "", false, "List stacks from all Kubernetes namespaces")
|
||||
flags.SetAnnotation("all-namespaces", "kubernetes", nil)
|
||||
flags.SetAnnotation("all-namespaces", "deprecated", nil)
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@ -104,20 +104,20 @@ func TestDisplayTrustRootInvalidFlags(t *testing.T) {
|
||||
errorMsg: "flag requires the `--rotate` flag to update the CA",
|
||||
},
|
||||
{
|
||||
args: []string{"--external-ca=protocol=cfssl,url=https://some.com/https/url"},
|
||||
args: []string{"--external-ca=protocol=cfssl,url=https://some.example.com/https/url"},
|
||||
errorMsg: "flag requires the `--rotate` flag to update the CA",
|
||||
},
|
||||
{ // to make sure we're not erroring because we didn't provide a CA cert and external CA
|
||||
args: []string{
|
||||
"--ca-cert=" + tmpfile,
|
||||
"--external-ca=protocol=cfssl,url=https://some.com/https/url",
|
||||
"--external-ca=protocol=cfssl,url=https://some.example.com/https/url",
|
||||
},
|
||||
errorMsg: "flag requires the `--rotate` flag to update the CA",
|
||||
},
|
||||
{
|
||||
args: []string{
|
||||
"--rotate",
|
||||
"--external-ca=protocol=cfssl,url=https://some.com/https/url",
|
||||
"--external-ca=protocol=cfssl,url=https://some.example.com/https/url",
|
||||
},
|
||||
errorMsg: "rotating to an external CA requires the `--ca-cert` flag to specify the external CA's cert - " +
|
||||
"to add an external CA with the current root CA certificate, use the `update` command instead",
|
||||
@ -243,7 +243,7 @@ func TestUpdateSwarmSpecCertAndExternalCA(t *testing.T) {
|
||||
"--rotate",
|
||||
"--detach",
|
||||
"--ca-cert=" + certfile,
|
||||
"--external-ca=protocol=cfssl,url=https://some.external.ca"})
|
||||
"--external-ca=protocol=cfssl,url=https://some.external.ca.example.com"})
|
||||
cmd.SetOut(cli.OutBuffer())
|
||||
assert.NilError(t, cmd.Execute())
|
||||
|
||||
@ -253,7 +253,7 @@ func TestUpdateSwarmSpecCertAndExternalCA(t *testing.T) {
|
||||
expected.CAConfig.ExternalCAs = []*swarm.ExternalCA{
|
||||
{
|
||||
Protocol: swarm.ExternalCAProtocolCFSSL,
|
||||
URL: "https://some.external.ca",
|
||||
URL: "https://some.external.ca.example.com",
|
||||
CACert: cert,
|
||||
Options: make(map[string]string),
|
||||
},
|
||||
@ -281,7 +281,7 @@ func TestUpdateSwarmSpecCertAndKeyAndExternalCA(t *testing.T) {
|
||||
"--detach",
|
||||
"--ca-cert=" + certfile,
|
||||
"--ca-key=" + keyfile,
|
||||
"--external-ca=protocol=cfssl,url=https://some.external.ca"})
|
||||
"--external-ca=protocol=cfssl,url=https://some.external.ca.example.com"})
|
||||
cmd.SetOut(cli.OutBuffer())
|
||||
assert.NilError(t, cmd.Execute())
|
||||
|
||||
@ -291,7 +291,7 @@ func TestUpdateSwarmSpecCertAndKeyAndExternalCA(t *testing.T) {
|
||||
expected.CAConfig.ExternalCAs = []*swarm.ExternalCA{
|
||||
{
|
||||
Protocol: swarm.ExternalCAProtocolCFSSL,
|
||||
URL: "https://some.external.ca",
|
||||
URL: "https://some.external.ca.example.com",
|
||||
CACert: cert,
|
||||
Options: make(map[string]string),
|
||||
},
|
||||
|
||||
@ -402,10 +402,7 @@ func printServerWarningsLegacy(dockerCli command.Cli, info types.Info) {
|
||||
if !info.SwapLimit {
|
||||
fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support")
|
||||
}
|
||||
if !info.KernelMemory {
|
||||
fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support")
|
||||
}
|
||||
if !info.OomKillDisable {
|
||||
if !info.OomKillDisable && info.CgroupVersion != "2" {
|
||||
fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support")
|
||||
}
|
||||
if !info.CPUCfsQuota {
|
||||
|
||||
@ -248,7 +248,6 @@ func TestPrettyPrintInfo(t *testing.T) {
|
||||
sampleInfoDaemonWarnings.Warnings = []string{
|
||||
"WARNING: No memory limit support",
|
||||
"WARNING: No swap limit support",
|
||||
"WARNING: No kernel memory limit support",
|
||||
"WARNING: No oom kill disable support",
|
||||
"WARNING: No cpu cfs quota support",
|
||||
"WARNING: No cpu cfs period support",
|
||||
|
||||
@ -1 +1 @@
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"KernelMemoryTCP":false,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":["WARNING: No memory limit support","WARNING: No swap limit support","WARNING: No kernel memory limit support","WARNING: No oom kill disable support","WARNING: No cpu cfs quota support","WARNING: No cpu cfs period support","WARNING: No cpu shares support","WARNING: No cpuset support","WARNING: IPv4 forwarding is disabled","WARNING: bridge-nf-call-iptables is disabled","WARNING: bridge-nf-call-ip6tables is disabled"],"ClientInfo":{"Debug":true,"Context":"default","Plugins":[],"Warnings":null}}
|
||||
{"ID":"EKHL:QDUU:QZ7U:MKGD:VDXK:S27Q:GIPU:24B7:R7VT:DGN6:QCSF:2UBX","Containers":0,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":0,"Images":0,"Driver":"aufs","DriverStatus":[["Root Dir","/var/lib/docker/aufs"],["Backing Filesystem","extfs"],["Dirs","0"],["Dirperm1 Supported","true"]],"Plugins":{"Volume":["local"],"Network":["bridge","host","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":true,"KernelMemory":true,"KernelMemoryTCP":false,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":false,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":true,"NFd":33,"OomKillDisable":true,"NGoroutines":135,"SystemTime":"2017-08-24T17:44:34.077811894Z","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.4.0-87-generic","OperatingSystem":"Ubuntu 16.04.3 LTS","OSVersion":"","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":null,"AllowNondistributableArtifactsHostnames":null,"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"NCPU":2,"MemTotal":2097356800,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"system-sample","Labels":["provider=digitalocean"],"ExperimentalBuild":false,"ServerVersion":"17.06.1-ce","Runtimes":{"runc":{"path":"docker-runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"6e23458c129b551d5c9871e5174f6b1b7f6d1170","Expected":"6e23458c129b551d5c9871e5174f6b1b7f6d1170"},"RuncCommit":{"ID":"810190ceaa507aa2727d7ae6f4790c76ec150bd2","Expected":"810190ceaa507aa2727d7ae6f4790c76ec150bd2"},"InitCommit":{"ID":"949e6fa","Expected":"949e6fa"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"DefaultAddressPools":[{"Base":"10.123.0.0/16","Size":24}],"Warnings":["WARNING: No memory limit support","WARNING: No swap limit support","WARNING: No oom kill disable support","WARNING: No cpu cfs quota support","WARNING: No cpu cfs period support","WARNING: No cpu shares support","WARNING: No cpuset support","WARNING: IPv4 forwarding is disabled","WARNING: bridge-nf-call-iptables is disabled","WARNING: bridge-nf-call-ip6tables is disabled"],"ClientInfo":{"Debug":true,"Context":"default","Plugins":[],"Warnings":null}}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
WARNING: No memory limit support
|
||||
WARNING: No swap limit support
|
||||
WARNING: No kernel memory limit support
|
||||
WARNING: No oom kill disable support
|
||||
WARNING: No cpu cfs quota support
|
||||
WARNING: No cpu cfs period support
|
||||
|
||||
@ -114,6 +114,7 @@ func NewVersionCommand(dockerCli command.Cli) *cobra.Command {
|
||||
flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
|
||||
flags.StringVar(&opts.kubeConfig, "kubeconfig", "", "Kubernetes config file")
|
||||
flags.SetAnnotation("kubeconfig", "kubernetes", nil)
|
||||
flags.SetAnnotation("kubeconfig", "deprecated", nil)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -24,17 +24,38 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
initConfigDir sync.Once
|
||||
initConfigDir = new(sync.Once)
|
||||
configDir string
|
||||
homeDir string
|
||||
)
|
||||
|
||||
// resetHomeDir is used in testing to reset the "homeDir" package variable to
|
||||
// force re-lookup of the home directory between tests.
|
||||
func resetHomeDir() {
|
||||
homeDir = ""
|
||||
}
|
||||
|
||||
func getHomeDir() string {
|
||||
if homeDir == "" {
|
||||
homeDir = homedir.Get()
|
||||
}
|
||||
return homeDir
|
||||
}
|
||||
|
||||
// resetConfigDir is used in testing to reset the "configDir" package variable
|
||||
// and its sync.Once to force re-lookup between tests.
|
||||
func resetConfigDir() {
|
||||
configDir = ""
|
||||
initConfigDir = new(sync.Once)
|
||||
}
|
||||
|
||||
func setConfigDir() {
|
||||
if configDir != "" {
|
||||
return
|
||||
}
|
||||
configDir = os.Getenv("DOCKER_CONFIG")
|
||||
if configDir == "" {
|
||||
configDir = filepath.Join(homedir.Get(), configFileDir)
|
||||
configDir = filepath.Join(getHomeDir(), configFileDir)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,10 +104,15 @@ func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
|
||||
return &configFile, err
|
||||
}
|
||||
|
||||
// TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file
|
||||
var printLegacyFileWarning bool
|
||||
|
||||
// Load reads the configuration files in the given directory, and sets up
|
||||
// the auth config information and returns values.
|
||||
// FIXME: use the internal golang config parser
|
||||
func Load(configDir string) (*configfile.ConfigFile, error) {
|
||||
printLegacyFileWarning = false
|
||||
|
||||
if configDir == "" {
|
||||
configDir = Dir()
|
||||
}
|
||||
@ -109,12 +135,9 @@ func Load(configDir string) (*configfile.ConfigFile, error) {
|
||||
}
|
||||
|
||||
// Can't find latest config file so check for the old one
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return configFile, errors.Wrap(err, oldConfigfile)
|
||||
}
|
||||
filename = filepath.Join(home, oldConfigfile)
|
||||
filename = filepath.Join(getHomeDir(), oldConfigfile)
|
||||
if file, err := os.Open(filename); err == nil {
|
||||
printLegacyFileWarning = true
|
||||
defer file.Close()
|
||||
if err := configFile.LegacyLoadFromReader(file); err != nil {
|
||||
return configFile, errors.Wrap(err, filename)
|
||||
@ -130,6 +153,9 @@ func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile {
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
|
||||
}
|
||||
if printLegacyFileWarning {
|
||||
_, _ = fmt.Fprintln(stderr, "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format is deprecated and will be removed in an upcoming release")
|
||||
}
|
||||
if !configFile.ContainsAuth() {
|
||||
configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore)
|
||||
}
|
||||
|
||||
@ -12,9 +12,11 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/docker/cli/cli/config/credentials"
|
||||
"github.com/docker/cli/cli/config/types"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/env"
|
||||
"gotest.tools/v3/fs"
|
||||
)
|
||||
|
||||
var homeKey = "HOME"
|
||||
@ -115,6 +117,7 @@ password`: "Invalid Auth config file",
|
||||
email`: "Invalid auth configuration file",
|
||||
}
|
||||
|
||||
resetHomeDir()
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
assert.NilError(t, err)
|
||||
defer os.RemoveAll(tmpHome)
|
||||
@ -131,6 +134,7 @@ email`: "Invalid auth configuration file",
|
||||
}
|
||||
|
||||
func TestOldValidAuth(t *testing.T) {
|
||||
resetHomeDir()
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
assert.NilError(t, err)
|
||||
defer os.RemoveAll(tmpHome)
|
||||
@ -165,6 +169,7 @@ func TestOldValidAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOldJSONInvalid(t *testing.T) {
|
||||
resetHomeDir()
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
assert.NilError(t, err)
|
||||
defer os.RemoveAll(tmpHome)
|
||||
@ -184,6 +189,7 @@ func TestOldJSONInvalid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOldJSON(t *testing.T) {
|
||||
resetHomeDir()
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
assert.NilError(t, err)
|
||||
defer os.RemoveAll(tmpHome)
|
||||
@ -219,6 +225,31 @@ func TestOldJSON(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOldJSONFallbackDeprecationWarning(t *testing.T) {
|
||||
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
|
||||
tmpHome := fs.NewDir(t, t.Name(), fs.WithFile(oldConfigfile, js))
|
||||
defer tmpHome.Remove()
|
||||
defer env.PatchAll(t, map[string]string{homeKey: tmpHome.Path(), "DOCKER_CONFIG": ""})()
|
||||
|
||||
// reset the homeDir, configDir, and its sync.Once, to force them being resolved again
|
||||
resetHomeDir()
|
||||
resetConfigDir()
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
configFile := LoadDefaultConfigFile(buffer)
|
||||
expected := configfile.New(tmpHome.Join(configFileDir, ConfigFileName))
|
||||
expected.AuthConfigs = map[string]types.AuthConfig{
|
||||
"https://index.docker.io/v1/": {
|
||||
Username: "joejoe",
|
||||
Password: "hello",
|
||||
Email: "user@example.com",
|
||||
ServerAddress: "https://index.docker.io/v1/",
|
||||
},
|
||||
}
|
||||
assert.Assert(t, strings.Contains(buffer.String(), "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format is deprecated and will be removed in an upcoming release"))
|
||||
assert.Check(t, is.DeepEqual(expected, configFile))
|
||||
}
|
||||
|
||||
func TestNewJSON(t *testing.T) {
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
assert.NilError(t, err)
|
||||
|
||||
@ -27,16 +27,19 @@ func TestEncodeAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProxyConfig(t *testing.T) {
|
||||
httpProxy := "http://proxy.mycorp.com:3128"
|
||||
httpsProxy := "https://user:password@proxy.mycorp.com:3129"
|
||||
ftpProxy := "http://ftpproxy.mycorp.com:21"
|
||||
noProxy := "*.intra.mycorp.com"
|
||||
defaultProxyConfig := ProxyConfig{
|
||||
HTTPProxy: httpProxy,
|
||||
HTTPSProxy: httpsProxy,
|
||||
FTPProxy: ftpProxy,
|
||||
NoProxy: noProxy,
|
||||
}
|
||||
var (
|
||||
httpProxy = "http://proxy.mycorp.example.com:3128"
|
||||
httpsProxy = "https://user:password@proxy.mycorp.example.com:3129"
|
||||
ftpProxy = "http://ftpproxy.mycorp.example.com:21"
|
||||
noProxy = "*.intra.mycorp.example.com"
|
||||
|
||||
defaultProxyConfig = ProxyConfig{
|
||||
HTTPProxy: httpProxy,
|
||||
HTTPSProxy: httpsProxy,
|
||||
FTPProxy: ftpProxy,
|
||||
NoProxy: noProxy,
|
||||
}
|
||||
)
|
||||
|
||||
cfg := ConfigFile{
|
||||
Proxies: map[string]ProxyConfig{
|
||||
@ -59,18 +62,21 @@ func TestProxyConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProxyConfigOverride(t *testing.T) {
|
||||
httpProxy := "http://proxy.mycorp.com:3128"
|
||||
overrideHTTPProxy := "http://proxy.example.com:3128"
|
||||
overrideNoProxy := ""
|
||||
httpsProxy := "https://user:password@proxy.mycorp.com:3129"
|
||||
ftpProxy := "http://ftpproxy.mycorp.com:21"
|
||||
noProxy := "*.intra.mycorp.com"
|
||||
defaultProxyConfig := ProxyConfig{
|
||||
HTTPProxy: httpProxy,
|
||||
HTTPSProxy: httpsProxy,
|
||||
FTPProxy: ftpProxy,
|
||||
NoProxy: noProxy,
|
||||
}
|
||||
var (
|
||||
httpProxy = "http://proxy.mycorp.example.com:3128"
|
||||
httpProxyOverride = "http://proxy.example.com:3128"
|
||||
httpsProxy = "https://user:password@proxy.mycorp.example.com:3129"
|
||||
ftpProxy = "http://ftpproxy.mycorp.example.com:21"
|
||||
noProxy = "*.intra.mycorp.example.com"
|
||||
noProxyOverride = ""
|
||||
|
||||
defaultProxyConfig = ProxyConfig{
|
||||
HTTPProxy: httpProxy,
|
||||
HTTPSProxy: httpsProxy,
|
||||
FTPProxy: ftpProxy,
|
||||
NoProxy: noProxy,
|
||||
}
|
||||
)
|
||||
|
||||
cfg := ConfigFile{
|
||||
Proxies: map[string]ProxyConfig{
|
||||
@ -84,46 +90,49 @@ func TestProxyConfigOverride(t *testing.T) {
|
||||
}
|
||||
|
||||
ropts := map[string]*string{
|
||||
"HTTP_PROXY": clone(overrideHTTPProxy),
|
||||
"NO_PROXY": clone(overrideNoProxy),
|
||||
"HTTP_PROXY": clone(httpProxyOverride),
|
||||
"NO_PROXY": clone(noProxyOverride),
|
||||
}
|
||||
proxyConfig := cfg.ParseProxyConfig("/var/run/docker.sock", ropts)
|
||||
expected := map[string]*string{
|
||||
"HTTP_PROXY": &overrideHTTPProxy,
|
||||
"HTTP_PROXY": &httpProxyOverride,
|
||||
"http_proxy": &httpProxy,
|
||||
"HTTPS_PROXY": &httpsProxy,
|
||||
"https_proxy": &httpsProxy,
|
||||
"FTP_PROXY": &ftpProxy,
|
||||
"ftp_proxy": &ftpProxy,
|
||||
"NO_PROXY": &overrideNoProxy,
|
||||
"NO_PROXY": &noProxyOverride,
|
||||
"no_proxy": &noProxy,
|
||||
}
|
||||
assert.Check(t, is.DeepEqual(expected, proxyConfig))
|
||||
}
|
||||
|
||||
func TestProxyConfigPerHost(t *testing.T) {
|
||||
httpProxy := "http://proxy.mycorp.com:3128"
|
||||
httpsProxy := "https://user:password@proxy.mycorp.com:3129"
|
||||
ftpProxy := "http://ftpproxy.mycorp.com:21"
|
||||
noProxy := "*.intra.mycorp.com"
|
||||
var (
|
||||
httpProxy = "http://proxy.mycorp.example.com:3128"
|
||||
httpsProxy = "https://user:password@proxy.mycorp.example.com:3129"
|
||||
ftpProxy = "http://ftpproxy.mycorp.example.com:21"
|
||||
noProxy = "*.intra.mycorp.example.com"
|
||||
|
||||
extHTTPProxy := "http://proxy.example.com:3128"
|
||||
extHTTPSProxy := "https://user:password@proxy.example.com:3129"
|
||||
extFTPProxy := "http://ftpproxy.example.com:21"
|
||||
extNoProxy := "*.intra.example.com"
|
||||
extHTTPProxy = "http://proxy.example.com:3128"
|
||||
extHTTPSProxy = "https://user:password@proxy.example.com:3129"
|
||||
extFTPProxy = "http://ftpproxy.example.com:21"
|
||||
extNoProxy = "*.intra.example.com"
|
||||
|
||||
defaultProxyConfig := ProxyConfig{
|
||||
HTTPProxy: httpProxy,
|
||||
HTTPSProxy: httpsProxy,
|
||||
FTPProxy: ftpProxy,
|
||||
NoProxy: noProxy,
|
||||
}
|
||||
externalProxyConfig := ProxyConfig{
|
||||
HTTPProxy: extHTTPProxy,
|
||||
HTTPSProxy: extHTTPSProxy,
|
||||
FTPProxy: extFTPProxy,
|
||||
NoProxy: extNoProxy,
|
||||
}
|
||||
defaultProxyConfig = ProxyConfig{
|
||||
HTTPProxy: httpProxy,
|
||||
HTTPSProxy: httpsProxy,
|
||||
FTPProxy: ftpProxy,
|
||||
NoProxy: noProxy,
|
||||
}
|
||||
|
||||
externalProxyConfig = ProxyConfig{
|
||||
HTTPProxy: extHTTPProxy,
|
||||
HTTPSProxy: extHTTPSProxy,
|
||||
FTPProxy: extFTPProxy,
|
||||
NoProxy: extNoProxy,
|
||||
}
|
||||
)
|
||||
|
||||
cfg := ConfigFile{
|
||||
Proxies: map[string]ProxyConfig{
|
||||
@ -226,9 +235,11 @@ func TestGetAllCredentialsCredsStore(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAllCredentialsCredHelper(t *testing.T) {
|
||||
testCredHelperSuffix := "test_cred_helper"
|
||||
testCredHelperRegistryHostname := "credhelper.com"
|
||||
testExtraCredHelperRegistryHostname := "somethingweird.com"
|
||||
const (
|
||||
testCredHelperSuffix = "test_cred_helper"
|
||||
testCredHelperRegistryHostname = "credhelper.com"
|
||||
testExtraCredHelperRegistryHostname = "somethingweird.com"
|
||||
)
|
||||
|
||||
unexpectedCredHelperAuth := types.AuthConfig{
|
||||
Username: "file_store_user",
|
||||
@ -265,9 +276,11 @@ func TestGetAllCredentialsCredHelper(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAllCredentialsFileStoreAndCredHelper(t *testing.T) {
|
||||
testFileStoreRegistryHostname := "example.com"
|
||||
testCredHelperSuffix := "test_cred_helper"
|
||||
testCredHelperRegistryHostname := "credhelper.com"
|
||||
const (
|
||||
testFileStoreRegistryHostname = "example.com"
|
||||
testCredHelperSuffix = "test_cred_helper"
|
||||
testCredHelperRegistryHostname = "credhelper.com"
|
||||
)
|
||||
|
||||
expectedFileStoreAuth := types.AuthConfig{
|
||||
Username: "file_store_user",
|
||||
@ -301,10 +314,12 @@ func TestGetAllCredentialsFileStoreAndCredHelper(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAllCredentialsCredStoreAndCredHelper(t *testing.T) {
|
||||
testCredStoreSuffix := "test_creds_store"
|
||||
testCredStoreRegistryHostname := "credstore.com"
|
||||
testCredHelperSuffix := "test_cred_helper"
|
||||
testCredHelperRegistryHostname := "credhelper.com"
|
||||
const (
|
||||
testCredStoreSuffix = "test_creds_store"
|
||||
testCredStoreRegistryHostname = "credstore.com"
|
||||
testCredHelperSuffix = "test_cred_helper"
|
||||
testCredHelperRegistryHostname = "credhelper.com"
|
||||
)
|
||||
|
||||
configFile := New("filename")
|
||||
configFile.CredentialsStore = testCredStoreSuffix
|
||||
@ -343,9 +358,11 @@ func TestGetAllCredentialsCredStoreAndCredHelper(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAllCredentialsCredHelperOverridesDefaultStore(t *testing.T) {
|
||||
testCredStoreSuffix := "test_creds_store"
|
||||
testCredHelperSuffix := "test_cred_helper"
|
||||
testRegistryHostname := "example.com"
|
||||
const (
|
||||
testCredStoreSuffix = "test_creds_store"
|
||||
testCredHelperSuffix = "test_cred_helper"
|
||||
testRegistryHostname = "example.com"
|
||||
)
|
||||
|
||||
configFile := New("filename")
|
||||
configFile.CredentialsStore = testCredStoreSuffix
|
||||
@ -424,38 +441,36 @@ func TestCheckKubernetesConfigurationRaiseAnErrorOnInvalidValue(t *testing.T) {
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"no kubernetes config is valid",
|
||||
nil,
|
||||
false,
|
||||
name: "no kubernetes config is valid",
|
||||
},
|
||||
{
|
||||
"enabled is valid",
|
||||
&KubernetesConfig{AllNamespaces: "enabled"},
|
||||
false,
|
||||
name: "enabled is valid",
|
||||
config: &KubernetesConfig{AllNamespaces: "enabled"},
|
||||
},
|
||||
{
|
||||
"disabled is valid",
|
||||
&KubernetesConfig{AllNamespaces: "disabled"},
|
||||
false,
|
||||
name: "disabled is valid",
|
||||
config: &KubernetesConfig{AllNamespaces: "disabled"},
|
||||
},
|
||||
{
|
||||
"empty string is valid",
|
||||
&KubernetesConfig{AllNamespaces: ""},
|
||||
false,
|
||||
name: "empty string is valid",
|
||||
config: &KubernetesConfig{AllNamespaces: ""},
|
||||
},
|
||||
{
|
||||
"other value is invalid",
|
||||
&KubernetesConfig{AllNamespaces: "unknown"},
|
||||
true,
|
||||
name: "other value is invalid",
|
||||
config: &KubernetesConfig{AllNamespaces: "unknown"},
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
err := checkKubernetesConfiguration(test.config)
|
||||
if test.expectError {
|
||||
assert.Assert(t, err != nil, test.name)
|
||||
} else {
|
||||
assert.NilError(t, err, test.name)
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
test := tc
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := checkKubernetesConfiguration(test.config)
|
||||
if test.expectError {
|
||||
assert.Assert(t, err != nil, test.name)
|
||||
} else {
|
||||
assert.NilError(t, err, test.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ func TestFileStoreGet(t *testing.T) {
|
||||
|
||||
func TestFileStoreGetAll(t *testing.T) {
|
||||
s1 := "https://example.com"
|
||||
s2 := "https://example2.com"
|
||||
s2 := "https://example2.example.com"
|
||||
f := newStore(map[string]types.AuthConfig{
|
||||
s1: {
|
||||
Auth: "super_secret_token",
|
||||
@ -80,7 +80,7 @@ func TestFileStoreGetAll(t *testing.T) {
|
||||
s2: {
|
||||
Auth: "super_secret_token2",
|
||||
Email: "foo@example2.com",
|
||||
ServerAddress: "https://example2.com",
|
||||
ServerAddress: "https://example2.example.com",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper
|
||||
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return commandconn.New(ctx, "ssh", append(sshFlags, sp.Args("docker", "system", "dial-stdio")...)...)
|
||||
},
|
||||
Host: "http://docker",
|
||||
Host: "http://docker.example.com",
|
||||
}, nil
|
||||
}
|
||||
// Future version may support plugins via ~/.docker/config.json. e.g. "dind"
|
||||
@ -63,6 +63,6 @@ func GetCommandConnectionHelper(cmd string, flags ...string) (*ConnectionHelper,
|
||||
Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return commandconn.New(ctx, cmd, flags...)
|
||||
},
|
||||
Host: "http://docker",
|
||||
Host: "http://docker.example.com",
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -26,7 +26,12 @@ type EndpointMeta = context.EndpointMetaBase
|
||||
// a Docker Engine endpoint, with its tls data
|
||||
type Endpoint struct {
|
||||
EndpointMeta
|
||||
TLSData *context.TLSData
|
||||
TLSData *context.TLSData
|
||||
|
||||
// Deprecated: Use of encrypted TLS private keys has been deprecated, and
|
||||
// will be removed in a future release. Golang has deprecated support for
|
||||
// legacy PEM encryption (as specified in RFC 1423), as it is insecure by
|
||||
// design (see https://go-review.googlesource.com/c/go/+/264159).
|
||||
TLSPassword string
|
||||
}
|
||||
|
||||
@ -66,8 +71,9 @@ func (c *Endpoint) tlsConfig() (*tls.Config, error) {
|
||||
}
|
||||
|
||||
var err error
|
||||
if x509.IsEncryptedPEMBlock(pemBlock) {
|
||||
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(c.TLSPassword))
|
||||
// TODO should we follow Golang, and deprecate RFC 1423 encryption, and produce a warning (or just error)? see https://github.com/docker/cli/issues/3212
|
||||
if x509.IsEncryptedPEMBlock(pemBlock) { //nolint: staticcheck // SA1019: x509.IsEncryptedPEMBlock is deprecated, and insecure by design
|
||||
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(c.TLSPassword)) //nolint: staticcheck // SA1019: x509.IsEncryptedPEMBlock is deprecated, and insecure by design
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it")
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ These resources are used to provide
|
||||
* An icon
|
||||
* A Windows manifest declaring Windows version support
|
||||
|
||||
The resource object files are generated with go generate.
|
||||
The resource object files are generated when building with scripts/build/binary .
|
||||
The resource source files are located in scripts/winresources.
|
||||
This occurs automatically when you run scripts/build/windows.
|
||||
|
||||
@ -14,5 +14,3 @@ is included.
|
||||
|
||||
*/
|
||||
package winresources
|
||||
|
||||
//go:generate ../../scripts/gen/windows-resources
|
||||
|
||||
@ -17,7 +17,9 @@ import (
|
||||
func TestClientDebugEnabled(t *testing.T) {
|
||||
defer debug.Disable()
|
||||
|
||||
tcmd := newDockerCommand(&command.DockerCli{})
|
||||
cli, err := command.NewDockerCli()
|
||||
assert.NilError(t, err)
|
||||
tcmd := newDockerCommand(cli)
|
||||
tcmd.SetFlag("debug", "true")
|
||||
cmd, _, err := tcmd.HandleGlobalFlags()
|
||||
assert.NilError(t, err)
|
||||
|
||||
@ -935,7 +935,7 @@ __docker_complete_log_options() {
|
||||
# awslogs does not implement the $common_options2.
|
||||
local awslogs_options="$common_options1 awslogs-create-group awslogs-credentials-endpoint awslogs-datetime-format awslogs-group awslogs-multiline-pattern awslogs-region awslogs-stream tag"
|
||||
|
||||
local fluentd_options="$common_options1 $common_options2 fluentd-address fluentd-async-connect fluentd-buffer-limit fluentd-retry-wait fluentd-max-retries fluentd-sub-second-precision tag"
|
||||
local fluentd_options="$common_options1 $common_options2 fluentd-address fluentd-async fluentd-buffer-limit fluentd-request-ack fluentd-retry-wait fluentd-max-retries fluentd-sub-second-precision tag"
|
||||
local gcplogs_options="$common_options1 $common_options2 gcp-log-cmd gcp-meta-id gcp-meta-name gcp-meta-zone gcp-project"
|
||||
local gelf_options="$common_options1 $common_options2 gelf-address gelf-compression-level gelf-compression-type gelf-tcp-max-reconnect gelf-tcp-reconnect-delay tag"
|
||||
local journald_options="$common_options1 $common_options2 tag"
|
||||
@ -1955,6 +1955,7 @@ _docker_container_run_and_create() {
|
||||
--pid
|
||||
--pids-limit
|
||||
--publish -p
|
||||
--pull
|
||||
--restart
|
||||
--runtime
|
||||
--security-opt
|
||||
@ -2153,6 +2154,10 @@ _docker_container_run_and_create() {
|
||||
esac
|
||||
return
|
||||
;;
|
||||
--pull)
|
||||
COMPREPLY=( $( compgen -W 'always missing never' -- "$cur" ) )
|
||||
return
|
||||
;;
|
||||
--runtime)
|
||||
__docker_complete_runtimes
|
||||
return
|
||||
@ -2548,6 +2553,7 @@ _docker_daemon() {
|
||||
--ip-forward=false
|
||||
--ip-masq=false
|
||||
--iptables=false
|
||||
--ip6tables
|
||||
--ipv6
|
||||
--live-restore
|
||||
--no-new-privileges
|
||||
@ -3601,7 +3607,7 @@ _docker_service_ls() {
|
||||
return
|
||||
;;
|
||||
mode)
|
||||
COMPREPLY=( $( compgen -W "global replicated" -- "${cur##*=}" ) )
|
||||
COMPREPLY=( $( compgen -W "global global-job replicated replicated-job" -- "${cur##*=}" ) )
|
||||
return
|
||||
;;
|
||||
name)
|
||||
@ -3731,6 +3737,7 @@ _docker_service_update_and_create() {
|
||||
--limit-pids
|
||||
--log-driver
|
||||
--log-opt
|
||||
--max-replicas
|
||||
--replicas
|
||||
--replicas-max-per-node
|
||||
--reserve-cpu
|
||||
@ -3804,7 +3811,7 @@ _docker_service_update_and_create() {
|
||||
return
|
||||
;;
|
||||
--mode)
|
||||
COMPREPLY=( $( compgen -W "global replicated" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "global global-job replicated replicated-job" -- "$cur" ) )
|
||||
return
|
||||
;;
|
||||
esac
|
||||
@ -4348,6 +4355,9 @@ _docker_node_ls() {
|
||||
__docker_complete_nodes --cur "${cur##*=}" --id
|
||||
return
|
||||
;;
|
||||
label|node.label)
|
||||
return
|
||||
;;
|
||||
membership)
|
||||
COMPREPLY=( $( compgen -W "accepted pending" -- "${cur##*=}" ) )
|
||||
return
|
||||
@ -4364,7 +4374,7 @@ _docker_node_ls() {
|
||||
|
||||
case "$prev" in
|
||||
--filter|-f)
|
||||
COMPREPLY=( $( compgen -W "id label membership name role" -S = -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "id label membership name node.label role" -S = -- "$cur" ) )
|
||||
__docker_nospace
|
||||
return
|
||||
;;
|
||||
|
||||
@ -1343,7 +1343,7 @@ __docker_node_complete_ls_filters() {
|
||||
;;
|
||||
esac
|
||||
else
|
||||
opts=('id' 'label' 'membership' 'name' 'role')
|
||||
opts=('id' 'label' 'membership' 'name' 'node.label' 'role')
|
||||
_describe -t filter-opts "filter options" opts -qS "=" && ret=0
|
||||
fi
|
||||
|
||||
@ -2544,6 +2544,82 @@ __docker_volume_subcommand() {
|
||||
|
||||
# EO volume
|
||||
|
||||
# BO context
|
||||
|
||||
__docker_complete_contexts() {
|
||||
[[ $PREFIX = -* ]] && return 1
|
||||
integer ret=1
|
||||
declare -a contexts
|
||||
|
||||
contexts=(${(f)${:-"$(_call_program commands docker $docker_options context ls -q)"$'\n'}})
|
||||
|
||||
_describe -t context-list "context" contexts && ret=0
|
||||
return ret
|
||||
}
|
||||
|
||||
__docker_context_commands() {
|
||||
local -a _docker_context_subcommands
|
||||
_docker_context_subcommands=(
|
||||
"create:Create new context"
|
||||
"inspect:Display detailed information on one or more contexts"
|
||||
"list:List available contexts"
|
||||
"rm:Remove one or more contexts"
|
||||
"show:Print the current context"
|
||||
"update:Update a context"
|
||||
"use:Set the default context"
|
||||
)
|
||||
_describe -t docker-context-commands "docker context command" _docker_context_subcommands
|
||||
}
|
||||
|
||||
__docker_context_subcommand() {
|
||||
local -a _command_args opts_help
|
||||
local expl help="--help"
|
||||
integer ret=1
|
||||
|
||||
opts_help=("(: -)--help[Print usage]")
|
||||
|
||||
case "$words[1]" in
|
||||
(create)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help)--default-stack-orchestrator=[Default orchestrator for stack operations to use with this context]:default-stack-orchestrator:(swarm kubernetes all)" \
|
||||
"($help)--description=[Description of the context]:description:" \
|
||||
"($help)--docker=[Set the docker endpoint]:docker:" \
|
||||
"($help)--kubernetes=[Set the kubernetes endpoint]:kubernetes:" \
|
||||
"($help)--from=[Create context from a named context]:from:__docker_complete_contexts" \
|
||||
"($help -):name: " && ret=0
|
||||
;;
|
||||
(use)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help -)1:context:__docker_complete_contexts" && ret=0
|
||||
;;
|
||||
(inspect)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help -)1:context:__docker_complete_contexts" && ret=0
|
||||
;;
|
||||
(rm)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help -)1:context:__docker_complete_contexts" && ret=0
|
||||
;;
|
||||
(update)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help)--default-stack-orchestrator=[Default orchestrator for stack operations to use with this context]:default-stack-orchestrator:(swarm kubernetes all)" \
|
||||
"($help)--description=[Description of the context]:description:" \
|
||||
"($help)--docker=[Set the docker endpoint]:docker:" \
|
||||
"($help)--kubernetes=[Set the kubernetes endpoint]:kubernetes:" \
|
||||
"($help -):name:" && ret=0
|
||||
;;
|
||||
esac
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
# EO context
|
||||
|
||||
__docker_caching_policy() {
|
||||
oldp=( "$1"(Nmh+1) ) # 1 hour
|
||||
(( $#oldp ))
|
||||
@ -2631,6 +2707,23 @@ __docker_subcommand() {
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
(context)
|
||||
local curcontext="$curcontext" state
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help -): :->command" \
|
||||
"($help -)*:: :->option-or-argument" && ret=0
|
||||
|
||||
case $state in
|
||||
(command)
|
||||
__docker_context_commands && ret=0
|
||||
;;
|
||||
(option-or-argument)
|
||||
curcontext=${curcontext%:*:*}:docker-${words[-1]}:
|
||||
__docker_context_subcommand && ret=0
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
(daemon)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
|
||||
63
docker-bake.hcl
Normal file
@ -0,0 +1,63 @@
|
||||
variable "VERSION" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "USE_GLIBC" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "STRIP_TARGET" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
group "default" {
|
||||
targets = ["binary"]
|
||||
}
|
||||
|
||||
target "binary" {
|
||||
target = "binary"
|
||||
platforms = ["local"]
|
||||
output = ["build"]
|
||||
args = {
|
||||
BASE_VARIANT = USE_GLIBC != "" ? "buster" : "alpine"
|
||||
VERSION = VERSION
|
||||
GO_STRIP = STRIP_TARGET
|
||||
}
|
||||
}
|
||||
|
||||
target "dynbinary" {
|
||||
inherits = ["binary"]
|
||||
args = {
|
||||
GO_LINKMODE = "dynamic"
|
||||
}
|
||||
}
|
||||
|
||||
variable "GROUP_TOTAL" {
|
||||
default = "1"
|
||||
}
|
||||
|
||||
variable "GROUP_INDEX" {
|
||||
default = "0"
|
||||
}
|
||||
|
||||
function "platforms" {
|
||||
params = []
|
||||
result = ["linux/amd64", "linux/386", "linux/arm64", "linux/arm", "linux/ppc64le", "linux/s390x", "darwin/amd64", "darwin/arm64", "windows/amd64"]
|
||||
}
|
||||
|
||||
function "glen" {
|
||||
params = [platforms, GROUP_TOTAL]
|
||||
result = ceil(length(platforms)/GROUP_TOTAL)
|
||||
}
|
||||
|
||||
target "_all_platforms" {
|
||||
platforms = slice(platforms(), GROUP_INDEX*glen(platforms(), GROUP_TOTAL),min(length(platforms()), (GROUP_INDEX+1)*glen(platforms(), GROUP_TOTAL)))
|
||||
}
|
||||
|
||||
target "cross" {
|
||||
inherits = ["binary", "_all_platforms"]
|
||||
}
|
||||
|
||||
target "dynbinary-cross" {
|
||||
inherits = ["dynbinary", "_all_platforms"]
|
||||
}
|
||||
@ -38,11 +38,6 @@ build_linter_image:
|
||||
# build dockerfile from stdin so that we don't send the build-context; source is bind-mounted in the development environment
|
||||
cat ./dockerfiles/Dockerfile.lint | docker build ${DOCKER_BUILD_ARGS} --build-arg=GO_VERSION -t $(LINTER_IMAGE_NAME) -
|
||||
|
||||
.PHONY: build_cross_image
|
||||
build_cross_image:
|
||||
# build dockerfile from stdin so that we don't send the build-context; source is bind-mounted in the development environment
|
||||
cat ./dockerfiles/Dockerfile.cross | docker build ${DOCKER_BUILD_ARGS} --build-arg=GO_VERSION -t $(CROSS_IMAGE_NAME) -
|
||||
|
||||
.PHONY: build_shell_validate_image
|
||||
build_shell_validate_image:
|
||||
# build dockerfile from stdin so that we don't send the build-context; source is bind-mounted in the development environment
|
||||
@ -80,22 +75,10 @@ test-unit: build_docker_image ## run unit tests (using go test)
|
||||
.PHONY: test ## run unit and e2e tests
|
||||
test: test-unit test-e2e
|
||||
|
||||
.PHONY: cross
|
||||
cross: build_cross_image ## build the CLI for macOS and Windows
|
||||
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make cross
|
||||
|
||||
.PHONY: binary-windows
|
||||
binary-windows: build_cross_image ## build the CLI for Windows
|
||||
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@
|
||||
|
||||
.PHONY: plugins-windows
|
||||
plugins-windows: build_cross_image ## build the example CLI plugins for Windows
|
||||
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@
|
||||
|
||||
.PHONY: binary-osx
|
||||
binary-osx: build_cross_image ## build the CLI for macOS
|
||||
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@
|
||||
|
||||
.PHONY: plugins-osx
|
||||
plugins-osx: build_cross_image ## build the example CLI plugins for macOS
|
||||
$(DOCKER_RUN) $(CROSS_IMAGE_NAME) make $@
|
||||
@ -120,9 +103,6 @@ fmt: ## run gofmt
|
||||
vendor: build_docker_image vendor.conf ## download dependencies (vendor/) listed in vendor.conf
|
||||
$(DOCKER_RUN) -it $(DEV_DOCKER_IMAGE_NAME) make vendor
|
||||
|
||||
dynbinary: build_cross_image ## build the CLI dynamically linked
|
||||
$(DOCKER_RUN) -it $(CROSS_IMAGE_NAME) make dynbinary
|
||||
|
||||
.PHONY: authors
|
||||
authors: ## generate AUTHORS file from git history
|
||||
$(DOCKER_RUN) -it $(DEV_DOCKER_IMAGE_NAME) make authors
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.13.15
|
||||
ARG GO_VERSION=1.16.8
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# syntax=docker/dockerfile:1.1.7-experimental
|
||||
ARG GO_VERSION=1.13.15
|
||||
# syntax=docker/dockerfile:1.3
|
||||
|
||||
ARG GO_VERSION=1.16.8
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS golang
|
||||
ENV CGO_ENABLED=0
|
||||
@ -9,21 +10,21 @@ ARG ESC_VERSION=v0.2.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
GO111MODULE=on go get github.com/mjibson/esc@${ESC_VERSION}
|
||||
GO111MODULE=on go install github.com/mjibson/esc@${ESC_VERSION}
|
||||
|
||||
FROM golang AS gotestsum
|
||||
ARG GOTESTSUM_VERSION=v0.4.0
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
GO111MODULE=on go get gotest.tools/gotestsum@${GOTESTSUM_VERSION}
|
||||
GO111MODULE=on go install gotest.tools/gotestsum@${GOTESTSUM_VERSION}
|
||||
|
||||
FROM golang AS vndr
|
||||
ARG VNDR_VERSION=v0.1.2
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
--mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=tmpfs,target=/go/src/ \
|
||||
GO111MODULE=on go get github.com/LK4D4/vndr@${VNDR_VERSION}
|
||||
GO111MODULE=on go install github.com/LK4D4/vndr@${VNDR_VERSION}
|
||||
|
||||
FROM golang AS dev
|
||||
RUN apk add --no-cache \
|
||||
@ -43,4 +44,5 @@ COPY --from=vndr /go/bin/* /go/bin/
|
||||
COPY --from=gotestsum /go/bin/* /go/bin/
|
||||
|
||||
WORKDIR /go/src/github.com/docker/cli
|
||||
ENV GO111MODULE=auto
|
||||
COPY . .
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.13.15
|
||||
ARG GO_VERSION=1.16.8
|
||||
|
||||
# Use Debian based image as docker-compose requires glibc.
|
||||
FROM golang:${GO_VERSION}-buster
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# syntax=docker/dockerfile:1.1.3-experimental
|
||||
# syntax=docker/dockerfile:1.3
|
||||
|
||||
ARG GO_VERSION=1.13.15
|
||||
ARG GO_VERSION=1.16.8
|
||||
ARG GOLANGCI_LINTER_SHA="v1.21.0"
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS build
|
||||
@ -13,6 +13,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
|
||||
go get github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINTER_SHA}
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine AS lint
|
||||
ENV GO111MODULE=off
|
||||
ENV CGO_ENABLED=0
|
||||
ENV DISABLE_WARN_OUTSIDE_CONTAINER=1
|
||||
COPY --from=build /go/bin/golangci-lint /usr/local/bin
|
||||
|
||||
@ -50,8 +50,11 @@ The table below provides an overview of the current status of deprecated feature
|
||||
|
||||
Status | Feature | Deprecated | Remove
|
||||
-----------|------------------------------------------------------------------------------------------------------------------------------------|------------|------------
|
||||
Deprecated | [Support for encrypted TLS private keys](#support-for-encrypted-tls-private-keys) | v20.10 | -
|
||||
Deprecated | [Kubernetes stack and context support](#kubernetes-stack-and-context-support) | v20.10 | -
|
||||
Deprecated | [Pulling images from non-compliant image registries](#pulling-images-from-non-compliant-image-registries) | v20.10 | -
|
||||
Deprecated | [Linux containers on Windows (LCOW)](#linux-containers-on-windows-lcow-experimental) | v20.10 | -
|
||||
Deprecated | [BLKIO weight options with cgroups v1](#blkio-weight-options–with-cgroups-v1) | v20.10 | -
|
||||
Deprecated | [Kernel memory limit](#kernel-memory-limit) | v20.10 | -
|
||||
Deprecated | [Classic Swarm and overlay networks using external key/value stores](#classic-swarm-and-overlay-networks-using-cluster-store) | v20.10 | -
|
||||
Deprecated | [Support for the legacy `~/.dockercfg` configuration file for authentication](#support-for-legacy-dockercfg-configuration-files) | v20.10 | -
|
||||
@ -96,6 +99,22 @@ Removed | [`--api-enable-cors` flag on `dockerd`](#--api-enable-cors-flag-on-
|
||||
Removed | [`--run` flag on `docker commit`](#--run-flag-on-docker-commit) | v0.10 | v1.13
|
||||
Removed | [Three arguments form in `docker import`](#three-arguments-form-in-docker-import) | v0.6.7 | v1.12
|
||||
|
||||
### Support for encrypted TLS private keys
|
||||
|
||||
**Deprecated in Release: v20.10**
|
||||
|
||||
Use of encrypted TLS private keys has been deprecated, and will be removed in a
|
||||
future release. Golang has deprecated support for legacy PEM encryption (as
|
||||
specified in [RFC 1423](https://datatracker.ietf.org/doc/html/rfc1423)), as it
|
||||
is insecure by design (see [https://go-review.googlesource.com/c/go/+/264159](https://go-review.googlesource.com/c/go/+/264159)).
|
||||
|
||||
### Kubernetes stack and context support
|
||||
|
||||
**Deprecated in Release: v20.10**
|
||||
|
||||
Following the deprecation of [Compose on Kubernetes](https://github.com/docker/compose-on-kubernetes), support for
|
||||
Kubernetes in the `stack` and `context` commands in the docker CLI is now marked as deprecated as well.
|
||||
|
||||
### Pulling images from non-compliant image registries
|
||||
|
||||
**Deprecated in Release: v20.10**
|
||||
@ -140,6 +159,16 @@ now stopped in favor of running docker natively on Linux in WSL2.
|
||||
Developers who want to run Linux workloads on a Windows host are encouraged to use
|
||||
[Docker Desktop with WSL2](https://docs.docker.com/docker-for-windows/wsl/) instead.
|
||||
|
||||
### BLKIO weight options with cgroups v1
|
||||
|
||||
**Deprecated in Release: v20.10**
|
||||
|
||||
Specifying blkio weight (`docker run --blkio-weight` and `docker run --blkio-weight-device`)
|
||||
is now marked as deprecated when using cgroups v1 because the corresponding features
|
||||
were [removed in Linux kernel v5.0 and up](https://github.com/torvalds/linux/commit/f382fb0bcef4c37dc049e9f6963e3baf204d815c).
|
||||
When using cgroups v2, the `--blkio-weight` options are implemented using
|
||||
[`io.weight](https://github.com/torvalds/linux/blob/v5.0/Documentation/admin-guide/cgroup-v2.rst#io).
|
||||
|
||||
### Kernel memory limit
|
||||
|
||||
**Deprecated in Release: v20.10**
|
||||
|
||||
@ -122,7 +122,7 @@ enabled, and use it to create a volume.
|
||||
To disable a plugin, use the `docker plugin disable` command. To completely
|
||||
remove it, use the `docker plugin remove` command. For other available
|
||||
commands and options, see the
|
||||
[command line reference](../reference/commandline/index.md).
|
||||
[command line reference](https://docs.docker.com/engine/reference/commandline/cli/).
|
||||
|
||||
|
||||
## Developing a plugin
|
||||
|
||||
@ -33,11 +33,11 @@ a `Dockerfile` and a *context*. The build's context is the set of files at a
|
||||
specified location `PATH` or `URL`. The `PATH` is a directory on your local
|
||||
filesystem. The `URL` is a Git repository location.
|
||||
|
||||
A context is processed recursively. So, a `PATH` includes any subdirectories and
|
||||
the `URL` includes the repository and its submodules. This example shows a
|
||||
build command that uses the current directory as context:
|
||||
The build context is processed recursively. So, a `PATH` includes any subdirectories
|
||||
and the `URL` includes the repository and its submodules. This example shows a
|
||||
build command that uses the current directory (`.`) as build context:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build .
|
||||
|
||||
Sending build context to Docker daemon 6.51 MB
|
||||
@ -52,8 +52,9 @@ Dockerfile.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> Do not use your root directory, `/`, as the `PATH` as it causes the build to
|
||||
> transfer the entire contents of your hard drive to the Docker daemon.
|
||||
> Do not use your root directory, `/`, as the `PATH` for your build context, as
|
||||
> it causes the build to transfer the entire contents of your hard drive to the
|
||||
> Docker daemon.
|
||||
{:.warning}
|
||||
|
||||
To use a file in the build context, the `Dockerfile` refers to the file specified
|
||||
@ -66,32 +67,37 @@ Traditionally, the `Dockerfile` is called `Dockerfile` and located in the root
|
||||
of the context. You use the `-f` flag with `docker build` to point to a Dockerfile
|
||||
anywhere in your file system.
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build -f /path/to/a/Dockerfile .
|
||||
```
|
||||
|
||||
You can specify a repository and tag at which to save the new image if
|
||||
the build succeeds:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build -t shykes/myapp .
|
||||
```
|
||||
|
||||
To tag the image into multiple repositories after the build,
|
||||
add multiple `-t` parameters when you run the `build` command:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
|
||||
```
|
||||
|
||||
Before the Docker daemon runs the instructions in the `Dockerfile`, it performs
|
||||
a preliminary validation of the `Dockerfile` and returns an error if the syntax is incorrect:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build -t test/myapp .
|
||||
|
||||
Sending build context to Docker daemon 2.048 kB
|
||||
Error response from daemon: Unknown instruction: RUNCMD
|
||||
[+] Building 0.3s (2/2) FINISHED
|
||||
=> [internal] load build definition from Dockerfile 0.1s
|
||||
=> => transferring dockerfile: 60B 0.0s
|
||||
=> [internal] load .dockerignore 0.1s
|
||||
=> => transferring context: 2B 0.0s
|
||||
error: failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition:
|
||||
dockerfile parse error line 2: unknown instruction: RUNCMD
|
||||
```
|
||||
|
||||
The Docker daemon runs the instructions in the `Dockerfile` one-by-one,
|
||||
@ -104,38 +110,35 @@ Note that each instruction is run independently, and causes a new image
|
||||
to be created - so `RUN cd /tmp` will not have any effect on the next
|
||||
instructions.
|
||||
|
||||
Whenever possible, Docker will re-use the intermediate images (cache),
|
||||
to accelerate the `docker build` process significantly. This is indicated by
|
||||
the `Using cache` message in the console output.
|
||||
(For more information, see the [`Dockerfile` best practices guide](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/):
|
||||
Whenever possible, Docker uses a build-cache to accelerate the `docker build`
|
||||
process significantly. This is indicated by the `CACHED` message in the console
|
||||
output. (For more information, see the [`Dockerfile` best practices guide](https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/):
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build -t svendowideit/ambassador .
|
||||
|
||||
Sending build context to Docker daemon 15.36 kB
|
||||
Step 1/4 : FROM alpine:3.2
|
||||
---> 31f630c65071
|
||||
Step 2/4 : MAINTAINER SvenDowideit@home.org.au
|
||||
---> Using cache
|
||||
---> 2a1c91448f5f
|
||||
Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/
|
||||
---> Using cache
|
||||
---> 21ed6e7fbb73
|
||||
Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
|
||||
---> Using cache
|
||||
---> 7ea8aef582cc
|
||||
Successfully built 7ea8aef582cc
|
||||
[+] Building 0.7s (6/6) FINISHED
|
||||
=> [internal] load build definition from Dockerfile 0.1s
|
||||
=> => transferring dockerfile: 286B 0.0s
|
||||
=> [internal] load .dockerignore 0.1s
|
||||
=> => transferring context: 2B 0.0s
|
||||
=> [internal] load metadata for docker.io/library/alpine:3.2 0.4s
|
||||
=> CACHED [1/2] FROM docker.io/library/alpine:3.2@sha256:e9a2035f9d0d7ce 0.0s
|
||||
=> CACHED [2/2] RUN apk add --no-cache socat 0.0s
|
||||
=> exporting to image 0.0s
|
||||
=> => exporting layers 0.0s
|
||||
=> => writing image sha256:1affb80ca37018ac12067fa2af38cc5bcc2a8f09963de 0.0s
|
||||
=> => naming to docker.io/svendowideit/ambassador 0.0s
|
||||
```
|
||||
|
||||
Build cache is only used from images that have a local parent chain. This means
|
||||
that these images were created by previous builds or the whole chain of images
|
||||
was loaded with `docker load`. If you wish to use build cache of a specific
|
||||
image you can specify it with `--cache-from` option. Images specified with
|
||||
`--cache-from` do not need to have a parent chain and may be pulled from other
|
||||
registries.
|
||||
By default, the build cache is based on results from previous builds on the machine
|
||||
on which you are building. The `--cache-from` option also allows you to use a
|
||||
build-cache that's distributed through an image registry refer to the
|
||||
[specifying external cache sources](commandline/build.md#specifying-external-cache-sources)
|
||||
section in the `docker build` command reference.
|
||||
|
||||
When you're done with your build, you're ready to look into [*Pushing a
|
||||
repository to its registry*](https://docs.docker.com/engine/tutorials/dockerrepos/#/contributing-to-docker-hub).
|
||||
When you're done with your build, you're ready to look into [scanning your image with `docker scan`](https://docs.docker.com/engine/scan/),
|
||||
and [pushing your image to Docker Hub](https://docs.docker.com/docker-hub/repos/).
|
||||
|
||||
|
||||
## BuildKit
|
||||
@ -315,6 +318,8 @@ The following parser directives are supported:
|
||||
|
||||
## syntax
|
||||
|
||||
<a name="external-implementation-features"><!-- included for deep-links to old section --></a>
|
||||
|
||||
```dockerfile
|
||||
# syntax=[remote image reference]
|
||||
```
|
||||
@ -322,55 +327,73 @@ The following parser directives are supported:
|
||||
For example:
|
||||
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile
|
||||
# syntax=docker/dockerfile:1.0
|
||||
# syntax=docker/dockerfile:1
|
||||
# syntax=docker.io/docker/dockerfile:1
|
||||
# syntax=docker/dockerfile:1.0.0-experimental
|
||||
# syntax=example.com/user/repo:tag@sha256:abcdef...
|
||||
```
|
||||
|
||||
This feature is only enabled if the [BuildKit](#buildkit) backend is used.
|
||||
This feature is only available when using the [BuildKit](#buildkit) backend, and
|
||||
is ignored when using the classic builder backend.
|
||||
|
||||
The syntax directive defines the location of the Dockerfile builder that is used for
|
||||
building the current Dockerfile. The BuildKit backend allows to seamlessly use
|
||||
external implementations of builders that are distributed as Docker images and
|
||||
execute inside a container sandbox environment.
|
||||
The syntax directive defines the location of the Dockerfile syntax that is used
|
||||
to build the Dockerfile. The BuildKit backend allows to seamlessly use external
|
||||
implementations that are distributed as Docker images and execute inside a
|
||||
container sandbox environment.
|
||||
|
||||
Custom Dockerfile implementation allows you to:
|
||||
Custom Dockerfile implementations allows you to:
|
||||
|
||||
- Automatically get bugfixes without updating the daemon
|
||||
- Automatically get bugfixes without updating the Docker daemon
|
||||
- Make sure all users are using the same implementation to build your Dockerfile
|
||||
- Use the latest features without updating the daemon
|
||||
- Try out new experimental or third-party features
|
||||
- Use the latest features without updating the Docker daemon
|
||||
- Try out new features or third-party features before they are integrated in the Docker daemon
|
||||
- Use [alternative build definitions, or create your own](https://github.com/moby/buildkit#exploring-llb)
|
||||
|
||||
### Official releases
|
||||
|
||||
Docker distributes official versions of the images that can be used for building
|
||||
Dockerfiles under `docker/dockerfile` repository on Docker Hub. There are two
|
||||
channels where new images are released: stable and experimental.
|
||||
channels where new images are released: `stable` and `labs`.
|
||||
|
||||
Stable channel follows semantic versioning. For example:
|
||||
Stable channel follows [semantic versioning](https://semver.org). For example:
|
||||
|
||||
- `docker/dockerfile:1.0.0` - only allow immutable version `1.0.0`
|
||||
- `docker/dockerfile:1.0` - allow versions `1.0.*`
|
||||
- `docker/dockerfile:1` - allow versions `1.*.*`
|
||||
- `docker/dockerfile:latest` - latest release on stable channel
|
||||
- `docker/dockerfile:1` - kept updated with the latest `1.x.x` minor _and_ patch release
|
||||
- `docker/dockerfile:1.2` - kept updated with the latest `1.2.x` patch release,
|
||||
and stops receiving updates once version `1.3.0` is released.
|
||||
- `docker/dockerfile:1.2.1` - immutable: never updated
|
||||
|
||||
The experimental channel uses incremental versioning with the major and minor
|
||||
component from the stable channel on the time of the release. For example:
|
||||
We recommend using `docker/dockerfile:1`, which always points to the latest stable
|
||||
release of the version 1 syntax, and receives both "minor" and "patch" updates
|
||||
for the version 1 release cycle. BuildKit automatically checks for updates of the
|
||||
syntax when performing a build, making sure you are using the most current version.
|
||||
|
||||
- `docker/dockerfile:1.0.1-experimental` - only allow immutable version `1.0.1-experimental`
|
||||
- `docker/dockerfile:1.0-experimental` - latest experimental releases after `1.0`
|
||||
- `docker/dockerfile:experimental` - latest release on experimental channel
|
||||
If a specific version is used, such as `1.2` or `1.2.1`, the Dockerfile needs to
|
||||
be updated manually to continue receiving bugfixes and new features. Old versions
|
||||
of the Dockerfile remain compatible with the new versions of the builder.
|
||||
|
||||
You should choose a channel that best fits your needs. If you only want
|
||||
bugfixes, you should use `docker/dockerfile:1.0`. If you want to benefit from
|
||||
experimental features, you should use the experimental channel. If you are using
|
||||
the experimental channel, newer releases may not be backwards compatible, so it
|
||||
**labs channel**
|
||||
|
||||
The "labs" channel provides early access to Dockerfile features that are not yet
|
||||
available in the stable channel. Labs channel images are released in conjunction
|
||||
with the stable releases, and follow the same versioning with the `-labs` suffix,
|
||||
for example:
|
||||
|
||||
- `docker/dockerfile:labs` - latest release on labs channel
|
||||
- `docker/dockerfile:1-labs` - same as `dockerfile:1` in the stable channel, with labs features enabled
|
||||
- `docker/dockerfile:1.2-labs` - same as `dockerfile:1.2` in the stable channel, with labs features enabled
|
||||
- `docker/dockerfile:1.2.1-labs` - immutable: never updated. Same as `dockerfile:1.2.1` in the stable channel, with labs features enabled
|
||||
|
||||
Choose a channel that best fits your needs; if you want to benefit from
|
||||
new features, use the labs channel. Images in the labs channel provide a superset
|
||||
of the features in the stable channel; note that `stable` features in the labs
|
||||
channel images follow [semantic versioning](https://semver.org), but "labs"
|
||||
features do not, and newer releases may not be backwards compatible, so it
|
||||
is recommended to use an immutable full version variant.
|
||||
|
||||
For master builds and nightly feature releases refer to the description in
|
||||
[the source repository](https://github.com/moby/buildkit/blob/master/README.md).
|
||||
For documentation on "labs" features, master builds, and nightly feature releases,
|
||||
refer to the description in [the BuildKit source repository on GitHub](https://github.com/moby/buildkit/blob/master/README.md).
|
||||
For a full list of available images, visit the [image repository on Docker Hub](https://hub.docker.com/r/docker/dockerfile),
|
||||
and the [docker/dockerfile-upstream image repository](https://hub.docker.com/r/docker/dockerfile-upstream)
|
||||
for development builds.
|
||||
|
||||
## escape
|
||||
|
||||
@ -413,14 +436,15 @@ RUN dir c:\
|
||||
|
||||
Results in:
|
||||
|
||||
```powershell
|
||||
PS C:\John> docker build -t cmd .
|
||||
```console
|
||||
PS E:\myproject> docker build -t cmd .
|
||||
|
||||
Sending build context to Docker daemon 3.072 kB
|
||||
Step 1/2 : FROM microsoft/nanoserver
|
||||
---> 22738ff49c6d
|
||||
Step 2/2 : COPY testfile.txt c:\RUN dir c:
|
||||
GetFileAttributesEx c:RUN: The system cannot find the file specified.
|
||||
PS C:\John>
|
||||
PS E:\myproject>
|
||||
```
|
||||
|
||||
One solution to the above would be to use `/` as the target of both the `COPY`
|
||||
@ -441,8 +465,9 @@ RUN dir c:\
|
||||
|
||||
Results in:
|
||||
|
||||
```powershell
|
||||
PS C:\John> docker build -t succeeds --no-cache=true .
|
||||
```console
|
||||
PS E:\myproject> docker build -t succeeds --no-cache=true .
|
||||
|
||||
Sending build context to Docker daemon 3.072 kB
|
||||
Step 1/3 : FROM microsoft/nanoserver
|
||||
---> 22738ff49c6d
|
||||
@ -467,7 +492,7 @@ Step 3/3 : RUN dir c:\
|
||||
---> 01c7f3bef04f
|
||||
Removing intermediate container a2c157f842f5
|
||||
Successfully built 01c7f3bef04f
|
||||
PS C:\John>
|
||||
PS E:\myproject>
|
||||
```
|
||||
|
||||
## Environment replacement
|
||||
@ -910,8 +935,8 @@ the most-recently-applied value overrides any previously-set value.
|
||||
To view an image's labels, use the `docker image inspect` command. You can use
|
||||
the `--format` option to show just the labels;
|
||||
|
||||
```bash
|
||||
docker image inspect --format='{{json .Config.Labels}}' myimage
|
||||
```console
|
||||
$ docker image inspect --format='{{json .Config.Labels}}' myimage
|
||||
```
|
||||
```json
|
||||
{
|
||||
@ -938,7 +963,7 @@ easily, for example with `docker inspect`. To set a label corresponding to the
|
||||
`MAINTAINER` field you could use:
|
||||
|
||||
```dockerfile
|
||||
LABEL maintainer="SvenDowideit@home.org.au"
|
||||
LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"
|
||||
```
|
||||
|
||||
This will then be visible from `docker inspect` with the other labels.
|
||||
@ -980,8 +1005,8 @@ port on the host, so the port will not be the same for TCP and UDP.
|
||||
Regardless of the `EXPOSE` settings, you can override them at runtime by using
|
||||
the `-p` flag. For example
|
||||
|
||||
```bash
|
||||
docker run -p 80:80/tcp -p 80:80/udp ...
|
||||
```console
|
||||
$ docker run -p 80:80/tcp -p 80:80/udp ...
|
||||
```
|
||||
|
||||
To set up port redirection on the host system, see [using the -P flag](run.md#expose-incoming-ports).
|
||||
@ -1397,7 +1422,7 @@ An `ENTRYPOINT` allows you to configure a container that will run as an executab
|
||||
For example, the following starts nginx with its default content, listening
|
||||
on port 80:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker run -i -t --rm -p 80:80 nginx
|
||||
```
|
||||
|
||||
@ -1432,7 +1457,7 @@ CMD ["-c"]
|
||||
|
||||
When you run the container, you can see that `top` is the only process:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker run -it --rm --name test top -H
|
||||
|
||||
top - 08:25:00 up 7:27, 0 users, load average: 0.00, 0.01, 0.05
|
||||
@ -1447,7 +1472,7 @@ KiB Swap: 1441840 total, 0 used, 1441840 free. 1324440 cached Mem
|
||||
|
||||
To examine the result further, you can use `docker exec`:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker exec -it test ps aux
|
||||
|
||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
@ -1519,7 +1544,7 @@ If you run this image with `docker run -it --rm -p 80:80 --name test apache`,
|
||||
you can then examine the container's processes with `docker exec`, or `docker top`,
|
||||
and then ask the script to stop Apache:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker exec -it test ps aux
|
||||
|
||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
@ -1579,7 +1604,7 @@ ENTRYPOINT exec top -b
|
||||
|
||||
When you run this image, you'll see the single `PID 1` process:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker run -it --rm --name test top
|
||||
|
||||
Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
|
||||
@ -1591,7 +1616,7 @@ Load average: 0.08 0.03 0.05 2/98 6
|
||||
|
||||
Which exits cleanly on `docker stop`:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ /usr/bin/time docker stop test
|
||||
|
||||
test
|
||||
@ -1610,7 +1635,7 @@ CMD --ignored-param1
|
||||
|
||||
You can then run it (giving it a name for the next step):
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker run -it --name test top --ignored-param2
|
||||
|
||||
Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
|
||||
@ -1626,7 +1651,7 @@ You can see from the output of `top` that the specified `ENTRYPOINT` is not `PID
|
||||
If you then run `docker stop test`, the container will not exit cleanly - the
|
||||
`stop` command will be forced to send a `SIGKILL` after the timeout:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker exec -it test ps aux
|
||||
|
||||
PID USER COMMAND
|
||||
@ -1859,9 +1884,10 @@ ARG user
|
||||
USER $user
|
||||
# ...
|
||||
```
|
||||
|
||||
A user builds this file by calling:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build --build-arg user=what_user .
|
||||
```
|
||||
|
||||
@ -1900,7 +1926,7 @@ RUN echo $CONT_IMG_VER
|
||||
|
||||
Then, assume this image is built with this command:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build --build-arg CONT_IMG_VER=v2.0.1 .
|
||||
```
|
||||
|
||||
@ -1922,7 +1948,7 @@ RUN echo $CONT_IMG_VER
|
||||
Unlike an `ARG` instruction, `ENV` values are always persisted in the built
|
||||
image. Consider a docker build without the `--build-arg` flag:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build .
|
||||
```
|
||||
|
||||
@ -1948,10 +1974,11 @@ corresponding `ARG` instruction in the Dockerfile.
|
||||
- `NO_PROXY`
|
||||
- `no_proxy`
|
||||
|
||||
To use these, simply pass them on the command line using the flag:
|
||||
To use these, pass them on the command line using the `--build-arg` flag, for
|
||||
example:
|
||||
|
||||
```bash
|
||||
--build-arg <varname>=<value>
|
||||
```console
|
||||
$ docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .
|
||||
```
|
||||
|
||||
By default, these pre-defined variables are excluded from the output of
|
||||
@ -2298,8 +2325,9 @@ RUN c:\example\Execute-MyCmdlet -sample 'hello world'
|
||||
|
||||
Resulting in:
|
||||
|
||||
```powershell
|
||||
PS E:\docker\build\shell> docker build -t shell .
|
||||
```console
|
||||
PS E:\myproject> docker build -t shell .
|
||||
|
||||
Sending build context to Docker daemon 4.096 kB
|
||||
Step 1/5 : FROM microsoft/nanoserver
|
||||
---> 22738ff49c6d
|
||||
@ -2314,9 +2342,9 @@ Step 3/5 : RUN New-Item -ItemType Directory C:\Example
|
||||
Directory: C:\
|
||||
|
||||
|
||||
Mode LastWriteTime Length Name
|
||||
---- ------------- ------ ----
|
||||
d----- 10/28/2016 11:26 AM Example
|
||||
Mode LastWriteTime Length Name
|
||||
---- ------------- ------ ----
|
||||
d----- 10/28/2016 11:26 AM Example
|
||||
|
||||
|
||||
---> 3f2fbf1395d9
|
||||
@ -2330,7 +2358,7 @@ hello world
|
||||
---> 8e559e9bf424
|
||||
Removing intermediate container be6d8e63fe75
|
||||
Successfully built 8e559e9bf424
|
||||
PS E:\docker\build\shell>
|
||||
PS E:\myproject>
|
||||
```
|
||||
|
||||
The `SHELL` instruction could also be used to modify the way in which
|
||||
@ -2340,61 +2368,10 @@ environment variable expansion semantics could be modified.
|
||||
The `SHELL` instruction can also be used on Linux should an alternate shell be
|
||||
required such as `zsh`, `csh`, `tcsh` and others.
|
||||
|
||||
## External implementation features
|
||||
|
||||
This feature is only available when using the [BuildKit](#buildkit) backend.
|
||||
|
||||
Docker build supports experimental features like cache mounts, build secrets and
|
||||
ssh forwarding that are enabled by using an external implementation of the
|
||||
builder with a syntax directive. To learn about these features,
|
||||
[refer to the documentation in BuildKit repository](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md).
|
||||
|
||||
## Dockerfile examples
|
||||
|
||||
Below you can see some examples of Dockerfile syntax.
|
||||
For examples of Dockerfiles, refer to:
|
||||
|
||||
```dockerfile
|
||||
# Nginx
|
||||
#
|
||||
# VERSION 0.0.1
|
||||
|
||||
FROM ubuntu
|
||||
LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
|
||||
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
|
||||
```
|
||||
|
||||
```dockerfile
|
||||
# Firefox over VNC
|
||||
#
|
||||
# VERSION 0.3
|
||||
|
||||
FROM ubuntu
|
||||
|
||||
# Install vnc, xvfb in order to create a 'fake' display and firefox
|
||||
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
|
||||
RUN mkdir ~/.vnc
|
||||
# Setup a password
|
||||
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
|
||||
# Autostart firefox (might not be the best way, but it does the trick)
|
||||
RUN bash -c 'echo "firefox" >> /.bashrc'
|
||||
|
||||
EXPOSE 5900
|
||||
CMD ["x11vnc", "-forever", "-usepw", "-create"]
|
||||
```
|
||||
|
||||
```dockerfile
|
||||
# Multiple images example
|
||||
#
|
||||
# VERSION 0.1
|
||||
|
||||
FROM ubuntu
|
||||
RUN echo foo > bar
|
||||
# Will output something like ===> 907ad6c2736f
|
||||
|
||||
FROM ubuntu
|
||||
RUN echo moo > oink
|
||||
# Will output something like ===> 695d7793cbe4
|
||||
|
||||
# You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
|
||||
# /oink.
|
||||
```
|
||||
- The ["build images" section](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
|
||||
- The ["get started](https://docs.docker.com/get-started/)
|
||||
- The [language-specific getting started guides](https://docs.docker.com/language/)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "Use the Docker command line"
|
||||
description: "Docker's CLI command description and usage"
|
||||
keywords: "Docker, Docker documentation, CLI, command line"
|
||||
keywords: "Docker, Docker documentation, CLI, command line, config.json, CLI configuration file"
|
||||
redirect_from:
|
||||
- /go/experimental/
|
||||
- /engine/reference/commandline/engine/
|
||||
@ -62,30 +62,22 @@ the [installation](https://docs.docker.com/install/) instructions for your opera
|
||||
|
||||
## Environment variables
|
||||
|
||||
For easy reference, the following list of environment variables are supported
|
||||
by the `docker` command line:
|
||||
The following list of environment variables are supported by the `docker` command
|
||||
line:
|
||||
|
||||
* `DOCKER_API_VERSION` The API version to use (e.g. `1.19`)
|
||||
* `DOCKER_CONFIG` The location of your client configuration files.
|
||||
* `DOCKER_HOST` Daemon socket to connect to.
|
||||
* `DOCKER_STACK_ORCHESTRATOR` Configure the default orchestrator to use when using `docker stack` management commands.
|
||||
* `DOCKER_CONTENT_TRUST` When set Docker uses notary to sign and verify images.
|
||||
Equates to `--disable-content-trust=false` for build, create, pull, push, run.
|
||||
* `DOCKER_CONTENT_TRUST_SERVER` The URL of the Notary server to use. This defaults
|
||||
to the same URL as the registry.
|
||||
* `DOCKER_HIDE_LEGACY_COMMANDS` When set, Docker hides "legacy" top-level commands (such as `docker rm`, and
|
||||
`docker pull`) in `docker help` output, and only `Management commands` per object-type (e.g., `docker container`) are
|
||||
printed. This may become the default in a future release, at which point this environment-variable is removed.
|
||||
* `DOCKER_CONTEXT` Specify the context to use (overrides DOCKER_HOST env var and default context set with "docker context use")
|
||||
* `DOCKER_DEFAULT_PLATFORM` Specify the default platform for the commands that take the `--platform` flag.
|
||||
|
||||
#### Shared Environment variables
|
||||
|
||||
These environment variables can be used both with the `docker` command line and
|
||||
`dockerd` command line:
|
||||
|
||||
* `DOCKER_CERT_PATH` The location of your authentication keys.
|
||||
* `DOCKER_TLS_VERIFY` When set Docker uses TLS and verifies the remote.
|
||||
| Variable | Description |
|
||||
|:------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `DOCKER_API_VERSION` | Override the negotiated API version to use for debugging (e.g. `1.19`) |
|
||||
| `DOCKER_CERT_PATH` | Location of your authentication keys. This variable is used both by the `docker` CLI and the [`dockerd` daemon](dockerd.md) |
|
||||
| `DOCKER_CONFIG` | The location of your client configuration files. |
|
||||
| `DOCKER_CONTENT_TRUST_SERVER` | The URL of the Notary server to use. Defaults to the same URL as the registry. |
|
||||
| `DOCKER_CONTENT_TRUST` | When set Docker uses notary to sign and verify images. Equates to `--disable-content-trust=false` for build, create, pull, push, run. |
|
||||
| `DOCKER_CONTEXT` | Name of the `docker context` to use (overrides `DOCKER_HOST` env var and default context set with `docker context use`) |
|
||||
| `DOCKER_DEFAULT_PLATFORM` | Default platform for commands that take the `--platform` flag. |
|
||||
| `DOCKER_HIDE_LEGACY_COMMANDS` | When set, Docker hides "legacy" top-level commands (such as `docker rm`, and `docker pull`) in `docker help` output, and only `Management commands` per object-type (e.g., `docker container`) are printed. This may become the default in a future release, at which point this environment-variable is removed. |
|
||||
| `DOCKER_HOST` | Daemon socket to connect to. |
|
||||
| `DOCKER_STACK_ORCHESTRATOR` | Configure the default orchestrator to use when using `docker stack` management commands. |
|
||||
| `DOCKER_TLS_VERIFY` | When set Docker uses TLS and verifies the remote. This variable is used both by the `docker` CLI and the [`dockerd` daemon](dockerd.md) |
|
||||
|
||||
Because Docker is developed using Go, you can also use any environment
|
||||
variables used by the Go runtime. In particular, you may find these useful:
|
||||
@ -98,7 +90,7 @@ These Go environment variables are case-insensitive. See the
|
||||
[Go specification](http://golang.org/pkg/net/http/) for details on these
|
||||
variables.
|
||||
|
||||
### Configuration files
|
||||
## Configuration files
|
||||
|
||||
By default, the Docker command line stores its configuration files in a
|
||||
directory called `.docker` within your `$HOME` directory.
|
||||
@ -124,7 +116,7 @@ specified, then the `--config` option overrides the `DOCKER_CONFIG` environment
|
||||
variable. The example below overrides the `docker ps` command using a
|
||||
`config.json` file located in the `~/testconfigs/` directory.
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker --config ~/testconfigs/ ps
|
||||
```
|
||||
|
||||
@ -133,79 +125,56 @@ configuration, you can set the `DOCKER_CONFIG` environment variable in your
|
||||
shell (e.g. `~/.profile` or `~/.bashrc`). The example below sets the new
|
||||
directory to be `HOME/newdir/.docker`.
|
||||
|
||||
```bash
|
||||
echo export DOCKER_CONFIG=$HOME/newdir/.docker > ~/.profile
|
||||
```console
|
||||
$ echo export DOCKER_CONFIG=$HOME/newdir/.docker > ~/.profile
|
||||
```
|
||||
|
||||
### `config.json` properties
|
||||
## Docker CLI configuration file (`config.json`) properties
|
||||
|
||||
The `config.json` file stores a JSON encoding of several properties:
|
||||
<a name="configjson-properties"><!-- included for deep-links to old section --></a>
|
||||
|
||||
Use the Docker CLI configuration to customize settings for the `docker` CLI. The
|
||||
configuration file uses JSON formatting, and properties:
|
||||
|
||||
By default, configuration file is stored in `~/.docker/config.json`. Refer to the
|
||||
[change the `.docker` directory](#change-the-docker-directory) section to use a
|
||||
different location.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> The configuration file and other files inside the `~/.docker` configuration
|
||||
> directory may contain sensitive information, such as authentication information
|
||||
> for proxies or, depending on your credential store, credentials for your image
|
||||
> registries. Review your configuration file's content before sharing with others,
|
||||
> and prevent committing the file to version control.
|
||||
|
||||
### Customize the default output format for commands
|
||||
|
||||
These fields allow you to customize the default output format for some commands
|
||||
if no `--format` flag is provided.
|
||||
|
||||
| Property | Description |
|
||||
|:-----------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `configFormat` | Custom default format for `docker config ls` output. Refer to the [**format the output** section in the `docker config ls` documentation](config_ls.md#format-the-output) for a list of supported formatting directives. |
|
||||
| `imagesFormat` | Custom default format for `docker images` / `docker image ls` output. Refer to the [**format the output** section in the `docker images` documentation](images.md#format-the-output) for a list of supported formatting directives. |
|
||||
| `nodesFormat` | Custom default format for `docker node ls` output. Refer to the [**formatting** section in the `docker node ls` documentation](node_ls.md#formatting) for a list of supported formatting directives. |
|
||||
| `pluginsFormat` | Custom default format for `docker plugin ls` output. Refer to the [**formatting** section in the `docker plugin ls` documentation](plugin_ls.md#formatting) for a list of supported formatting directives. |
|
||||
| `psFormat` | Custom default format for `docker ps` / `docker container ps` output. Refer to the [**formatting** section in the `docker ps` documentation](ps.md#formatting) for a list of supported formatting directives. |
|
||||
| `secretFormat` | Custom default format for `docker secret ls` output. Refer to the [**format the output** section in the `docker secret ls` documentation](secret_ls.md#format-the-output) for a list of supported formatting directives. |
|
||||
| `serviceInspectFormat` | Custom default format for `docker service inspect` output. Refer to the [**formatting** section in the `docker service inspect` documentation](service_inspect.md#formatting) for a list of supported formatting directives. |
|
||||
| `servicesFormat` | Custom default format for `docker service ls` output. Refer to the [**formatting** section in the `docker service ls` documentation](service_ls.md#formatting) for a list of supported formatting directives. |
|
||||
| `statsFormat` | Custom default format for `docker stats` output. Refer to the [**formatting** section in the `docker stats` documentation](stats.md#formatting) for a list of supported formatting directives. |
|
||||
|
||||
|
||||
### Custom HTTP headers
|
||||
|
||||
The property `HttpHeaders` specifies a set of headers to include in all messages
|
||||
sent from the Docker client to the daemon. Docker does not try to interpret or
|
||||
understand these header; it simply puts them into the messages. Docker does
|
||||
understand these headers; it simply puts them into the messages. Docker does
|
||||
not allow these headers to change any headers it sets for itself.
|
||||
|
||||
The property `psFormat` specifies the default format for `docker ps` output.
|
||||
When the `--format` flag is not provided with the `docker ps` command,
|
||||
Docker's client uses this property. If this property is not set, the client
|
||||
falls back to the default table format. For a list of supported formatting
|
||||
directives, see the
|
||||
[**Formatting** section in the `docker ps` documentation](ps.md)
|
||||
|
||||
The property `imagesFormat` specifies the default format for `docker images` output.
|
||||
When the `--format` flag is not provided with the `docker images` command,
|
||||
Docker's client uses this property. If this property is not set, the client
|
||||
falls back to the default table format. For a list of supported formatting
|
||||
directives, see the [**Formatting** section in the `docker images` documentation](images.md)
|
||||
|
||||
The property `pluginsFormat` specifies the default format for `docker plugin ls` output.
|
||||
When the `--format` flag is not provided with the `docker plugin ls` command,
|
||||
Docker's client uses this property. If this property is not set, the client
|
||||
falls back to the default table format. For a list of supported formatting
|
||||
directives, see the [**Formatting** section in the `docker plugin ls` documentation](plugin_ls.md)
|
||||
|
||||
The property `servicesFormat` specifies the default format for `docker
|
||||
service ls` output. When the `--format` flag is not provided with the
|
||||
`docker service ls` command, Docker's client uses this property. If this
|
||||
property is not set, the client falls back to the default json format. For a
|
||||
list of supported formatting directives, see the
|
||||
[**Formatting** section in the `docker service ls` documentation](service_ls.md)
|
||||
|
||||
The property `serviceInspectFormat` specifies the default format for `docker
|
||||
service inspect` output. When the `--format` flag is not provided with the
|
||||
`docker service inspect` command, Docker's client uses this property. If this
|
||||
property is not set, the client falls back to the default json format. For a
|
||||
list of supported formatting directives, see the
|
||||
[**Formatting** section in the `docker service inspect` documentation](service_inspect.md)
|
||||
|
||||
The property `statsFormat` specifies the default format for `docker
|
||||
stats` output. When the `--format` flag is not provided with the
|
||||
`docker stats` command, Docker's client uses this property. If this
|
||||
property is not set, the client falls back to the default table
|
||||
format. For a list of supported formatting directives, see
|
||||
[**Formatting** section in the `docker stats` documentation](stats.md)
|
||||
|
||||
The property `secretFormat` specifies the default format for `docker
|
||||
secret ls` output. When the `--format` flag is not provided with the
|
||||
`docker secret ls` command, Docker's client uses this property. If this
|
||||
property is not set, the client falls back to the default table
|
||||
format. For a list of supported formatting directives, see
|
||||
[**Formatting** section in the `docker secret ls` documentation](secret_ls.md)
|
||||
|
||||
|
||||
The property `nodesFormat` specifies the default format for `docker node ls` output.
|
||||
When the `--format` flag is not provided with the `docker node ls` command,
|
||||
Docker's client uses the value of `nodesFormat`. If the value of `nodesFormat` is not set,
|
||||
the client uses the default table format. For a list of supported formatting
|
||||
directives, see the [**Formatting** section in the `docker node ls` documentation](node_ls.md)
|
||||
|
||||
The property `configFormat` specifies the default format for `docker
|
||||
config ls` output. When the `--format` flag is not provided with the
|
||||
`docker config ls` command, Docker's client uses this property. If this
|
||||
property is not set, the client falls back to the default table
|
||||
format. For a list of supported formatting directives, see
|
||||
[**Formatting** section in the `docker config ls` documentation](config_ls.md)
|
||||
### Credential store options
|
||||
|
||||
The property `credsStore` specifies an external binary to serve as the default
|
||||
credential store. When this property is set, `docker login` will attempt to
|
||||
@ -221,11 +190,17 @@ credentials for specific registries. If this property is set, the binary
|
||||
for a specific registry. For more information, see the
|
||||
[**Credential helpers** section in the `docker login` documentation](login.md#credential-helpers)
|
||||
|
||||
|
||||
### Orchestrator options for docker stacks
|
||||
|
||||
The property `stackOrchestrator` specifies the default orchestrator to use when
|
||||
running `docker stack` management commands. Valid values are `"swarm"`,
|
||||
`"kubernetes"`, and `"all"`. This property can be overridden with the
|
||||
`DOCKER_STACK_ORCHESTRATOR` environment variable, or the `--orchestrator` flag.
|
||||
|
||||
|
||||
### Automatic proxy configuration for containers
|
||||
|
||||
The property `proxies` specifies proxy environment variables to be automatically
|
||||
set on containers, and set as `--build-arg` on containers used during `docker build`.
|
||||
A `"default"` set of proxies can be configured, and will be used for any docker
|
||||
@ -233,15 +208,26 @@ daemon that the client connects to, or a configuration per host (docker daemon),
|
||||
for example, "https://docker-daemon1.example.com". The following properties can
|
||||
be set for each environment:
|
||||
|
||||
* `httpProxy` (sets the value of `HTTP_PROXY` and `http_proxy`)
|
||||
* `httpsProxy` (sets the value of `HTTPS_PROXY` and `https_proxy`)
|
||||
* `ftpProxy` (sets the value of `FTP_PROXY` and `ftp_proxy`)
|
||||
* `noProxy` (sets the value of `NO_PROXY` and `no_proxy`)
|
||||
| Property | Description |
|
||||
|:---------------|:--------------------------------------------------------------------------------------------------------|
|
||||
| `httpProxy` | Default value of `HTTP_PROXY` and `http_proxy` for containers, and as `--build-arg` on `docker build` |
|
||||
| `httpsProxy` | Default value of `HTTPS_PROXY` and `https_proxy` for containers, and as `--build-arg` on `docker build` |
|
||||
| `ftpProxy` | Default value of `FTP_PROXY` and `ftp_proxy` for containers, and as `--build-arg` on `docker build` |
|
||||
| `noProxy` | Default value of `NO_PROXY` and `no_proxy` for containers, and as `--build-arg` on `docker build` |
|
||||
|
||||
> **Warning**: Proxy settings may contain sensitive information (for example,
|
||||
> if the proxy requires authentication). Environment variables are stored as
|
||||
> plain text in the container's configuration, and as such can be inspected
|
||||
> through the remote API or committed to an image when using `docker commit`.
|
||||
These settings are used to configure proxy settings for containers only, and not
|
||||
used as proxy settings for the `docker` CLI or the `dockerd` daemon. Refer to the
|
||||
[environment variables](#environment-variables) and [HTTP/HTTPS proxy](https://docs.docker.com/config/daemon/systemd/#httphttps-proxy)
|
||||
sections for configuring proxy settings for the cli and daemon.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> Proxy settings may contain sensitive information (for example, if the proxy
|
||||
> requires authentication). Environment variables are stored as plain text in
|
||||
> the container's configuration, and as such can be inspected through the remote
|
||||
> API or committed to an image when using `docker commit`.
|
||||
|
||||
### Default key-sequence to detach from containers
|
||||
|
||||
Once attached to a container, users detach from it and leave it running using
|
||||
the using `CTRL-p CTRL-q` key sequence. This detach key sequence is customizable
|
||||
@ -261,11 +247,17 @@ Users can override your custom or the default key sequence on a per-container
|
||||
basis. To do this, the user specifies the `--detach-keys` flag with the `docker
|
||||
attach`, `docker exec`, `docker run` or `docker start` command.
|
||||
|
||||
### CLI Plugin options
|
||||
|
||||
The property `plugins` contains settings specific to CLI plugins. The
|
||||
key is the plugin name, while the value is a further map of options,
|
||||
which are specific to that plugin.
|
||||
|
||||
Following is a sample `config.json` file:
|
||||
|
||||
### Sample configuration file
|
||||
|
||||
Following is a sample `config.json` file to illustrate the format used for
|
||||
various fields:
|
||||
|
||||
```json
|
||||
{% raw %}
|
||||
@ -301,14 +293,14 @@ Following is a sample `config.json` file:
|
||||
"proxies": {
|
||||
"default": {
|
||||
"httpProxy": "http://user:pass@example.com:3128",
|
||||
"httpsProxy": "http://user:pass@example.com:3128",
|
||||
"noProxy": "http://user:pass@example.com:3128",
|
||||
"httpsProxy": "https://my-proxy.example.com:3129",
|
||||
"noProxy": "intra.mycorp.example.com",
|
||||
"ftpProxy": "http://user:pass@example.com:3128"
|
||||
},
|
||||
"https://manager1.mycorp.example.com:2377": {
|
||||
"httpProxy": "http://user:pass@example.com:3128",
|
||||
"httpsProxy": "http://user:pass@example.com:3128"
|
||||
},
|
||||
"httpsProxy": "https://my-proxy.example.com:3129"
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endraw %}
|
||||
@ -336,16 +328,18 @@ list of root Certificate Authorities.
|
||||
To list the help on any command just execute the command, followed by the
|
||||
`--help` option.
|
||||
|
||||
$ docker run --help
|
||||
```console
|
||||
$ docker run --help
|
||||
|
||||
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
|
||||
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
|
||||
|
||||
Run a command in a new container
|
||||
Run a command in a new container
|
||||
|
||||
Options:
|
||||
--add-host value Add a custom host-to-IP mapping (host:ip) (default [])
|
||||
-a, --attach value Attach to STDIN, STDOUT or STDERR (default [])
|
||||
...
|
||||
Options:
|
||||
--add-host value Add a custom host-to-IP mapping (host:ip) (default [])
|
||||
-a, --attach value Attach to STDIN, STDOUT or STDERR (default [])
|
||||
<...>
|
||||
```
|
||||
|
||||
### Option types
|
||||
|
||||
@ -366,7 +360,7 @@ container **will** run in "detached" mode, in the background.
|
||||
Options which default to `true` (e.g., `docker build --rm=true`) can only be
|
||||
set to the non-default value by explicitly setting them to `false`:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker build --rm=false .
|
||||
```
|
||||
|
||||
@ -375,7 +369,7 @@ $ docker build --rm=false .
|
||||
You can specify options like `-a=[]` multiple times in a single command line,
|
||||
for example in these commands:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker run -a stdin -a stdout -i -t ubuntu /bin/bash
|
||||
|
||||
$ docker run -a stdin -a stdout -a stderr ubuntu /bin/ls
|
||||
@ -384,7 +378,7 @@ $ docker run -a stdin -a stdout -a stderr ubuntu /bin/ls
|
||||
Sometimes, multiple options can call for a more complex value string as for
|
||||
`-v`:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ docker run -v /host:/container example/mysql
|
||||
```
|
||||
|
||||
|
||||
35
docs/reference/commandline/config.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "config"
|
||||
description: "The config command description and usage"
|
||||
keywords: "config"
|
||||
---
|
||||
|
||||
# config
|
||||
|
||||
```markdown
|
||||
Usage: docker config COMMAND
|
||||
|
||||
Manage Docker configs
|
||||
|
||||
Options:
|
||||
--help Print usage
|
||||
|
||||
Commands:
|
||||
create Create a config from a file or STDIN
|
||||
inspect Display detailed information on one or more configs
|
||||
ls List configs
|
||||
rm Remove one or more configs
|
||||
|
||||
Run 'docker config COMMAND --help' for more information on a command.
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
Manage configs.
|
||||
|
||||
## Related commands
|
||||
|
||||
* [config create](config_create.md)
|
||||
* [config inspect](config_inspect.md)
|
||||
* [config list](config_ls.md)
|
||||
* [config rm](config_rm.md)
|
||||
99
docs/reference/commandline/config_create.md
Normal file
@ -0,0 +1,99 @@
|
||||
---
|
||||
title: "config create"
|
||||
description: "The config create command description and usage"
|
||||
keywords: ["config, create"]
|
||||
---
|
||||
|
||||
# config create
|
||||
|
||||
```Markdown
|
||||
Usage: docker config create [OPTIONS] CONFIG [file|-]
|
||||
|
||||
Create a config from a file or STDIN as content
|
||||
|
||||
Options:
|
||||
-l, --label list Config labels
|
||||
--template-driver string Template driver
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
Creates a config using standard input or from a file for the config content.
|
||||
|
||||
For detailed information about using configs, refer to [store configuration data using Docker Configs](https://docs.docker.com/engine/swarm/configs/).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> This is a cluster management command, and must be executed on a swarm
|
||||
> manager node. To learn about managers and workers, refer to the
|
||||
> [Swarm mode section](https://docs.docker.com/engine/swarm/) in the
|
||||
> documentation.
|
||||
|
||||
## Examples
|
||||
|
||||
### Create a config
|
||||
|
||||
```bash
|
||||
$ printf <config> | docker config create my_config -
|
||||
|
||||
onakdyv307se2tl7nl20anokv
|
||||
|
||||
$ docker config ls
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
onakdyv307se2tl7nl20anokv my_config 6 seconds ago 6 seconds ago
|
||||
```
|
||||
|
||||
### Create a config with a file
|
||||
|
||||
```bash
|
||||
$ docker config create my_config ./config.json
|
||||
|
||||
dg426haahpi5ezmkkj5kyl3sn
|
||||
|
||||
$ docker config ls
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
dg426haahpi5ezmkkj5kyl3sn my_config 7 seconds ago 7 seconds ago
|
||||
```
|
||||
|
||||
### Create a config with labels
|
||||
|
||||
```bash
|
||||
$ docker config create \
|
||||
--label env=dev \
|
||||
--label rev=20170324 \
|
||||
my_config ./config.json
|
||||
|
||||
eo7jnzguqgtpdah3cm5srfb97
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker config inspect my_config
|
||||
|
||||
[
|
||||
{
|
||||
"ID": "eo7jnzguqgtpdah3cm5srfb97",
|
||||
"Version": {
|
||||
"Index": 17
|
||||
},
|
||||
"CreatedAt": "2017-03-24T08:15:09.735271783Z",
|
||||
"UpdatedAt": "2017-03-24T08:15:09.735271783Z",
|
||||
"Spec": {
|
||||
"Name": "my_config",
|
||||
"Labels": {
|
||||
"env": "dev",
|
||||
"rev": "20170324"
|
||||
},
|
||||
"Data": "aGVsbG8K"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
## Related commands
|
||||
|
||||
* [config inspect](config_inspect.md)
|
||||
* [config ls](config_ls.md)
|
||||
* [config rm](config_rm.md)
|
||||
97
docs/reference/commandline/config_inspect.md
Normal file
@ -0,0 +1,97 @@
|
||||
---
|
||||
title: "config inspect"
|
||||
description: "The config inspect command description and usage"
|
||||
keywords: ["config, inspect"]
|
||||
---
|
||||
|
||||
# config inspect
|
||||
|
||||
```Markdown
|
||||
Usage: docker config inspect [OPTIONS] CONFIG [CONFIG...]
|
||||
|
||||
Display detailed information on one or more configs
|
||||
|
||||
Options:
|
||||
-f, --format string Format the output using the given Go template
|
||||
--help Print usage
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
Inspects the specified config.
|
||||
|
||||
By default, this renders all results in a JSON array. If a format is specified,
|
||||
the given template will be executed for each result.
|
||||
|
||||
Go's [text/template](http://golang.org/pkg/text/template/) package
|
||||
describes all the details of the format.
|
||||
|
||||
For detailed information about using configs, refer to [store configuration data using Docker Configs](https://docs.docker.com/engine/swarm/configs/).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> This is a cluster management command, and must be executed on a swarm
|
||||
> manager node. To learn about managers and workers, refer to the
|
||||
> [Swarm mode section](https://docs.docker.com/engine/swarm/) in the
|
||||
> documentation.
|
||||
|
||||
## Examples
|
||||
|
||||
### Inspect a config by name or ID
|
||||
|
||||
You can inspect a config, either by its *name*, or *ID*
|
||||
|
||||
For example, given the following config:
|
||||
|
||||
```bash
|
||||
$ docker config ls
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
eo7jnzguqgtpdah3cm5srfb97 my_config 3 minutes ago 3 minutes ago
|
||||
```
|
||||
|
||||
```bash
|
||||
$ docker config inspect config.json
|
||||
```
|
||||
|
||||
The output is in JSON format, for example:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ID": "eo7jnzguqgtpdah3cm5srfb97",
|
||||
"Version": {
|
||||
"Index": 17
|
||||
},
|
||||
"CreatedAt": "2017-03-24T08:15:09.735271783Z",
|
||||
"UpdatedAt": "2017-03-24T08:15:09.735271783Z",
|
||||
"Spec": {
|
||||
"Name": "my_config",
|
||||
"Labels": {
|
||||
"env": "dev",
|
||||
"rev": "20170324"
|
||||
},
|
||||
"Data": "aGVsbG8K"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Formatting
|
||||
|
||||
You can use the --format option to obtain specific information about a
|
||||
config. The following example command outputs the creation time of the
|
||||
config.
|
||||
|
||||
```bash
|
||||
$ docker config inspect --format='{{.CreatedAt}}' eo7jnzguqgtpdah3cm5srfb97
|
||||
|
||||
2017-03-24 08:15:09.735271783 +0000 UTC
|
||||
```
|
||||
|
||||
|
||||
## Related commands
|
||||
|
||||
* [config create](config_create.md)
|
||||
* [config ls](config_ls.md)
|
||||
* [config rm](config_rm.md)
|
||||
155
docs/reference/commandline/config_ls.md
Normal file
@ -0,0 +1,155 @@
|
||||
---
|
||||
title: "config ls"
|
||||
description: "The config ls command description and usage"
|
||||
keywords: ["config, ls"]
|
||||
---
|
||||
|
||||
# config ls
|
||||
|
||||
```Markdown
|
||||
Usage: docker config ls [OPTIONS]
|
||||
|
||||
List configs
|
||||
|
||||
Aliases:
|
||||
ls, list
|
||||
|
||||
Options:
|
||||
-f, --filter filter Filter output based on conditions provided
|
||||
--format string Pretty-print configs using a Go template
|
||||
--help Print usage
|
||||
-q, --quiet Only display IDs
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
Run this command on a manager node to list the configs in the swarm.
|
||||
|
||||
For detailed information about using configs, refer to [store configuration data using Docker Configs](https://docs.docker.com/engine/swarm/configs/).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> This is a cluster management command, and must be executed on a swarm
|
||||
> manager node. To learn about managers and workers, refer to the
|
||||
> [Swarm mode section](https://docs.docker.com/engine/swarm/) in the
|
||||
> documentation.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
$ docker config ls
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
6697bflskwj1998km1gnnjr38 q5s5570vtvnimefos1fyeo2u2 6 weeks ago 6 weeks ago
|
||||
9u9hk4br2ej0wgngkga6rp4hq my_config 5 weeks ago 5 weeks ago
|
||||
mem02h8n73mybpgqjf0kfi1n0 test_config 3 seconds ago 3 seconds ago
|
||||
```
|
||||
|
||||
### Filtering
|
||||
|
||||
The filtering flag (`-f` or `--filter`) format is a `key=value` pair. If there is more
|
||||
than one filter, then pass multiple flags (e.g., `--filter "foo=bar" --filter "bif=baz"`)
|
||||
|
||||
The currently supported filters are:
|
||||
|
||||
- [id](#id) (config's ID)
|
||||
- [label](#label) (`label=<key>` or `label=<key>=<value>`)
|
||||
- [name](#name) (config's name)
|
||||
|
||||
#### id
|
||||
|
||||
The `id` filter matches all or prefix of a config's id.
|
||||
|
||||
```bash
|
||||
$ docker config ls -f "id=6697bflskwj1998km1gnnjr38"
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
6697bflskwj1998km1gnnjr38 q5s5570vtvnimefos1fyeo2u2 6 weeks ago 6 weeks ago
|
||||
```
|
||||
|
||||
#### label
|
||||
|
||||
The `label` filter matches configs based on the presence of a `label` alone or
|
||||
a `label` and a value.
|
||||
|
||||
The following filter matches all configs with a `project` label regardless of
|
||||
its value:
|
||||
|
||||
```bash
|
||||
$ docker config ls --filter label=project
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
mem02h8n73mybpgqjf0kfi1n0 test_config About an hour ago About an hour ago
|
||||
```
|
||||
|
||||
The following filter matches only services with the `project` label with the
|
||||
`project-a` value.
|
||||
|
||||
```bash
|
||||
$ docker service ls --filter label=project=test
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
mem02h8n73mybpgqjf0kfi1n0 test_config About an hour ago About an hour ago
|
||||
```
|
||||
|
||||
#### name
|
||||
|
||||
The `name` filter matches on all or prefix of a config's name.
|
||||
|
||||
The following filter matches config with a name containing a prefix of `test`.
|
||||
|
||||
```bash
|
||||
$ docker config ls --filter name=test_config
|
||||
|
||||
ID NAME CREATED UPDATED
|
||||
mem02h8n73mybpgqjf0kfi1n0 test_config About an hour ago About an hour ago
|
||||
```
|
||||
|
||||
### Format the output
|
||||
|
||||
The formatting option (`--format`) pretty prints configs output
|
||||
using a Go template.
|
||||
|
||||
Valid placeholders for the Go template are listed below:
|
||||
|
||||
| Placeholder | Description |
|
||||
| ------------ | ------------------------------------------------------------------------------------ |
|
||||
| `.ID` | Config ID |
|
||||
| `.Name` | Config name |
|
||||
| `.CreatedAt` | Time when the config was created |
|
||||
| `.UpdatedAt` | Time when the config was updated |
|
||||
| `.Labels` | All labels assigned to the config |
|
||||
| `.Label` | Value of a specific label for this config. For example `{{.Label "my-label"}}` |
|
||||
|
||||
When using the `--format` option, the `config ls` command will either
|
||||
output the data exactly as the template declares or, when using the
|
||||
`table` directive, will include column headers as well.
|
||||
|
||||
The following example uses a template without headers and outputs the
|
||||
`ID` and `Name` entries separated by a colon (`:`) for all images:
|
||||
|
||||
```bash
|
||||
$ docker config ls --format "{{.ID}}: {{.Name}}"
|
||||
|
||||
77af4d6b9913: config-1
|
||||
b6fa739cedf5: config-2
|
||||
78a85c484f71: config-3
|
||||
```
|
||||
|
||||
To list all configs with their name and created date in a table format you
|
||||
can use:
|
||||
|
||||
```bash
|
||||
$ docker config ls --format "table {{.ID}}\t{{.Name}}\t{{.CreatedAt}}"
|
||||
|
||||
ID NAME CREATED
|
||||
77af4d6b9913 config-1 5 minutes ago
|
||||
b6fa739cedf5 config-2 3 hours ago
|
||||
78a85c484f71 config-3 10 days ago
|
||||
```
|
||||
|
||||
## Related commands
|
||||
|
||||
* [config create](config_create.md)
|
||||
* [config inspect](config_inspect.md)
|
||||
* [config rm](config_rm.md)
|
||||
53
docs/reference/commandline/config_rm.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "config rm"
|
||||
description: "The config rm command description and usage"
|
||||
keywords: ["config, rm"]
|
||||
---
|
||||
|
||||
# config rm
|
||||
|
||||
```Markdown
|
||||
Usage: docker config rm CONFIG [CONFIG...]
|
||||
|
||||
Remove one or more configs
|
||||
|
||||
Aliases:
|
||||
rm, remove
|
||||
|
||||
Options:
|
||||
--help Print usage
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
Removes the specified configs from the swarm.
|
||||
|
||||
For detailed information about using configs, refer to [store configuration data using Docker Configs](https://docs.docker.com/engine/swarm/configs/).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> This is a cluster management command, and must be executed on a swarm
|
||||
> manager node. To learn about managers and workers, refer to the
|
||||
> [Swarm mode section](https://docs.docker.com/engine/swarm/) in the
|
||||
> documentation.
|
||||
|
||||
## Examples
|
||||
|
||||
This example removes a config:
|
||||
|
||||
```bash
|
||||
$ docker config rm my_config
|
||||
sapth4csdo5b6wz2p5uimh5xg
|
||||
```
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> Unlike `docker rm`, this command does not ask for confirmation before removing
|
||||
> a config.
|
||||
|
||||
|
||||
## Related commands
|
||||
|
||||
* [config create](config_create.md)
|
||||
* [config inspect](config_inspect.md)
|
||||
* [config ls](config_ls.md)
|
||||
@ -1203,8 +1203,8 @@ command line or Docker's Engine API are allowed or denied by the plugin.
|
||||
If you have multiple plugins installed, each plugin, in order, must
|
||||
allow the request for it to complete.
|
||||
|
||||
For information about how to create an authorization plugin, see [authorization
|
||||
plugin](../../extend/plugins_authorization.md) section in the Docker extend section of this documentation.
|
||||
For information about how to create an authorization plugin, refer to the
|
||||
[authorization plugin](../../extend/plugins_authorization.md) section.
|
||||
|
||||
|
||||
### Daemon user namespace options
|
||||
@ -1232,10 +1232,16 @@ Docker supports softlinks for the Docker data directory (`/var/lib/docker`) and
|
||||
for `/var/lib/docker/tmp`. The `DOCKER_TMPDIR` and the data directory can be
|
||||
set like this:
|
||||
|
||||
DOCKER_TMPDIR=/mnt/disk2/tmp /usr/local/bin/dockerd -D -g /var/lib/docker -H unix:// > /var/lib/docker-machine/docker.log 2>&1
|
||||
# or
|
||||
export DOCKER_TMPDIR=/mnt/disk2/tmp
|
||||
/usr/local/bin/dockerd -D -g /var/lib/docker -H unix:// > /var/lib/docker-machine/docker.log 2>&1
|
||||
```console
|
||||
$ DOCKER_TMPDIR=/mnt/disk2/tmp /usr/local/bin/dockerd -D -g /var/lib/docker -H unix:// > /var/lib/docker-machine/docker.log 2>&1
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```console
|
||||
$ export DOCKER_TMPDIR=/mnt/disk2/tmp
|
||||
$ /usr/local/bin/dockerd -D -g /var/lib/docker -H unix:// > /var/lib/docker-machine/docker.log 2>&1
|
||||
````
|
||||
|
||||
#### Default cgroup parent
|
||||
|
||||
@ -1400,6 +1406,10 @@ This is a full example of the allowed configuration options on Linux:
|
||||
"log-driver": "json-file",
|
||||
"log-level": "",
|
||||
"log-opts": {
|
||||
"cache-disabled": "false",
|
||||
"cache-max-file": "5",
|
||||
"cache-max-size": "20m",
|
||||
"cache-compress": "true",
|
||||
"env": "os,customer",
|
||||
"labels": "somelabel",
|
||||
"max-file": "5",
|
||||
@ -1560,7 +1570,9 @@ previously configured cluster configurations.
|
||||
|
||||
### Run multiple daemons
|
||||
|
||||
> **Note:** Running multiple daemons on a single host is considered as "experimental". The user should be aware of
|
||||
> **Note:**
|
||||
>
|
||||
> Running multiple daemons on a single host is considered as "experimental". The user should be aware of
|
||||
> unsolved problems. This solution may not work properly in some cases. Solutions are currently under development
|
||||
> and will be delivered in the near future.
|
||||
|
||||
@ -1612,7 +1624,7 @@ The `--tls*` options enable use of specific certificates for individual daemons.
|
||||
|
||||
Example script for a separate “bootstrap” instance of the Docker daemon without network:
|
||||
|
||||
```bash
|
||||
```console
|
||||
$ sudo dockerd \
|
||||
-H unix:///var/run/docker-bootstrap.sock \
|
||||
-p /var/run/docker-bootstrap.pid \
|
||||
|
||||
@ -175,7 +175,7 @@ equivalent docker daemon flags used for docker0 bridge:
|
||||
| `com.docker.network.bridge.enable_icc` | `--icc` | Enable or Disable Inter Container Connectivity |
|
||||
| `com.docker.network.bridge.host_binding_ipv4` | `--ip` | Default IP when binding container ports |
|
||||
| `com.docker.network.driver.mtu` | `--mtu` | Set the containers network MTU |
|
||||
| `com.docker.network.container_interface_prefix` | - | Set a custom prefix for container interfaces |
|
||||
| `com.docker.network.container_iface_prefix` | - | Set a custom prefix for container interfaces |
|
||||
|
||||
The following arguments can be passed to `docker network create` for any
|
||||
network driver, again with their approximate equivalents to `docker daemon`.
|
||||
|
||||
@ -60,6 +60,7 @@ The currently supported filters are:
|
||||
|
||||
* [id](#id)
|
||||
* [label](#label)
|
||||
* [node.label](#nodelabel)
|
||||
* [membership](#membership)
|
||||
* [name](#name)
|
||||
* [role](#role)
|
||||
@ -77,7 +78,10 @@ ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
|
||||
|
||||
#### label
|
||||
|
||||
The `label` filter matches nodes based on engine labels and on the presence of a `label` alone or a `label` and a value. Node labels are currently not used for filtering.
|
||||
The `label` filter matches nodes based on engine labels and on the presence of a
|
||||
`label` alone or a `label` and a value. Engine labels are configured in
|
||||
the [daemon configuration](dockerd.md#daemon-configuration-file). To filter on
|
||||
Swarm `node` labels, use [`node.label` instead](#nodelabel).
|
||||
|
||||
The following filter matches nodes with the `foo` label regardless of its value.
|
||||
|
||||
@ -88,6 +92,42 @@ ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
|
||||
1bcef6utixb0l0ca7gxuivsj0 swarm-worker2 Ready Active
|
||||
```
|
||||
|
||||
#### node.label
|
||||
|
||||
The `node.label` filter matches nodes based on node labels and on the presence
|
||||
of a `node.label` alone or a `node.label` and a value.
|
||||
|
||||
The following filter updates nodes to have a `region` node label:
|
||||
|
||||
```console
|
||||
$ docker node update --label-add region=region-a swarm-test-01
|
||||
$ docker node update --label-add region=region-a swarm-test-02
|
||||
$ docker node update --label-add region=region-b swarm-test-03
|
||||
$ docker node update --label-add region=region-b swarm-test-04
|
||||
```
|
||||
|
||||
Show all nodes that have a `region` node label set:
|
||||
|
||||
```console
|
||||
$ docker node ls --filter node.label=region
|
||||
|
||||
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
||||
yg550ettvsjn6g6t840iaiwgb * swarm-test-01 Ready Active Leader 20.10.2
|
||||
2lm9w9kbepgvkzkkeyku40e65 swarm-test-02 Ready Active Reachable 20.10.2
|
||||
hc0pu7ntc7s4uvj4pv7z7pz15 swarm-test-03 Ready Active Reachable 20.10.2
|
||||
n41b2cijmhifxxvz56vwrs12q swarm-test-04 Ready Active 20.10.2
|
||||
```
|
||||
|
||||
Show all nodes that have a `region` node label, with value `region-a`:
|
||||
|
||||
```console
|
||||
$ docker node ls --filter node.label=region=region-a
|
||||
|
||||
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
|
||||
yg550ettvsjn6g6t840iaiwgb * swarm-test-01 Ready Active Leader 20.10.2
|
||||
2lm9w9kbepgvkzkkeyku40e65 swarm-test-02 Ready Active Reachable 20.10.2
|
||||
```
|
||||
|
||||
#### membership
|
||||
|
||||
The `membership` filter matches nodes based on the presence of a `membership` and a value
|
||||
|
||||
@ -160,7 +160,7 @@ Digest can also be used in the `FROM` of a Dockerfile, for example:
|
||||
|
||||
```dockerfile
|
||||
FROM ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2
|
||||
LABEL maintainer="some maintainer <maintainer@example.com>"
|
||||
LABEL org.opencontainers.image.authors="some maintainer <maintainer@example.com>"
|
||||
```
|
||||
|
||||
> **Note**
|
||||
|
||||
@ -76,7 +76,7 @@ listed.
|
||||
|
||||
### Push all tags of an image
|
||||
|
||||
Use the `-a` (or `--all-tags`) option to push To push all tags of a local image.
|
||||
Use the `-a` (or `--all-tags`) option to push all tags of a local image.
|
||||
|
||||
The following example creates multiple tags for an image, and pushes all those
|
||||
tags to Docker Hub.
|
||||
|
||||
@ -58,13 +58,33 @@ The main process inside the container referenced under the link `redis` will rec
|
||||
|
||||
### Remove all stopped containers
|
||||
|
||||
```bash
|
||||
$ docker rm $(docker ps -a -q)
|
||||
Use the [`docker container prune`](container_prune.md) command to remove all
|
||||
stopped containers, or refer to the [`docker system prune`](system_prune.md)
|
||||
command to remove unused containers in addition to other Docker resources, such
|
||||
as (unused) images and networks.
|
||||
|
||||
Alternatively, you can use the `docker ps` with the `-q` / `--quiet` option to
|
||||
generate a list of container IDs to remove, and use that list as argument for
|
||||
the `docker rm` command.
|
||||
|
||||
Combining commands can be more flexible, but is less portable as it depends
|
||||
on features provided by the shell, and the exact syntax may differ depending on
|
||||
what shell is used. To use this approach on Windows, consider using PowerShell
|
||||
or Bash.
|
||||
|
||||
The example below uses `docker ps -q` to print the IDs of all containers that
|
||||
have exited (`--filter status=exited`), and removes those containers with
|
||||
the `docker rm` command:
|
||||
|
||||
```console
|
||||
$ docker rm $(docker ps --filter status=exited -q)
|
||||
```
|
||||
|
||||
This command deletes all stopped containers. The command
|
||||
`docker ps -a -q` above returns all existing container IDs and passes them to
|
||||
the `rm` command which deletes them. Running containers are not deleted.
|
||||
Or, using the `xargs` Linux utility;
|
||||
|
||||
```console
|
||||
$ docker ps --filter status=exited -q | xargs docker rm
|
||||
```
|
||||
|
||||
### Remove a container and its volumes
|
||||
|
||||
|
||||
@ -470,7 +470,7 @@ $ docker run -itd --network=my-net --ip=10.10.9.75 busybox
|
||||
If you want to add a running container to a network use the `docker network connect` subcommand.
|
||||
|
||||
You can connect multiple containers to the same network. Once connected, the
|
||||
containers can communicate easily need only another container's IP address
|
||||
containers can communicate easily using only another container's IP address
|
||||
or name. For `overlay` networks or custom plugins that support multi-host
|
||||
connectivity, containers connected to the same multi-host network but launched
|
||||
from different Engines can also communicate in this way.
|
||||
|
||||
@ -43,7 +43,7 @@ ID NAME MODE REPLICAS IMAGE
|
||||
c8wgl7q4ndfd frontend replicated 5/5 nginx:alpine
|
||||
dmu1ept4cxcf redis replicated 3/3 redis:3.0.6
|
||||
iwe3278osahj mongo global 7/7 mongo:3.3
|
||||
hh08h9uu8uwr job replicated-job 1/1 (3/5 completed) nginx:latest
|
||||
hh08h9uu8uwr job replicated-job 1/1 (3/5 completed) nginx:latest
|
||||
```
|
||||
|
||||
The `REPLICAS` column shows both the *actual* and *desired* number of tasks for
|
||||
|
||||
@ -19,7 +19,9 @@ Options:
|
||||
## Description
|
||||
|
||||
The main process inside the container will receive `SIGTERM`, and after a grace
|
||||
period, `SIGKILL`.
|
||||
period, `SIGKILL`. The first signal can be changed with the `STOPSIGNAL`
|
||||
instruction in the container's Dockerfile, or the `--stop-signal` option to
|
||||
`docker run`.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
---
|
||||
description: "Configure containers at runtime"
|
||||
keywords: "docker, run, configure, runtime"
|
||||
redirect_from:
|
||||
- /reference/run/
|
||||
---
|
||||
|
||||
<!-- This file is maintained within the docker/cli GitHub
|
||||
@ -585,7 +587,7 @@ $ docker inspect -f "{{ .State.StartedAt }}" my-container
|
||||
|
||||
Combining `--restart` (restart policy) with the `--rm` (clean up) flag results
|
||||
in an error. On container restart, attached clients are disconnected. See the
|
||||
examples on using the [`--rm` (clean up)](#clean-up-rm) flag later in this page.
|
||||
examples on using the [`--rm` (clean up)](#clean-up---rm) flag later in this page.
|
||||
|
||||
### Examples
|
||||
|
||||
@ -1738,7 +1740,7 @@ volume mounted on the host).
|
||||
|
||||
The `container-dest` must always be an absolute path such as `/src/docs`.
|
||||
The `host-src` can either be an absolute path or a `name` value. If you
|
||||
supply an absolute path for the `host-dir`, Docker bind-mounts to the path
|
||||
supply an absolute path for the `host-src`, Docker bind-mounts to the path
|
||||
you specify. If you supply a `name`, Docker creates a named volume by that `name`.
|
||||
|
||||
A `name` value must start with an alphanumeric character,
|
||||
|
||||
@ -199,6 +199,9 @@ func genFlagResult(flags *pflag.FlagSet) []cmdOption {
|
||||
if _, ok := flag.Annotations["experimental"]; ok {
|
||||
opt.Experimental = true
|
||||
}
|
||||
if _, ok := flag.Annotations["deprecated"]; ok {
|
||||
opt.Deprecated = true
|
||||
}
|
||||
if v, ok := flag.Annotations["version"]; ok {
|
||||
opt.MinAPIVersion = v[0]
|
||||
}
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/cli/internal/test/environment"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/icmd"
|
||||
"gotest.tools/v3/skip"
|
||||
)
|
||||
@ -22,3 +26,42 @@ func TestTLSVerify(t *testing.T) {
|
||||
result = icmd.RunCmd(icmd.Command("docker", "--tlsverify=true", "ps"))
|
||||
result.Assert(t, icmd.Expected{ExitCode: 1, Err: "ca.pem"})
|
||||
}
|
||||
|
||||
// TestTCPSchemeUsesHTTPProxyEnv verifies that the cli uses HTTP_PROXY if
|
||||
// DOCKER_HOST is set to use the 'tcp://' scheme.
|
||||
//
|
||||
// Prior to go1.16, https:// schemes would use HTTPS_PROXY, and any other
|
||||
// scheme would use HTTP_PROXY. However, golang/net@7b1cca2 (per a request in
|
||||
// golang/go#40909) changed this behavior to only use HTTP_PROXY for http://
|
||||
// schemes, no longer using a proxy for any other scheme.
|
||||
//
|
||||
// Docker uses the tcp:// scheme as a default for API connections, to indicate
|
||||
// that the API is not "purely" HTTP. Various parts in the code also *require*
|
||||
// this scheme to be used. While we could change the default and allow http(s)
|
||||
// schemes to be used, doing so will take time, taking into account that there
|
||||
// are many installs in existence that have tcp:// configured as DOCKER_HOST.
|
||||
//
|
||||
// Note that due to Golang's use of sync.Once for proxy-detection, this test
|
||||
// cannot be done as a unit-test, hence it being an e2e test.
|
||||
func TestTCPSchemeUsesHTTPProxyEnv(t *testing.T) {
|
||||
const responseJSON = `{"Version": "99.99.9", "ApiVersion": "1.41", "MinAPIVersion": "1.12"}`
|
||||
var received string
|
||||
proxyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
received = r.Host
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(responseJSON))
|
||||
}))
|
||||
defer proxyServer.Close()
|
||||
|
||||
// Configure the CLI to use our proxyServer. DOCKER_HOST can point to any
|
||||
// address (as it won't be connected to), but must use tcp:// for this test,
|
||||
// to verify it's using HTTP_PROXY.
|
||||
result := icmd.RunCmd(
|
||||
icmd.Command("docker", "version", "--format", "{{ .Server.Version }}"),
|
||||
icmd.WithEnv("HTTP_PROXY="+proxyServer.URL, "DOCKER_HOST=tcp://docker.acme.example.com:2376"),
|
||||
)
|
||||
// Verify the command ran successfully, and that it connected to the proxyServer
|
||||
result.Assert(t, icmd.Success)
|
||||
assert.Equal(t, strings.TrimSpace(result.Stdout()), "99.99.9")
|
||||
assert.Equal(t, received, "docker.acme.example.com:2376")
|
||||
}
|
||||
|
||||
@ -39,12 +39,5 @@ Checkpoint and restore support for Containers.
|
||||
Metrics (Prometheus) output for basic container, image, and daemon operations.
|
||||
|
||||
* [External graphdriver plugins](../docs/extend/plugins_graphdriver.md)
|
||||
* [Ipvlan Network Drivers](vlan-networks.md)
|
||||
* [Checkpoint & Restore](checkpoint-restore.md)
|
||||
* [Docker build with --squash argument](../docs/reference/commandline/build.md#squash-an-images-layers---squash-experimental)
|
||||
|
||||
## How to comment on an experimental feature
|
||||
|
||||
Each feature's documentation includes a list of proposal pull requests or PRs associated with the feature. If you want to comment on or suggest a change to a feature, please add it to the existing feature PR.
|
||||
|
||||
Issues or problems with a feature? Inquire for help on the `#docker` IRC channel or on the [Docker Google group](https://groups.google.com/forum/#!forum/docker-user).
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 108 KiB |
@ -1,632 +0,0 @@
|
||||
# Ipvlan Network Driver
|
||||
|
||||
### Getting Started
|
||||
|
||||
The Ipvlan driver is currently in experimental mode in order to incubate Docker
|
||||
users use cases and vet the implementation to ensure a hardened, production ready
|
||||
driver in a future release. Libnetwork now gives users total control over both
|
||||
IPv4 and IPv6 addressing. The VLAN driver builds on top of that in giving
|
||||
operators complete control of layer 2 VLAN tagging and even Ipvlan L3 routing
|
||||
for users interested in underlay network integration. For overlay deployments
|
||||
that abstract away physical constraints see the
|
||||
[multi-host overlay](https://docs.docker.com/network/network-tutorial-overlay/)
|
||||
driver.
|
||||
|
||||
Ipvlan is a new twist on the tried and true network virtualization technique.
|
||||
The Linux implementations are extremely lightweight because rather than using
|
||||
the traditional Linux bridge for isolation, they are simply associated to a Linux
|
||||
Ethernet interface or sub-interface to enforce separation between networks and
|
||||
connectivity to the physical network.
|
||||
|
||||
Ipvlan offers a number of unique features and plenty of room for further
|
||||
innovations with the various modes. Two high level advantages of these approaches
|
||||
are, the positive performance implications of bypassing the Linux bridge and the
|
||||
simplicity of having fewer moving parts. Removing the bridge that traditionally
|
||||
resides in between the Docker host NIC and container interface leaves a simple
|
||||
setup consisting of container interfaces, attached directly to the Docker host
|
||||
interface. This result is easy access for external facing services as there is
|
||||
no need for port mappings in these scenarios.
|
||||
|
||||
### Pre-Requisites
|
||||
|
||||
- The examples on this page are all single host and require using Docker
|
||||
experimental features to be enabled.
|
||||
- All of the examples can be performed on a single host running Docker. Any
|
||||
example using a sub-interface like `eth0.10` can be replaced with `eth0` or
|
||||
any other valid parent interface on the Docker host. Sub-interfaces with a `.`
|
||||
are created on the fly. `-o parent` interfaces can also be left out of the
|
||||
`docker network create` all together and the driver will create a `dummy`
|
||||
interface that will enable local host connectivity to perform the examples.
|
||||
- Kernel requirements:
|
||||
- To check your current kernel version, use `uname -r`
|
||||
- Ipvlan Linux kernel v4.2+ (support for earlier kernels exists but is buggy)
|
||||
|
||||
### Ipvlan L2 Mode Example Usage
|
||||
|
||||
An example of the ipvlan `L2` mode topology is shown in the following image.
|
||||
The driver is specified with `-d driver_name` option. In this case `-d ipvlan`.
|
||||
|
||||

|
||||
|
||||
The parent interface in the next example `-o parent=eth0` is configured as follows:
|
||||
|
||||
```bash
|
||||
$ ip addr show eth0
|
||||
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
|
||||
inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
|
||||
```
|
||||
|
||||
Use the network from the host's interface as the `--subnet` in the
|
||||
`docker network create`. The container will be attached to the same network as
|
||||
the host interface as set via the `-o parent=` option.
|
||||
|
||||
Create the ipvlan network and run a container attaching to it:
|
||||
|
||||
```bash
|
||||
# Ipvlan (-o ipvlan_mode= Defaults to L2 mode if not specified)
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.1.0/24 \
|
||||
--gateway=192.168.1.1 \
|
||||
-o ipvlan_mode=l2 \
|
||||
-o parent=eth0 db_net
|
||||
|
||||
# Start a container on the db_net network
|
||||
$ docker run --net=db_net -it --rm alpine /bin/sh
|
||||
|
||||
# NOTE: the containers can NOT ping the underlying host interfaces as
|
||||
# they are intentionally filtered by Linux for additional isolation.
|
||||
```
|
||||
|
||||
The default mode for Ipvlan is `l2`. If `-o ipvlan_mode=` are left unspecified,
|
||||
the default mode will be used. Similarly, if the `--gateway` is left empty, the
|
||||
first usable address on the network will be set as the gateway. For example, if
|
||||
the subnet provided in the network create is `--subnet=192.168.1.0/24` then the
|
||||
gateway the container receives is `192.168.1.1`.
|
||||
|
||||
To help understand how this mode interacts with other hosts, the following
|
||||
figure shows the same layer 2 segment between two Docker hosts that applies to
|
||||
and Ipvlan L2 mode.
|
||||
|
||||

|
||||
|
||||
The following will create the exact same network as the network `db_net` created
|
||||
prior, with the driver defaults for `--gateway=192.168.1.1` and `-o ipvlan_mode=l2`.
|
||||
|
||||
```bash
|
||||
# Ipvlan (-o ipvlan_mode= Defaults to L2 mode if not specified)
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.1.0/24 \
|
||||
-o parent=eth0 db_net_ipv
|
||||
|
||||
# Start a container with an explicit name in daemon mode
|
||||
$ docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh
|
||||
|
||||
# Start a second container and ping using the container name
|
||||
# to see the docker included name resolution functionality
|
||||
$ docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
|
||||
$ ping -c 4 ipv1
|
||||
|
||||
# NOTE: the containers can NOT ping the underlying host interfaces as
|
||||
# they are intentionally filtered by Linux for additional isolation.
|
||||
```
|
||||
|
||||
The drivers also support the `--internal` flag that will completely isolate
|
||||
containers on a network from any communications external to that network. Since
|
||||
network isolation is tightly coupled to the network's parent interface the result
|
||||
of leaving the `-o parent=` option off of a `docker network create` is the exact
|
||||
same as the `--internal` option. If the parent interface is not specified or the
|
||||
`--internal` flag is used, a netlink type `dummy` parent interface is created
|
||||
for the user and used as the parent interface effectively isolating the network
|
||||
completely.
|
||||
|
||||
The following two `docker network create` examples result in identical networks
|
||||
that you can attach container to:
|
||||
|
||||
```bash
|
||||
# Empty '-o parent=' creates an isolated network
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.10.0/24 isolated1
|
||||
|
||||
# Explicit '--internal' flag is the same:
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.11.0/24 --internal isolated2
|
||||
|
||||
# Even the '--subnet=' can be left empty and the default
|
||||
# IPAM subnet of 172.18.0.0/16 will be assigned
|
||||
$ docker network create -d ipvlan isolated3
|
||||
|
||||
$ docker run --net=isolated1 --name=cid1 -it --rm alpine /bin/sh
|
||||
$ docker run --net=isolated2 --name=cid2 -it --rm alpine /bin/sh
|
||||
$ docker run --net=isolated3 --name=cid3 -it --rm alpine /bin/sh
|
||||
|
||||
# To attach to any use `docker exec` and start a shell
|
||||
$ docker exec -it cid1 /bin/sh
|
||||
$ docker exec -it cid2 /bin/sh
|
||||
$ docker exec -it cid3 /bin/sh
|
||||
```
|
||||
|
||||
### Ipvlan 802.1q Trunk L2 Mode Example Usage
|
||||
|
||||
Architecturally, Ipvlan L2 mode trunking is the same as Macvlan with regard to
|
||||
gateways and L2 path isolation. There are nuances that can be advantageous for
|
||||
CAM table pressure in ToR switches, one MAC per port and MAC exhaustion on a
|
||||
host's parent NIC to name a few. The 802.1q trunk scenario looks the same. Both
|
||||
modes adhere to tagging standards and have seamless integration with the physical
|
||||
network for underlay integration and hardware vendor plugin integrations.
|
||||
|
||||
Hosts on the same VLAN are typically on the same subnet and almost always are
|
||||
grouped together based on their security policy. In most scenarios, a multi-tier
|
||||
application is tiered into different subnets because the security profile of each
|
||||
process requires some form of isolation. For example, hosting your credit card
|
||||
processing on the same virtual network as the frontend webserver would be a
|
||||
regulatory compliance issue, along with circumventing the long standing best
|
||||
practice of layered defense in depth architectures. VLANs or the equivocal VNI
|
||||
(Virtual Network Identifier) when using the Overlay driver, are the first step
|
||||
in isolating tenant traffic.
|
||||
|
||||

|
||||
|
||||
The Linux sub-interface tagged with a vlan can either already exist or will be
|
||||
created when you call a `docker network create`. `docker network rm` will delete
|
||||
the sub-interface. Parent interfaces such as `eth0` are not deleted, only
|
||||
sub-interfaces with a netlink parent index > 0.
|
||||
|
||||
For the driver to add/delete the vlan sub-interfaces the format needs to be
|
||||
`interface_name.vlan_tag`. Other sub-interface naming can be used as the
|
||||
specified parent, but the link will not be deleted automatically when
|
||||
`docker network rm` is invoked.
|
||||
|
||||
The option to use either existing parent vlan sub-interfaces or let Docker manage
|
||||
them enables the user to either completely manage the Linux interfaces and
|
||||
networking or let Docker create and delete the Vlan parent sub-interfaces
|
||||
(netlink `ip link`) with no effort from the user.
|
||||
|
||||
For example: use `eth0.10` to denote a sub-interface of `eth0` tagged with the
|
||||
vlan id of `10`. The equivalent `ip link` command would be
|
||||
`ip link add link eth0 name eth0.10 type vlan id 10`.
|
||||
|
||||
The example creates the vlan tagged networks and then start two containers to
|
||||
test connectivity between containers. Different Vlans cannot ping one another
|
||||
without a router routing between the two networks. The default namespace is not
|
||||
reachable per ipvlan design in order to isolate container namespaces from the
|
||||
underlying host.
|
||||
|
||||
**Vlan ID 20**
|
||||
|
||||
In the first network tagged and isolated by the Docker host, `eth0.20` is the
|
||||
parent interface tagged with vlan id `20` specified with `-o parent=eth0.20`.
|
||||
Other naming formats can be used, but the links need to be added and deleted
|
||||
manually using `ip link` or Linux configuration files. As long as the `-o parent`
|
||||
exists anything can be used if compliant with Linux netlink.
|
||||
|
||||
```bash
|
||||
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.20.0/24 \
|
||||
--gateway=192.168.20.1 \
|
||||
-o parent=eth0.20 ipvlan20
|
||||
|
||||
# in two separate terminals, start a Docker container and the containers can now ping one another.
|
||||
$ docker run --net=ipvlan20 -it --name ivlan_test1 --rm alpine /bin/sh
|
||||
$ docker run --net=ipvlan20 -it --name ivlan_test2 --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
**Vlan ID 30**
|
||||
|
||||
In the second network, tagged and isolated by the Docker host, `eth0.30` is the
|
||||
parent interface tagged with vlan id `30` specified with `-o parent=eth0.30`. The
|
||||
`ipvlan_mode=` defaults to l2 mode `ipvlan_mode=l2`. It can also be explicitly
|
||||
set with the same result as shown in the next example.
|
||||
|
||||
```bash
|
||||
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged.
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.30.0/24 \
|
||||
--gateway=192.168.30.1 \
|
||||
-o parent=eth0.30 \
|
||||
-o ipvlan_mode=l2 ipvlan30
|
||||
|
||||
# in two separate terminals, start a Docker container and the containers can now ping one another.
|
||||
$ docker run --net=ipvlan30 -it --name ivlan_test3 --rm alpine /bin/sh
|
||||
$ docker run --net=ipvlan30 -it --name ivlan_test4 --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
The gateway is set inside of the container as the default gateway. That gateway
|
||||
would typically be an external router on the network.
|
||||
|
||||
```bash
|
||||
$$ ip route
|
||||
default via 192.168.30.1 dev eth0
|
||||
192.168.30.0/24 dev eth0 src 192.168.30.2
|
||||
```
|
||||
|
||||
Example: Multi-Subnet Ipvlan L2 Mode starting two containers on the same subnet
|
||||
and pinging one another. In order for the `192.168.114.0/24` to reach
|
||||
`192.168.116.0/24` it requires an external router in L2 mode. L3 mode can route
|
||||
between subnets that share a common `-o parent=`.
|
||||
|
||||
Secondary addresses on network routers are common as an address space becomes
|
||||
exhausted to add another secondary to an L3 vlan interface or commonly referred
|
||||
to as a "switched virtual interface" (SVI).
|
||||
|
||||
```bash
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.114.0/24 --subnet=192.168.116.0/24 \
|
||||
--gateway=192.168.114.254 --gateway=192.168.116.254 \
|
||||
-o parent=eth0.114 \
|
||||
-o ipvlan_mode=l2 ipvlan114
|
||||
|
||||
$ docker run --net=ipvlan114 --ip=192.168.114.10 -it --rm alpine /bin/sh
|
||||
$ docker run --net=ipvlan114 --ip=192.168.114.11 -it --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
A key takeaway is, operators have the ability to map their physical network into
|
||||
their virtual network for integrating containers into their environment with no
|
||||
operational overhauls required. NetOps simply drops an 802.1q trunk into the
|
||||
Docker host. That virtual link would be the `-o parent=` passed in the network
|
||||
creation. For untagged (non-VLAN) links, it is as simple as `-o parent=eth0` or
|
||||
for 802.1q trunks with VLAN IDs each network gets mapped to the corresponding
|
||||
VLAN/Subnet from the network.
|
||||
|
||||
An example being, NetOps provides VLAN ID and the associated subnets for VLANs
|
||||
being passed on the Ethernet link to the Docker host server. Those values are
|
||||
simply plugged into the `docker network create` commands when provisioning the
|
||||
Docker networks. These are persistent configurations that are applied every time
|
||||
the Docker engine starts which alleviates having to manage often complex
|
||||
configuration files. The network interfaces can also be managed manually by
|
||||
being pre-created and docker networking will never modify them, simply use them
|
||||
as parent interfaces. Example mappings from NetOps to Docker network commands
|
||||
are as follows:
|
||||
|
||||
- VLAN: 10, Subnet: 172.16.80.0/24, Gateway: 172.16.80.1
|
||||
- `--subnet=172.16.80.0/24 --gateway=172.16.80.1 -o parent=eth0.10`
|
||||
- VLAN: 20, IP subnet: 172.16.50.0/22, Gateway: 172.16.50.1
|
||||
- `--subnet=172.16.50.0/22 --gateway=172.16.50.1 -o parent=eth0.20 `
|
||||
- VLAN: 30, Subnet: 10.1.100.0/16, Gateway: 10.1.100.1
|
||||
- `--subnet=10.1.100.0/16 --gateway=10.1.100.1 -o parent=eth0.30`
|
||||
|
||||
### IPVlan L3 Mode Example
|
||||
|
||||
IPVlan will require routes to be distributed to each endpoint. The driver only
|
||||
builds the Ipvlan L3 mode port and attaches the container to the interface. Route
|
||||
distribution throughout a cluster is beyond the initial implementation of this
|
||||
single host scoped driver. In L3 mode, the Docker host is very similar to a
|
||||
router starting new networks in the container. They are on networks that the
|
||||
upstream network will not know about without route distribution. For those
|
||||
curious how Ipvlan L3 will fit into container networking see the following
|
||||
examples.
|
||||
|
||||

|
||||
|
||||
Ipvlan L3 mode drops all broadcast and multicast traffic. This reason alone
|
||||
makes Ipvlan L3 mode a prime candidate for those looking for massive scale and
|
||||
predictable network integrations. It is predictable and in turn will lead to
|
||||
greater uptimes because there is no bridging involved. Bridging loops have been
|
||||
responsible for high profile outages that can be hard to pinpoint depending on
|
||||
the size of the failure domain. This is due to the cascading nature of BPDUs
|
||||
(Bridge Port Data Units) that are flooded throughout a broadcast domain (VLAN)
|
||||
to find and block topology loops. Eliminating bridging domains, or at the least,
|
||||
keeping them isolated to a pair of ToRs (top of rack switches) will reduce hard
|
||||
to troubleshoot bridging instabilities. Ipvlan L2 modes is well suited for
|
||||
isolated VLANs only trunked into a pair of ToRs that can provide a loop-free
|
||||
non-blocking fabric. The next step further is to route at the edge via Ipvlan L3
|
||||
mode that reduces a failure domain to a local host only.
|
||||
|
||||
- L3 mode needs to be on a separate subnet as the default namespace since it
|
||||
requires a netlink route in the default namespace pointing to the Ipvlan parent
|
||||
interface.
|
||||
- The parent interface used in this example is `eth0` and it is on the subnet
|
||||
`192.168.1.0/24`. Notice the `docker network` is **not** on the same subnet
|
||||
as `eth0`.
|
||||
- Unlike ipvlan l2 modes, different subnets/networks can ping one another as
|
||||
long as they share the same parent interface `-o parent=`.
|
||||
|
||||
```bash
|
||||
$$ ip a show eth0
|
||||
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
|
||||
link/ether 00:50:56:39:45:2e brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
|
||||
```
|
||||
|
||||
- A traditional gateway doesn't mean much to an L3 mode Ipvlan interface since
|
||||
there is no broadcast traffic allowed. Because of that, the container default
|
||||
gateway simply points to the containers `eth0` device. See below for CLI output
|
||||
of `ip route` or `ip -6 route` from inside an L3 container for details.
|
||||
|
||||
The mode ` -o ipvlan_mode=l3` must be explicitly specified since the default
|
||||
ipvlan mode is `l2`.
|
||||
|
||||
The following example does not specify a parent interface. The network drivers
|
||||
will create a dummy type link for the user rather than rejecting the network
|
||||
creation and isolating containers from only communicating with one another.
|
||||
|
||||
```bash
|
||||
# Create the Ipvlan L3 network
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.214.0/24 \
|
||||
--subnet=10.1.214.0/24 \
|
||||
-o ipvlan_mode=l3 ipnet210
|
||||
|
||||
# Test 192.168.214.0/24 connectivity
|
||||
$ docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
|
||||
$ docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh
|
||||
|
||||
# Test L3 connectivity from 10.1.214.0/24 to 192.168.212.0/24
|
||||
$ docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10
|
||||
|
||||
# Test L3 connectivity from 192.168.212.0/24 to 10.1.214.0/24
|
||||
$ docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10
|
||||
|
||||
```
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Notice that there is no `--gateway=` option in the network create. The field
|
||||
> is ignored if one is specified `l3` mode. Take a look at the container routing
|
||||
> table from inside of the container:
|
||||
>
|
||||
> ```bash
|
||||
> # Inside an L3 mode container
|
||||
> $$ ip route
|
||||
> default dev eth0
|
||||
> 192.168.214.0/24 dev eth0 src 192.168.214.10
|
||||
> ```
|
||||
|
||||
In order to ping the containers from a remote Docker host or the container be
|
||||
able to ping a remote host, the remote host or the physical network in between
|
||||
need to have a route pointing to the host IP address of the container's Docker
|
||||
host eth interface. More on this as we evolve the Ipvlan `L3` story.
|
||||
|
||||
### Dual Stack IPv4 IPv6 Ipvlan L2 Mode
|
||||
|
||||
- Not only does Libnetwork give you complete control over IPv4 addressing, but
|
||||
it also gives you total control over IPv6 addressing as well as feature parity
|
||||
between the two address families.
|
||||
|
||||
- The next example will start with IPv6 only. Start two containers on the same
|
||||
VLAN `139` and ping one another. Since the IPv4 subnet is not specified, the
|
||||
default IPAM will provision a default IPv4 subnet. That subnet is isolated
|
||||
unless the upstream network is explicitly routing it on VLAN `139`.
|
||||
|
||||
```bash
|
||||
# Create a v6 network
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=2001:db8:abc2::/64 --gateway=2001:db8:abc2::22 \
|
||||
-o parent=eth0.139 v6ipvlan139
|
||||
|
||||
# Start a container on the network
|
||||
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
View the container eth0 interface and v6 routing table:
|
||||
|
||||
```bash
|
||||
# Inside the IPv6 container
|
||||
$$ ip a show eth0
|
||||
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
|
||||
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
|
||||
inet 172.18.0.2/16 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc2::1/64 scope link nodad
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
$$ ip -6 route
|
||||
2001:db8:abc4::/64 dev eth0 proto kernel metric 256
|
||||
2001:db8:abc2::/64 dev eth0 proto kernel metric 256
|
||||
default via 2001:db8:abc2::22 dev eth0 metric 1024
|
||||
```
|
||||
|
||||
Start a second container and ping the first container's v6 address.
|
||||
|
||||
```bash
|
||||
# Test L2 connectivity over IPv6
|
||||
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh
|
||||
|
||||
# Inside the second IPv6 container
|
||||
$$ ip a show eth0
|
||||
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
|
||||
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
|
||||
inet 172.18.0.3/16 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link tentative dadfailed
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc2::2/64 scope link nodad
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
$$ ping6 2001:db8:abc2::1
|
||||
PING 2001:db8:abc2::1 (2001:db8:abc2::1): 56 data bytes
|
||||
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=0 ttl=64 time=0.044 ms
|
||||
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=1 ttl=64 time=0.058 ms
|
||||
|
||||
2 packets transmitted, 2 packets received, 0% packet loss
|
||||
round-trip min/avg/max/stddev = 0.044/0.051/0.058/0.000 ms
|
||||
```
|
||||
|
||||
The next example with setup a dual stack IPv4/IPv6 network with an example
|
||||
VLAN ID of `140`.
|
||||
|
||||
Next create a network with two IPv4 subnets and one IPv6 subnets, all of which
|
||||
have explicit gateways:
|
||||
|
||||
```bash
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.140.0/24 --subnet=192.168.142.0/24 \
|
||||
--gateway=192.168.140.1 --gateway=192.168.142.1 \
|
||||
--subnet=2001:db8:abc9::/64 --gateway=2001:db8:abc9::22 \
|
||||
-o parent=eth0.140 \
|
||||
-o ipvlan_mode=l2 ipvlan140
|
||||
```
|
||||
|
||||
Start a container and view eth0 and both v4 & v6 routing tables:
|
||||
|
||||
```bash
|
||||
$ docker run --net=ipvlan140 --ip6=2001:db8:abc2::51 -it --rm alpine /bin/sh
|
||||
|
||||
$ ip a show eth0
|
||||
78: eth0@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
|
||||
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.140.2/24 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc9::1/64 scope link nodad
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
$$ ip route
|
||||
default via 192.168.140.1 dev eth0
|
||||
192.168.140.0/24 dev eth0 proto kernel scope link src 192.168.140.2
|
||||
|
||||
$$ ip -6 route
|
||||
2001:db8:abc4::/64 dev eth0 proto kernel metric 256
|
||||
2001:db8:abc9::/64 dev eth0 proto kernel metric 256
|
||||
default via 2001:db8:abc9::22 dev eth0 metric 1024
|
||||
```
|
||||
|
||||
Start a second container with a specific `--ip4` address and ping the first host
|
||||
using IPv4 packets:
|
||||
|
||||
```bash
|
||||
$ docker run --net=ipvlan140 --ip=192.168.140.10 -it --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> Different subnets on the same parent interface in Ipvlan `L2` mode cannot ping
|
||||
> one another. That requires a router to proxy-arp the requests with a secondary
|
||||
> subnet. However, Ipvlan `L3` will route the unicast traffic between disparate
|
||||
> subnets as long as they share the same `-o parent` parent link.
|
||||
|
||||
### Dual Stack IPv4 IPv6 Ipvlan L3 Mode
|
||||
|
||||
**Example:** IpVlan L3 Mode Dual Stack IPv4/IPv6, Multi-Subnet w/ 802.1q Vlan Tag:118
|
||||
|
||||
As in all of the examples, a tagged VLAN interface does not have to be used. The
|
||||
sub-interfaces can be swapped with `eth0`, `eth1`, `bond0` or any other valid
|
||||
interface on the host other then the `lo` loopback.
|
||||
|
||||
The primary difference you will see is that L3 mode does not create a default
|
||||
route with a next-hop but rather sets a default route pointing to `dev eth` only
|
||||
since ARP/Broadcasts/Multicast are all filtered by Linux as per the design. Since
|
||||
the parent interface is essentially acting as a router, the parent interface IP
|
||||
and subnet needs to be different from the container networks. That is the opposite
|
||||
of bridge and L2 modes, which need to be on the same subnet (broadcast domain)
|
||||
in order to forward broadcast and multicast packets.
|
||||
|
||||
```bash
|
||||
# Create an IPv6+IPv4 Dual Stack Ipvlan L3 network
|
||||
# Gateways for both v4 and v6 are set to a dev e.g. 'default dev eth0'
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.110.0/24 \
|
||||
--subnet=192.168.112.0/24 \
|
||||
--subnet=2001:db8:abc6::/64 \
|
||||
-o parent=eth0 \
|
||||
-o ipvlan_mode=l3 ipnet110
|
||||
|
||||
|
||||
# Start a few of containers on the network (ipnet110)
|
||||
# in separate terminals and check connectivity
|
||||
$ docker run --net=ipnet110 -it --rm alpine /bin/sh
|
||||
# Start a second container specifying the v6 address
|
||||
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::10 -it --rm alpine /bin/sh
|
||||
# Start a third specifying the IPv4 address
|
||||
$ docker run --net=ipnet110 --ip=192.168.112.30 -it --rm alpine /bin/sh
|
||||
# Start a 4th specifying both the IPv4 and IPv6 addresses
|
||||
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::50 --ip=192.168.112.50 -it --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
Interface and routing table outputs are as follows:
|
||||
|
||||
```bash
|
||||
$$ ip a show eth0
|
||||
63: eth0@if59: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
|
||||
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.112.2/24 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 2001:db8:abc6::10/64 scope link nodad
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
# Note the default route is simply the eth device because ARPs are filtered.
|
||||
$$ ip route
|
||||
default dev eth0 scope link
|
||||
192.168.112.0/24 dev eth0 proto kernel scope link src 192.168.112.2
|
||||
|
||||
$$ ip -6 route
|
||||
2001:db8:abc4::/64 dev eth0 proto kernel metric 256
|
||||
2001:db8:abc6::/64 dev eth0 proto kernel metric 256
|
||||
default dev eth0 metric 1024
|
||||
```
|
||||
|
||||
> *Note*
|
||||
>
|
||||
> There may be a bug when specifying `--ip6=` addresses when you delete a
|
||||
> container with a specified v6 address and then start a new container with the
|
||||
> same v6 address it throws the following like the address isn't properly being
|
||||
> released to the v6 pool. It will fail to unmount the container and be left dead.
|
||||
|
||||
```console
|
||||
docker: Error response from daemon: Address already in use.
|
||||
```
|
||||
|
||||
### Manually Creating 802.1q Links
|
||||
|
||||
**Vlan ID 40**
|
||||
|
||||
If a user does not want the driver to create the vlan sub-interface it simply
|
||||
needs to exist prior to the `docker network create`. If you have sub-interface
|
||||
naming that is not `interface.vlan_id` it is honored in the `-o parent=` option
|
||||
again as long as the interface exists and is up.
|
||||
|
||||
Links, when manually created, can be named anything as long as they exist when
|
||||
the network is created. Manually created links do not get deleted regardless of
|
||||
the name when the network is deleted with `docker network rm`.
|
||||
|
||||
```bash
|
||||
# create a new sub-interface tied to dot1q vlan 40
|
||||
$ ip link add link eth0 name eth0.40 type vlan id 40
|
||||
|
||||
# enable the new sub-interface
|
||||
$ ip link set eth0.40 up
|
||||
|
||||
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.40.0/24 \
|
||||
--gateway=192.168.40.1 \
|
||||
-o parent=eth0.40 ipvlan40
|
||||
|
||||
# in two separate terminals, start a Docker container and the containers can now ping one another.
|
||||
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
|
||||
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
**Example:** Vlan sub-interface manually created with any name:
|
||||
|
||||
```bash
|
||||
# create a new sub interface tied to dot1q vlan 40
|
||||
$ ip link add link eth0 name foo type vlan id 40
|
||||
|
||||
# enable the new sub-interface
|
||||
$ ip link set foo up
|
||||
|
||||
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
|
||||
$ docker network create -d ipvlan \
|
||||
--subnet=192.168.40.0/24 --gateway=192.168.40.1 \
|
||||
-o parent=foo ipvlan40
|
||||
|
||||
# in two separate terminals, start a Docker container and the containers can now ping one another.
|
||||
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
|
||||
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
|
||||
```
|
||||
|
||||
Manually created links can be cleaned up with:
|
||||
|
||||
```bash
|
||||
$ ip link del foo
|
||||
```
|
||||
|
||||
As with all of the Libnetwork drivers, they can be mixed and matched, even as
|
||||
far as running 3rd party ecosystem drivers in parallel for maximum flexibility
|
||||
to the Docker user.
|
||||