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
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
copy code above to Vagrantfile
and one done run command:
vagrant up
Notes:
- you need to be
cd
ed at the same folder where you have created theVagrantfile
- 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:
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
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
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
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
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
We should test whether the configuration has worked or not, thus:
docker run -d hello-world
curl localhost:2375/v1.41/images/json
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 enginev1.41
is api version, which is provided by docker documentaionimages
is something called endpoint. Consider it to be a table name, which obviously lists names of images currently located on the hostjson
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
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/;
}
}
Each configuration change requires restart, thus:
sudo systemctl restart nginx
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}]
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"
- To create container instance:
curl "http://localhost/containers/create" -X POST -H "Content-Type: application/json" -d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}'
- this command should have output of hash-id of ready container:
{"Id":"105afe820928621621a5cfc133b98d1fab9419709fa6e0eea6a5a5822cd5dcf7","Warnings":[]}
- Start the container
curl -X POST http://localhost/containers/105afe8209/start
# the hash is output from previous command
- List the container running
curl -X POST http://localhost/containers/json
- List the container running
curl -X POST http://localhost/images/json
In cases where we need to stop container
curl -X POST http://localhost/containers/105afe8209/stop
Print the logs of a specific container
curl -X POST http://localhost/containers/105afe8209/logs?stdout=1
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)