Add docs about configs

This commit is contained in:
Misty Stanley-Jones 2017-06-05 15:06:45 -07:00 committed by Misty Stanley-Jones
parent abae9c48fa
commit 044bc28dbb
2 changed files with 531 additions and 0 deletions

View File

@ -334,6 +334,8 @@ guides:
title: Manage nodes in a swarm
- path: /engine/swarm/services/
title: Deploy services to a swarm
- path: /engine/swarm/configs/
title: Store service configuration data
- path: /engine/swarm/secrets/
title: Manage sensitive data with Docker secrets
- path: /engine/swarm/swarm_manager_locking/
@ -544,6 +546,18 @@ reference:
title: docker checkpoint rm
- path: /engine/reference/commandline/commit/
title: docker commit
- sectiontitle: docker config *
section:
- path: /engine/reference/commandline/config/
title: docker config
- path: /engine/reference/commandline/config_create/
title: docker config create
- path: /engine/reference/commandline/config_inspect/
title: docker config inspect
- path: /engine/reference/commandline/config_ls/
title: docker config ls
- path: /engine/reference/commandline/config_rm/
title: docker config rm
- sectiontitle: docker container *
section:
- path: /engine/reference/commandline/container/

517
engine/swarm/configs.md Normal file
View File

@ -0,0 +1,517 @@
---
title: Store configuration data using Docker Configs
description: How to store configuration data separate from the runtime
keywords: swarm, configuration, configs
---
## About configs
Docker 17.06 introduces swarm service configs, which allow you to store
non-sensitive information, such as configuration files, outside a service's
image or running containers. This allows you to keep your images as generic
as possible, without the need to bind-mount configuration files into the
containers or use environment variables.
Configs operate in a similar way to [secrets](secrets.md), except that they are
not encrypted at rest. Configs can be added or removed from a service at any
time, and services can share a config. You can even use configs in conjunction
with environment variables or labels, for maximum flexibility.
> **Note**: Docker configs are only available to swarm services, not to
> standalone containers. To use this feature, consider adapting your container
> to run as a service with a scale of 1.
Configs are supported on both Linux and Windows services.
## How Docker manages configs
When you add a config to the swarm, Docker sends the config to the swarm manager
over a mutual TLS connection. The config is stored in the Raft log, which is
encrypted. The entire Raft log is replicated across the other managers, ensuring
the same high availability guarantees for configs as for the rest of the swarm
management data.
When you grant a newly-created or running service access to a config, the
config is mounted as a file in the container, in an in-memory filesystem. The
location of the mount point within the container defaults to
`/<config-name>` in Linux containers. In Windows containers, configs are all
mounted into `C:\ProgramData\Docker\configs` and symbolic links are created to
the desired location, which defaults to `C:\<config-name>`.
You can update a service to grant it access to additional configs or revoke its
access to a given config at any time.
A node only has access to configs if the node is a swarm manager or if it is
running service tasks which have been granted access to the config. When a
container task stops running, the configs shared to it are unmounted from the
in-memory filesystem for that container and flushed from the node's memory.
If a node loses connectivity to the swarm while it is running a task container
with access to a config, the task container still has access to its configs, but
cannot receive updates until the node reconnects to the swarm.
You can add or inspect an individual config at any time, or list all
configs. You cannot remove a config that a running service is
using. See [Rotate a config](configs.md#example-rotate-a-config) for a way to
remove a config without disrupting running services.
In order to update or roll back configs more easily, consider adding a version
number or date to the config name. This is made easier by the ability to control
the mount point of the config within a given container.
## Read more about `docker config` commands
Use these links to read about specific commands, or continue to the
[example about using configs with a service](configs.md#example-use-configs-with-a-service).
- [`docker config create`](/engine/reference/commandline/config_create.md)
- [`docker config inspect`](/engine/reference/commandline/config_inspect.md)
- [`docker config ls`](/engine/reference/commandline/config_ls.md)
- [`docker config rm`](/engine/reference/commandline/config_rm.md)
## Examples
This section includes graduated examples which illustrate how to use
Docker configs.
> **Note**: These examples use a single-Engine swarm and unscaled services for
> simplicity. The examples use Linux containers, but Windows containers also
> support configs.
### Simple example: Get started with configs
This simple example shows how configs work in just a few commands. For a
real-world example, continue to
[Intermediate example: Use configs with a Nginx service](#advanced-example-use-configs-with-a-nginx-service).
1. Add a config to Docker. The `docker config create` command reads standard
input because the last argument, which represents the file to read the
config from, is set to `-`.
```bash
$ echo "This is a config" | docker config create my-config -
```
2. Create a `redis` service and grant it access to the config. By default,
the container can access the config at `/my-config`, but
you can customize the file name on the container using the `target` option.
```bash
$ docker service create --name="redis" --config="my-config" redis:alpine
```
3. Verify that the task is running without issues using `docker service ps`. If
everything is working, the output looks similar to this:
```bash
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bkna6bpn8r1a redis.1 redis:alpine ip-172-31-46-109 Running Running 8 seconds ago
```
4. Get the ID of the `redis` service task container using `docker ps`, so that
you can use `docker exec` to connect to the container and read the contents
of the config data file, which defaults to being readable by all and has the
same name as the name of the config. The first command below illustrates
how to find the container ID, and the second and third commands use shell
completion to do this automatically.
```bash
$ docker ps --filter name=redis -q
5cb1c2348a59
$ docker exec $(docker ps --filter name=redis -q) ls -l /my-config
-r--r--r-- 1 root root 12 Jun 5 20:49 my-config
$ docker exec $(docker ps --filter name=redis -q) cat /my-config
This is a config
```
5. Verify that the config is **not** available if you commit the container.
```none
$ docker commit $(docker ps --filter name=redis -q) committed_redis
$ docker run --rm -it committed_redis cat /my-config
cat: can't open '/my-config': No such file or directory
```
6. Try removing the config. The removal fails because the `redis` service is
running and has access to the config.
```bash
$ docker config ls
ID NAME CREATED UPDATED
fzwcfuqjkvo5foqu7ts7ls578 hello 31 minutes ago 31 minutes ago
$ docker config rm my-config
Error response from daemon: rpc error: code = 3 desc = config 'my-config' is in use by the following service: redis
```
7. Remove access to the config from the running `redis` service by updating the
service.
```bash
$ docker service update --config-rm="my-config" redis
```
8. Repeat steps 3 and 4 again, verifying that the service no longer has access
to the config. The container ID will be different, because the
`service update` command redeploys the service.
```none
$ docker exec -it $(docker ps --filter name=redis -q) cat /my-config
cat: can't open '/my-config': No such file or directory
```
7. Stop and remove the service, and remove the config from Docker.
```bash
$ docker service rm redis
$ docker config rm my-config
```
### Advanced example: Use configs with a Nginx service
This example is divided into two parts.
[The first part](#generate-the-site-certificate) is all about generating
the site certificate and does not directly involve Docker configs at all, but
it sets up [the second part](#configure-the-nginx-container), where you store
and use the site certificate as a series of secrets and the Nginx configuration
as a config.
#### Generate the site certificate
Generate a root CA and TLS certificate and key for your site. For production
sites, you may want to use a service such as `Lets Encrypt` to generate the
TLS certificate and key, but this example uses command-line tools. This step
is a little complicated, but is only a set-up step so that you have
something to store as a Docker secret. If you want to skip these sub-steps,
you can [use Let's Encrypt](https://letsencrypt.org/getting-started/) to
generate the site key and certificate, name the files `site.key` and
`site.crt`, and skip to
[Configure the Nginx container](#configure-the-nginx-container).
1. Generate a root key.
```bash
$ openssl genrsa -out "root-ca.key" 4096
```
2. Generate a CSR using the root key.
```bash
$ openssl req \
-new -key "root-ca.key" \
-out "root-ca.csr" -sha256 \
-subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA'
```
3. Configure the root CA. Edit a new file called `root-ca.cnf` and paste
the following contents into it. This constrains the root CA to only be
able to sign leaf certificates and not intermediate CAs.
```none
[root_ca]
basicConstraints = critical,CA:TRUE,pathlen:1
keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
subjectKeyIdentifier=hash
```
4. Sign the certificate.
```bash
$ openssl x509 -req -days 3650 -in "root-ca.csr" \
-signkey "root-ca.key" -sha256 -out "root-ca.crt" \
-extfile "root-ca.cnf" -extensions \
root_ca
```
5. Generate the site key.
```bash
$ openssl genrsa -out "site.key" 4096
```
6. Generate the site certificate and sign it with the site key.
```bash
$ openssl req -new -key "site.key" -out "site.csr" -sha256 \
-subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'
```
7. Configure the site certificate. Edit a new file called `site.cnf` and
paste the following contents into it. This constrains the site
certificate so that it can only be used to authenticate a server and
can't be used to sign certificates.
```none
[server]
authorityKeyIdentifier=keyid,issuer
basicConstraints = critical,CA:FALSE
extendedKeyUsage=serverAuth
keyUsage = critical, digitalSignature, keyEncipherment
subjectAltName = DNS:localhost, IP:127.0.0.1
subjectKeyIdentifier=hash
```
8. Sign the site certificate.
```bash
$ openssl x509 -req -days 750 -in "site.csr" -sha256 \
-CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
-out "site.crt" -extfile "site.cnf" -extensions server
```
9. The `site.csr` and `site.cnf` files are not needed by the Nginx service, but
you will need them if you want to generate a new site certificate. Protect
the `root-ca.key` file.
#### Configure the Nginx container
1. Produce a very basic Nginx configuration that serves static files over HTTPS.
The TLS certificate and key will be stored as Docker secrets so that they
can be rotated easily.
In the current directory, create a new file called `site.conf` with the
following contents:
```none
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /run/secrets/site.crt;
ssl_certificate_key /run/secrets/site.key;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
```
2. Create two secrets, representing the key and the certificate. You can store
any file as a secret as long as it is smaller than 500 KB. This allows you
to decouple the key and certificate from the services that will use them.
In these examples, the secret name and the file name are the same.
```bash
$ docker secret create site.key site.key
$ docker secret create site.crt site.crt
```
3. Save the `site.conf` file in a Docker config. The first parameter is the
name of the secret, and the second parameter is the file to read it from.
```bash
$ docker config create site.conf site.conf
```
List the configs:
```bash
$ docker config ls
ID NAME CREATED UPDATED
4ory233120ccg7biwvy11gl5z site.conf 4 seconds ago 4 seconds ago
```
4. Create a service that runs Nginx and has access to the two secrets and the
config.
```bash
$ docker service create \
--name nginx \
--secret site.key \
--secret site.crt \
--config source=site.conf,target=/etc/nginx/conf.d/site.conf \
--publish 3000:443 \
nginx:latest \
sh -c "exec nginx -g 'daemon off;'"
```
Within the running containers, the following three files now exist:
- `/run/secrets/site.key`
- `/run/secrets/site.crt`
- `/etc/nginx/conf.d/site.conf`
5. Verify that the Nginx service is running.
```bash
$ docker service ls
ID NAME MODE REPLICAS IMAGE
zeskcec62q24 nginx replicated 1/1 nginx:latest
$ docker service ps nginx
NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
nginx.1.9ls3yo9ugcls nginx:latest moby Running Running 3 minutes ago
```
6. Verify that the service is operational: you can reach the Nginx
server, and that the correct TLS certificate is being used.
```bash
$ curl --cacert root-ca.crt https://0.0.0.0:3000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```
```bash
$ openssl s_client -connect 0.0.0.0:3000 -CAfile root-ca.crt
CONNECTED(00000003)
depth=1 /C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
verify return:1
depth=0 /C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
verify return:1
---
Certificate chain
0 s:/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
i:/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
---
Server certificate
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
subject=/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
issuer=/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
---
No client certificate CA names sent
---
SSL handshake has read 1663 bytes and written 712 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID: A1A8BF35549C5715648A12FD7B7E3D861539316B03440187D9DA6C2E48822853
Session-ID-ctx:
Master-Key: F39D1B12274BA16D3A906F390A61438221E381952E9E1E05D3DD784F0135FB81353DA38C6D5C021CB926E844DFC49FC4
Key-Arg : None
Start Time: 1481685096
Timeout : 300 (sec)
Verify return code: 0 (ok)
```
7. Unless you are going to continue to the next example, clean up after running
this example by removing the `nginx` service and the stored secrets and
config.
```bash
$ docker service rm nginx
$ docker secret rm site.crt site.key
$ docker config rm site.conf
```
You have now configured a Nginx service with its configuration decoupled from
its image. You could run multiple sites with exactly the same image but
separate configurations, without the need to build a custom image at all.
### Example: Rotate a config
To rotate a config, you first save a new config with a different name than the
one that is currently in use. You then redeploy the service, removing the old
config and adding the new config at the same mount point within the container.
This example builds upon the previous one by rotating the `site.conf`
configuration file.
1. Edit the `site.conf` file locally. Add `index.php` to the `index` line, and
save the file.
```none
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /run/secrets/site.crt;
ssl_certificate_key /run/secrets/site.key;
location / {
root /usr/share/nginx/html;
index index.html index.htm index.php;
}
}
```
2. Create a new Docker config using the new `site.conf`, called `site-v2.conf`.
```bah
$ docker config create site-v2.conf site.conf
```
3. Update the `nginx` service to use the new config instead of the old one.
```bash
$ docker service update \
--config-rm site.conf \
--config-add source=site-v2.conf,target=/etc/nginx/conf.d/site.conf \
nginx
```
4. Verify that the `nginx` service is fully re-deployed, using
`docker service ls nginx`. When it is, you can remove the old `site.conf`
config.
```bash
$ docker config rm site.conf
```
5. To clean up, you can remove the `nginx` service, as well as the secrets and
configs.
```bash
$ docker service rm nginx
$ docker secret rm site.crt site.key
$ docker config rm site-v2.conf
```
You have now updated your `nginx` service's configuration without the need to
rebuild its image.