Tools that we will use
Docker
Docker is a simple and elegant library for creating lightweight, isolated from each other virtual containers in which you can execute any code. It is not demanding at all resources, minimum overhead.
Having collected the container once, it can be reused.
A simple example is the Redis DB. If we need several Redis servers on the same computer, with the usual approach we will have to change the configuration files in / etc / redis and change the files in /etc/init.d. You can write a bash script, but this does not make the process easier.
In the case of Docker, we can use the following command:
')
docker run -d --name test-redis-server dockerfile/redis
This command will download the Redis container from the main repository (
index.docker.io ), run it in the background and give the newly created container the name test-redis-server.
This container can be run later with the command:
docker start test-redis-server
Skydns
More recently, Docker developers have introduced the --link tool when launching a container so that several containers can be linked using ENV environment variables. For example, to associate a web application container with Redis, Postgresql, Elasticsearch containers, etc.
This is convenient, but we need to monitor the accuracy of the ENV and change the code when changing the conditions of the launch containers and the parameter --link.
This is called Service Discovery, for it there are many solutions (for more information about existing solutions, you can read the article
Open-Source Service Discovery ).
One of these solutions is SkyDNS. A small local DNS and DNS proxy server written in the Go language (it is important to note that Go is extremely effective in terms of resource consumption, up to about 6MB of memory at startup. I personally conducted several synthetic tests for myself, the maximum memory consumption for 50 simultaneous simple queries was about 20MB).
SkyDNS allows you to add DNS records using a simple API (in more detail:
SkyDNS ), and then make regular queries that return SRV, A or AAAA records.
If the record is not found, SkyDNS will send a request to google public dns (8.8.8.8/8.8.4.4).
SkyDNS uses its own interesting domain scheme:
<uuid>.<host>.<region>.<version>.<service>.<environment>.skydns.local
If environment = production, and service = redis, then you can make a request to
redis.production.skydns.local , which will return one or more records (by default, it returns A record).
Skydock
Skydock is a small program that combines Docker and SkyDNS.
Skydock uses the SkyDNS domain scheme as follows:
<name>.<container-name>.<environment>.skydns.local
ontainer-name is the name of the Docker image without a repository (for example, crosbymichael / redis => redis or test / cool-api => cool-api).
name is the name of the container assigned to it using the --name parameter.
Skydock automatically detects running containers and adds them to SkyDNS.
Docker assigns a separate IP address for each container, therefore if we launch the container as follows:
docker run -d --name redis-test-app dockerfile/redis
We will be able to make a request (later it will be described why we make a request for 172.17.42.1) and we will receive in response A record, that is, the IP address of the container in which Redis is running.
dig @172.17.42.1 redis-test-app.redis.dev.skydns.local dev.skydns.local. 27 IN A 172.17.0.3
The default Redis port is 6379, so in the code we can do something like this (pseudo-language example):
redisConn = redis.Connect("redis-test-app.redis.dev.skydns.local:6379")
Installation
We will not consider the installation of Docker, it is very simple and described in detail here:
Start using DockerWe need to launch 2 containers - one with SkyDNS, the other with Skydock. Unlike Skydock, I recommend running SkyDNS with the additional option -p 172.17.42.1:8080:8080 - this will allow your containers to use the SkyDNS API directly for their own needs.
docker pull crosbymichael/skydns docker run -d -p 172.17.42.1:53:53/udp -p 172.17.42.1:8080:8080 --name skydns crosbymichael/skydns -nameserver 8.8.8.8:53 -domain skydns.local
IP 172.17.42.1 is the docker0 bridge, used by Docker to configure its own network. We specified the skydns.local domain, although you can do any of your choice, for example, docker, super.local. In my opinion, skydns.local is more convenient and versatile, especially since it is used by default in SkyDNS.
Next, run Skydock:
docker pull crosbymichael/skydock docker run -d -v /var/run/docker.sock:/docker.sock --name skydock -link skydns:skydns crosbymichael/skydock -ttl 30 -environment dev -s /docker.sock -domain skydns.local
Here you need to specify the TTL (if it is smaller - more dynamic environments, you can make more changes to the architecture faster. If more - a less dynamic, more cached environment) and environment - this can be absolutely any line (dev, development, production, stage, qa ).
If everything went well, then all the necessary components are running.
The only thing that needs to be done is when launching the container with your application, you need to specify the primary DNS server:
docker run -d --dns 172.17.42.1 test/cool-api
Our cool-api container will be available in the local DNS at:
cool-api.dev.skydns.local - this will list the IP addresses of all containers called cool-api. This property we will use to configure nginx.
If you specify --name api1 when you start the container, it will be available at
api1.cool-api.dev.skydns.local - just 1 container with the name api1.
Inside the container, you can now specify the domain directly, since it will use the local DNS:
redis.dev.skydns.local - will return A records of all containers running Redis. Naturally, only 1 address will be selected to which the Redis client will connect.
nginx
I use this magic of local DNS, we can do for example:
- Load balancing - web server or database connections
- Simple routing of requests by criterion. For example, by creating an image test / cool-api-v1 - we can send requests to the API v1 to some containers ( cool-api-v1.dev.skydns.local ), and use cool-api.dev.skydns.local as the latest version. At the same time with automatic balancing
- Update code on the fly - what we need
Add this configuration file to nginx:
server { listen 80; server_name super-cool-domain.com;
We simply specify that nginx use the local DNS server, then specify where to go - the $ dns variable and do the good old proxy_pass to the port that your application uses.
Now, when launching a new container, Skydock will add it to SkyDNS, nginx will proxy requests to this container. When the container is stopped, Skydock will delete its address from SkyDNS.
By launching 2-3 containers in this way, we can balance the load between them.
We will launch several additional containers, nginx will automatically start proxying requests to them. After that, we can stop the work of the old - thereby making an update on the fly.
This will not require reconfiguration. Everything works by default. In essence, all you need to do to change the code is:
Conclusion
The author Skydock wants to develop the idea and make support for multiple servers in the data center. At the moment, this is not implemented, although SkyDNS itself is already used in the production environment on multiple servers.
The article also does not address the topic of docker repositories. There is an open source solution that allows you to create a private image repository.
The solution has almost no effect on performance, Docker and SkyDNS are very well designed and use the effective and fast language Go.
At first glance, this seems to be a somewhat complicated process, but the result is a very flexible solution that does not need to be further configured after the initial setup.