You need to hand a service a config file without baking it into the image, and docker config is how a Swarm does that. This guide creates a config from a small file, checks its name and labels, inspects its metadata, and removes it cleanly. The examples use Docker Community CLI 29.8.1 installed with docker-ce-cli. Allow about ten minutes, plus time to reach a Swarm manager if your host is not already configured.
docker config manages cluster objects, so the commands need a Docker endpoint connected to a Swarm manager. A worker-only engine, or an engine with no active Swarm, is not enough.
sudo; add it only if your administrator requires elevated access.docker context show
docker version --format '{{.Client.Version}}'
docker info --format '{{.Swarm.LocalNodeState}} {{.Swarm.ControlAvailable}}'
Checkpoint: The version check should print 29.8.1 on the machine covered here. If Swarm is inactive, stop and connect to a manager endpoint before creating anything.
Create a temporary file with a harmless setting. It is input to the next command. The config object remains in the Swarm after the file is removed, so use a name unique to this exercise.
config_file="$(mktemp)"
trap 'rm -f "$config_file"' EXIT
printf '%s\n' 'log_level=info' > "$config_file"
cat "$config_file"
Expected output:
log_level=info
Warning: Do not put passwords, private keys or other secret material in a Swarm config. This command is for configuration data, not a replacement for docker secret.
Avoid pointing at an important existing file until you have checked the destination name and context.
Choose a name and create the object from the file. The final argument is the file path. Using - instead makes Docker read content from standard input.
config_name="demo-log-settings"
docker config create \
--label env=dev \
--label owner=operator \
"$config_name" "$config_file"
A successful command prints a long config ID, such as q5s5570vtvnimefos1fyeo2u2. The ID differs on every Swarm.
Filter by the name you selected. This keeps a busy cluster readable and prevents a nearby object being mistaken for this one.
docker config ls --filter "name=${config_name}"
docker config ls --format '{{.ID}} {{.Name}} {{.CreatedAt}}' \
--filter "name=${config_name}"
The first command normally shows ID, NAME, CREATED and UPDATED columns. The second emits one compact line. The local manpage documents table as the default format, JSON as an available format, and -q or --quiet for IDs only.
Labels help with later selection. Verify them with inspection:
docker config inspect --format '{{json .Spec.Labels}}' "$config_name"
docker config ls --filter 'label=env=dev' --format '{{.Name}}'
Expected label output includes both values:
{"env":"dev","owner":"operator"}
docker config inspect accepts a name or ID and returns a JSON array by default. It includes the ID, version index, timestamps, name, labels and encoded data. The encoded data is not an editing interface.
docker config inspect "$config_name"
docker config inspect --pretty "$config_name"
docker config inspect --format '{{.ID}} {{.Spec.Name}}' "$config_name"
--pretty: human-friendly output.Destructive action: Removal is immediate and does not ask for confirmation. Compare the name or ID with the earlier list output before running it.
docker config inspect --format '{{.ID}} {{.Spec.Name}}' "$config_name"
docker config rm "$config_name"
Success prints the removed config ID. Confirm the name is gone:
docker config ls --filter "name=${config_name}"
docker config inspect "$config_name"
Checkpoint: The list should be empty, and inspect should fail because the object no longer exists.
Recovery: If an active service references the config, Docker may refuse removal. Find that service and remove or update it first, taking account of the resulting workload change.
docker context show before changing cluster state.docker info.docker config rm has no confirmation prompt. Keep the original source and labels if you may need to recreate it.ls and inspect.