DEV Community

Cover image for Gateway To Docker API Engine
Alex M. Schapelle for Otomato

Posted on

Gateway To Docker API Engine

Welcome back gentle reader. Many thanks for your return to refine your wisdom. My name is Silent-Mobius, also known as Alex M. Schapelle, your dedicated storyteller.
In today's query I'd like to talk about containers and a very specific way of using them: accessing via http protocol to Nginx reverse-proxy that redirects request to docker engine's internal API.

This short projects demonstrates the same idea, but with much simpler execution with Nginx reverse-proxy sending http requests to docker engine, in order to start required specific container.

The motivation

I believe, you remember my mazin-docker project in which I've developed flask based RestAPI application that can run multi-container environment which you'd prefer to use instead of complex tool like #k8s.
The motivation was to implement something in the most easiest way possible, and thus this tutorial was born.

Before we start

Not everything is fruit of my imagination, and some of things that I work on, are thanks to small team of people that work with me, and in this case, I'd like to thank @antweiss for guidance on this small project. Thanks!

Plan of work

To begin our short adventure, We'll start by making small choices as follows:

  • Get and install Debian based system. You may set it up with Virtualbox, KVM, AWS, Linode or Digital-Ocean. Choice is up to you.
  • We'll install Nginx and #docker on that Debian based system
  • Add configuration for both installed tools
  • Test the access to docker API via Nginx with HTTP
  • Append ssl configuration and test it as well

One question that might pop-up is: "what is the use case for this?" ->

Setup

Me being person of Infrastructure As Code (IaC), I prefer to test Proof Of Concepts (POC) in virtual environments, and this is where Virtualbox and Vagrant come in to play. Whether you are using Linux, Mac or Windows, these tools always are useful.
To install Virtualbox use this link. Download the executable and install on your system.

Note: you might need to enable virtualization in your computers BIOS/EUFI configuration check here
Vagrant IaC framework that uses virtual-box to download and run pre defined virtual appliances (zipped virtual operational systems) and create systems faster then doing it manually - install vagrant from here
Once these 2 are installed, let's setup our POC environment, by opening shell or powershell:

mkdir poc
cd poc
vagrant init # this will create file named Vagrantfile
echo ' ' > Vagrantfile # clearing the initial config
Enter fullscreen mode Exit fullscreen mode

Usually vagrant provides an initial template to setup virtual machines inside Vagrantfile, yet I prefer to provide you with my own version that configuration:

Vagrant.configure("2") do |config|
  config.vm.define "deb" do |deb|
    deb.vm.box = 'debian/bullseye64'
    deb.vm.network "private_network", ip: "192.168.56.4"
    deb.vm.hostname="debian"
    deb.vm.provider :virtualbox
   end
end
Enter fullscreen mode Exit fullscreen mode

copy code above to Vagrantfile and one done run command:

vagrant up
Enter fullscreen mode Exit fullscreen mode

Notes:

  • you need to be cded at the same folder where you have created the Vagrantfile
  • in case you are using windows, use notepad or notepad++ to edit the file from power-shell
  • for more info in regards to vagrant read here

The output should look like this:
vagrant up
Once the command runs, it will download Debian Linux distribution 11, with code name bullseye. The download will work with ova image, which is a standard format for packaging virtual appliances, to your device and will run it with virtualbox virtualization provider. It should take about 3 minutes, it also depends on your network connection, thus wait until there is no output from last command. Once done, you should connect to vm.

To connect to the virtual machine (vm), we use ssh command of vagrant:

vagrant ssh deb
Enter fullscreen mode Exit fullscreen mode

Mazal Tov !!! You are using IaC and are connected to remote machine.

Lets us finish installation by installing main software for which we came here for: Nginx and docker

sudo apt-get update && sudo apt-get install -y nginx
curl -L get.docker.com | sudo bash 
Enter fullscreen mode Exit fullscreen mode

Configuration

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

To expose the service, you need to bind the Docker daemon to a TCP socket as well as, or instead of, the default IP and port:

sudo vi /lib/systemd/system/docker.service 
Enter fullscreen mode Exit fullscreen mode

This is docker daemon service file where you should append -H tcp://127.0.0.1:2375 to line 13

It should look like this:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://127.0.0.1:2375
Enter fullscreen mode Exit fullscreen mode

Due to a fact of us editing service file, systemd daemon needs to be reloaded and docker service needs to be restart for the changes to be accepted, thus:

sudo systemctl daemon-reload
sudo systemcttl restart docker
Enter fullscreen mode Exit fullscreen mode

We should test whether the configuration has worked or not, thus:

docker run -d hello-world
curl localhost:2375/v1.41/images/json
Enter fullscreen mode Exit fullscreen mode

The curl should return json format file that contains details of hello-world image that we used command before this.

Notes:

  • localhost:2375 is a socket (combination of ip and port) that we enabled for docker engine
  • v1.41 is api version, which is provided by docker documentaion
  • images is something called endpoint. Consider it to be a table name, which obviously lists names of images currently located on the host
  • json is format in which the data is presented, AFAIK json is only format at the moment.

Although this works, but it still not what we wanted, thus lets configure other part of this project:

  • Let us configure the Nginx redirect from port 80 to 2375
echo ' ' > /etc/nginx/sites-enabled/default # removing default config
sudo vi /etc/nginx/sites-enabled/default
Enter fullscreen mode Exit fullscreen mode

Paste the default configuration as follows:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

  location / {
      proxy_pass http://127.0.0.1:2375/v1.41/;
    }

}
Enter fullscreen mode Exit fullscreen mode

Each configuration change requires restart, thus:

sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Now it is right time to test the changes from nginx point of view:

curl localhost
    {"message":"page not found"}
curl -s localhost/images/json
    [{"Containers":-1,"Created":1675917382,"Id":"sha256:3f8a00f137a0d2c8a2163a09901e28e2471999fde4efc2f9570b91f1c30acf94","Labels":{"maintainer":"NGINX Docker Maintainers <docker-maint@nginx.com>"},"ParentId":"","RepoDigests":["nginx@sha256:6650513efd1d27c1f8a5351cbd33edf85cc7e0d9d0fcb4ffb23d8fa89b601ba8"],"RepoTags":["nginx:latest"],"SharedSize":-1,"Size":141838619,"VirtualSize":141838619}]
Enter fullscreen mode Exit fullscreen mode

Docker API Use

The use of docker API, may be some what rigid and requires step by step guidance. To create running containers, steps are as follows:

  • Pull the image from the registry
  • Create the container instance id
  • Start container by id

Here are commands:

  • To pull image:
 curl -X POST "http://localhost/image/create?fromImage=alpine:latest"
Enter fullscreen mode Exit fullscreen mode
  • To create container instance:
curl "http://localhost/containers/create" -X POST  -H "Content-Type: application/json"  -d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}'
Enter fullscreen mode Exit fullscreen mode
  • this command should have output of hash-id of ready container:
{"Id":"105afe820928621621a5cfc133b98d1fab9419709fa6e0eea6a5a5822cd5dcf7","Warnings":[]}
Enter fullscreen mode Exit fullscreen mode
  • Start the container
curl -X POST http://localhost/containers/105afe8209/start
# the hash is output from previous command
Enter fullscreen mode Exit fullscreen mode
  • List the container running
curl -X POST http://localhost/containers/json
Enter fullscreen mode Exit fullscreen mode
  • List the container running
curl -X POST http://localhost/images/json
Enter fullscreen mode Exit fullscreen mode

In cases where we need to stop container

curl -X POST http://localhost/containers/105afe8209/stop
Enter fullscreen mode Exit fullscreen mode

Print the logs of a specific container

curl -X POST http://localhost/containers/105afe8209/logs?stdout=1
Enter fullscreen mode Exit fullscreen mode

Conclusion

As you can see, it there are lots done, yet to recap:

  • We created virtual machine
  • Installed Nginx and Docker
  • Opened docker api connection
  • Configured Nginx to pass commands to docker engine
  • Listed some of the api commands

That would be all, hope you found this article informative and educative. One last thing: Do Try To Have Some Fun

Top comments (0)