Docker Engine exposes a REST API which you can use to control your containers without the docker CLI. The API exposes equivalent functionality using HTTP network calls. You can script common Docker operations using your favorite programming language or remotely control one of your hosts. The CLI internally relies on the same API to provide its built-in commands.
In this article we’ll look at the basics of enabling and using the API. If you’ve got a specific use case in mind, refer to the API reference documentation to identify the endpoints you need.
Enabling Docker Engine’s API
The API is integrated with Docker Engine. Any functioning Docker host is already primed to cater for API interactions. To expose the service, you need to bind the Docker daemon to a TCP socket as well as, or instead of, the default Unix socket. Start dockerd with the -H flag to specify the sockets to listen on:
This command exposes the API on port 2375. The default Unix socket is retained so the Docker CLI will continue functioning without any reconfiguration. Port 2375 is used for Docker by convention; feel free to change it to suit your environment.
You can make Docker always start with these settings by editing its systemd service configuration file. Edit or create /etc/systemd/system/docker.service.d/options.conf, find the ExecStart line, and modify it to include your extra flags:
Reload your systemd configuration to apply the change:
Now you’re ready to interact with the Docker Engine API on 127.0.0.1:2375.
A Note On Security
The steps above expose the API with no protection whatsoever. Anyone with access to port 2375 on your host can send arbitrary commands to the Docker daemon, starting new containers, filling your disk with images, or destroying existing workloads.
You should set your firewall to block connections to the port unless you’re intentionally exposing Docker on your network. If you do want to enable remote access, you should configure TLS for the daemon socket to limit access to authenticated clients.
When TLS is enabled you’ll need to install your daemon’s certificate authority on each of your clients. You’ll have to supply the client certificate and client key with each request you make. The steps to take will depend on the tool you’re using. Here’s an example for curl:
You might not need to bind a TCP socket at all depending on your use case. If your client supports Unix sockets, you could use Docker’s existing one to make your connections:
This can be a safer choice than risking unintentional exposure of a TCP socket.
Using the API
The API uses versioned endpoints so you can pin to specific versions of request and response formats. You must indicate the version you’re using at the start of each endpoint URL. v1.41 is the latest release present in production Docker builds at the time of writing.
API endpoints are grouped into REST functional units. These map to Docker’s fundamental object types such as containers, images, and volumes. You can usually find the APIs for a specific object type within the base URL that starts with its name:
The API uses JSON for all data exchanges with your HTTP client. Endpoints accept JSON request bodies and issue JSON responses in return. This should simplify data handling inside your applications as you can use the JSON library included with your programming environment. Tools like jq can be used to condense, filter, and sort responses if you’re experimenting in your terminal.
Common Endpoints
As the API replicates the functionality of Docker’s CLI, there’s too many possible endpoints to cover them all here. Instead we’ll demonstrate a few of the most commonly used options relating to Docker’s core functionality.
Listing Containers
The complete list of containers on the host can be obtained from the /containers/json endpoint:
It defaults to surfacing only running containers. Add all=true to the query string to include stopped containers too. Limit the total number of containers returned with the limit parameter, such as limit=10. Only the 10 most recently-created containers will be included.
Several different filters are available to prune the list to containers with particular attributes. These are set with the following syntax:
This URL returns the information associated with the demo container. Other filters can be expressed in a similar way such as {“status”:[“running”,“paused”]} to get running and paused containers or {“health=[“healthy”]} for only healthy containers.
Starting a New Container
Starting a container is a two-stage process when using the API. First you need to create the container, then start it in a separate API call.
Create your container by making a POST request to the /containers/create endpoint. This needs a JSON body with fields that correspond to the flags accepted by the docker run CLI command.
Here’s a minimal example of creating a container:
The JSON response will include the new container’s ID and any warnings arising from its creation. Send the ID in a call to the /containers/:id/start endpoint:
The container will now be running on the Docker host.
Cleaning Up Containers
Remove stopped containers by issuing a POST request to the /containers/prune endpoint:
You’ll be issued a JSON response with ContainersDeleted and SpaceReclaimed fields. ContainersDeleted is an array of the container IDs that were successfully removed. SpaceReclaimed informs of you the total storage space freed in bytes.
This endpoint accepts two query string parameters to constrain the operation. The until parameter limits the deletion to containers created before a given time, such as until=10m or until=2022-03-01. The label option filters to containers with or without given labels; setting label=demo=example will only remove containers with the demo=example label.
Listing Images
The /images/json endpoint is used to enumerate the images stored on the Docker host:
You can use filters to alter the contents of the response. These are supplied as a JSON object in the filters query string parameter, similarly to the container list API. One noteworthy option is reference which selects the image with a given tag: filters={“reference”:“hello-world:latest”}.
Building Images
You can use the API to build new Docker images from Dockerfiles. The /build endpoint should be sent a tar archive. The contents of this archive will be used as the image’s build context. The archive should include Dockerfile containg the instructions for the build.
The command above will send context.tar to the Docker daemon and build an image using the Dockerfile within. The image will be tagged as example-image:latest and stored on the Docker host.
This endpoint accepts many additional query string parameters that match the functionality of the docker build CLI. These include dockerfile=path/to/dockerfile, to specify the path to the build context’s Dockerfile, rm=true, which deletes intermediate containers created by the build, and pull=true to try and acquire updated versions of images referenced by the Dockerfile.
The API requires your client stay connected until the build completes. The build will be cancelled if the network drops and the connection is closed.
Listing Daemon Event Logs
The /events API surfaces the daemon event log data that’s also accessible with the docker events CLI command. This endpoint streams events in real-time as they happen.
Several different kinds of event are exposed including container creations, image tags, volume mounts, and network changes. You can filter to a specific kind of event using the type field of the filters query parameter:
It’s also possible to constrain to events relating to a specific object:
Two other query string parameters, since and until, let you specify a timestamp range to surface historical events within.
Getting System Information
The Docker Engine API can be used to get information about the physical host it’s running on:
This endpoint provides extensive details describing the current state and configuration of the host and Docker daemon. Fields in the response include counts of the number of running, paused, and stopped containers, the path to Docker’s installation directory, hardware and OS details, and the server’s Swarm configuration when it’s operating within a cluster.
Conclusion
The Docker Engine API gives you a way to send commands to your host’s Docker daemon over HTTP. This makes it simpler to script programmatic interactions without becoming reliant on specific Docker CLI behaviors. The API can also be used to remotely manage your Docker servers for enhanced monitoring and ease of maintenance.
While calling the API should be straightforward, you need to pay attention to the security protections around your TCP socket. Avoid exposing the socket on your network unless it’s secured with TLS so only approved clients can connect. Omitting this extra set up stage could prove costly if an intruder discovers your daemon instance and begins issuing commands.
You can make it even easier to use the API within your own applications by adopting one of the SDKs. Either an official or community-provided option is available for all popular programming languages, including C, C#, C++, Go, Java, NodeJS, PHP, Python, and Ruby. The SDKs wrap the API’s endpoints in convenient classes and functions to call from your code, reducing the amount of boilerplate needed to interact with a Docker installation.