docker swarm container communication - docker

I create a swarm and join a node, very nice all works fine
docker swarm init --advertise-addr 192.168.99.1
docker swarm join --token verylonggeneratedtoken 192.168.99.1:2377
I create 3 services on the swarm manager
docker service create --replicas 1 --name nginx nginx --publish published=80,target=80
docker service create --replicas 1 --name php php:7.1-fpm published=9000,target=9000
docker service create --replicas 1 --name postgres postgres:9.5 published=5432,target=5432
All services boots up just fine, but if I customize the php image with my app, and configure nginx to listen to the php fpm socket I can’t find a way to communicate these three services. Even if I access the services using “docker exec -it service-id bash” and try to ping the container names or host names (I even tried to curl them).
What I am trying to say is I don’t know how to configure nginx to connect to fpm since I don’t know how one container communicates to another using swarm. Using docker-compose or docker run is simple as using a links option. I’ve read all documentation around, spent hours on trial and error, and I just couldn’t wrap my head around this. I have read about the routing mesh, wish will get the ports published and it really does to the outside world, but I couldn’t figure in wish ip its published for the internal containers, also that can't be an random ip as that will cause problems to manage my apps configuration, even the nginx configurations.

To have multiple containers communicate with each other, they next to be running on a user created network. With swarm mode, you want to use an overlay network so containers can run on multiple hosts.
docker network create -d overlay mynet
Then run the services with that network:
docker service create --network mynet ...
The easier solution is to use a compose.yml file to define each of the services. By default, the services in a stack are deployed on their own network:
docker stack deploy -c compose.yml stack-name

Or you can just make 1 Docker-compose, and make a docker stack with them.

It's easier and more reliable to combine php_fpm and nginx in the same image. I know this goes against the official way of single-app images, but for cases like php_fpm+nginx where you must have both to return a request, it's the best case. I have a WIP sample here: https://github.com/BretFisher/php-docker-good-defaults

Related

Docker container talks to docker container in the same local host? [duplicate]

This question already has answers here:
accessing a docker container from another container
(8 answers)
Closed 1 year ago.
I am in a confusion right now. I try many things I can find on the web, but, none solved it. I have Win10 and Docker desktop installed using WSL 2 to host Linux containers. I use the following command to start the Jenkins website.
docker run --name jenkins-master-c -d -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:2.282-alpine
This works fine. I can access the website using http://localhost:8080/
The problem is, I try to curl http://localhost:8080 from another alpine docker container, but, I am not getting the web page back, it said connection refused. I tried my own tiny web service on my Windows machine without docker. Same thing. I can access the web service using web browser on Windows 10. However, if I get inside a container, I couldn't access the web service on the localhost.
I know I am missing some thing really basic, because the web doesn't seem to have this topic. I am just on my own computer without anything fancy. Thus, I just want to use localhost. The web said the default is supposed to use bridge which the container should talk to each other easily, but, it is not working for me. What am I missing. Maybe I shouldn't type localhost? But, what else should I do?
thank you
Edit: just want to explain what I did to get my problem solved. The creating network --network my-network-name was what I originally did, which failed because the way I curl the webpage is wrong. I did --name jenkins-master-c only to make it easy locate my container on the docker ps. But, as pointed out in my question, I suspected the localhost is wrong, which is confirmed by the solution. Instead of using localhost, I do curl http://jenkins-master-c:8080 which worked. Thanks
localhost is always a question of perspective, it refers to the current machine. This means if you call localhost from a container it speaks to himself and not the machine you see as localhost. If you want to call a service running on this one you have to use its real IP address.
You can imagine that docker containers are individual virtual machines, they have their own localhost. And they are isolated from your host pc and other containers.
Now if you want to communicate among two or more docker containers then you can use bridge network. In docker perspective, a bridge network allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network. You can see the docker doc for bridge network.
On the other hand, if you want to communicate with your docker container from your host then you need to fort-forward for opening/exposing a port to connect with the container (which you did in -p 8080:8080)
Another way you can bring your containers under a local host is using kubernetes, in kuernetes you can run one or more containers in a pod and then they will share same network space. kubernetes pod
Probably these two containers are not in the same network, you they cannot see and talk to each other.
First of all, create a network by docker command docker network create SOMENAME, and then run containers again (both of them):
docker run --name jenkins-master-c --network SOMENAME -d -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:2.282-alpine
Now it should talk to another docker container.

Installing 2-node cluster of MarkLogic in docker

I'd like to install MarkLogic in docker and form a cluster i.e. two or more ML nodes instance running on the same machine. How to achieve that ?
In the Building a MarkLogic Docker Container blog entry, it describes how to create and initialize a Docker image running MarkLogic.
Near the bottom of the article, it describes how to link multiple containers using the --link switch and docker-compose to assist in managing a cluster of Docker containers:
Linking Containers
You are the one who tells Docker how containers should communicate! When using the docker run command, you can also pass in a --link flag.
Consider the following examples:
docker run -d --name=marklogic1 --hostname=marklogic1.local -p 8000-8002:8000-8002 marklogic:8.05-preinitialized
docker run -d --name=marklogic2 --hostname=marklogic2.local --link marklogic1:marklogic1 -p 18000-18002:8000-8002 marklogic:8.05-preinitialized
The above creates two MarkLogic containers. The second has the --link flag. Docker networking sets environment variables and the /etc/hosts file inside each container being linked along and also the linking container. This sets up the ability for Docker containers to communicate over the internal Docker network. The --hostname flag is used to be consistent with MarkLogic, which uses the full domain name when contacting other MarkLogic servers in the cluster. So we simply add the .local domain to the name of the container.
Finally, note the -p flag on the second container exposes the MarkLogic’s ports in the range of 8000 to 8002 to the host computer’s ports of 18000 to 18002. Why not use the host computer’s ports of 8000 to 8002? Because the first container is already using them. Remember, Docker shares networking with the host computer! But of course, you can choose any range of open ports on your host computer to map the container’s MarkLogic ports.
Now, simply point your browser to port 8001 in the first container (marklogic1) and go through the post-installation steps. Skip joining a cluster. When finished, point your browser to port 18001 for the second container (marklogic2) and go through the post-installation steps. When asked to join a cluster, simply use the host name of localhost and leave the port number at 8001. MarkLogic in the second container will contact MarkLogic in the first container. The configuration will be updated such that the marklogic2 joins the cluster with marklogic1. Create and add a third MarkLogic container, also linking it to marklogic1:marklogic1 and marklogic2:marklogic2 and you’ll soon have a proper 3-node MarkLogic cluster!
Using docker-compose
Docker has created another tool to aid in managing clusters of Docker containers. docker-compose has commands to create multiple containers and network them together. You can then create them, start them and stop them using docker-compose commands. Docker uses a file called Dockerfile to build containers. docker-compose uses a file called docker-compose.yml to build networks of containers.
docker-compose is available as a separate download.

best practices for deploying nginx

I am totally new in the cloud stuff, I wanted to deploy my application which using node,MongoDB and redis. all these parts become a docker container and working well together.
now I want to set up nginx. I wonder what is the best practice for deploying load balancers? should I run nginx as docker container? or just install it in system level?
I think it depends on how many services you want to serve with your nginx instance. For example, since you can have only one nginx instance bound to the 80 and 443 ports, if you want to share the same SAP between different domains I would go for nginx running on the host (or in a dedicated stack but it looks complex). If you use the SAP for a single domain then it makes perfect sense to have it inside the stack.
If you are running other components of the stack on containers , then it makes sense to run nginx as container as well.
But it depends on your environment , what tools are available. You can scale nginx on kubernetes easily , as well as on docker swram or any other tool of your choice.
Ideally you need to run each compenent in a separate container so that you can manage and scale and troubleshoot them independently.
It's a really good idea to embed an nginx in your docker network. As a docker container, in a docker network, it could connect to other by their service/container name, while you will define port forwarding rule only on the nginx service.
For example :
docker network create --driver overlay --attachable demo
docker run -d -p 80:80 --network demo --name nginx nginx
docker run -it --network demo --name alpine alpine
Your shell should be in the alpine container. Do a "ping nginx". You should be able to ping it. The opposite is possible too.
So now, you have at localhost:80 (from your host machine) a nginx deployed, which can call other containers with their container/service name. Really useful to have an access point to your web-apis deployed in your docker network.

access all instances of docker swarm

We're starting to implement docker swarm or some of the parts of our application. One of these parts is a web socket server which allows us to push "live" content to a particular user.
My question is - if I want to make a rest call to particular container, and not a load balanced one on the overlay network - is that possible? If so, how would I go about doing it?
Thanks
Ben
If I understood your use case correctly, the following example might help you started.
Given an overlay network and a service with several replicas:
docker network create --driver overlay --attachable nginx
docker service create --name nginx --network nginx --replicas 3 nginx:alpine
You can run a container attached to the nginx network:
docker run --rm -it --network nginx alpine:edge ash
Inside that container you can find all tasks for the service like this:
apk add -U drill
drill tasks.nginx
The response should contain something similar to this:
...
;; ANSWER SECTION:
tasks.nginx. 600 IN A 10.0.1.3
tasks.nginx. 600 IN A 10.0.1.4
tasks.nginx. 600 IN A 10.0.1.5
...
You don't really need the attachable network and the single container, though. Alternatively you could also create another service in the same network like nginx and let that service perform the tasks.<service-name> lookup to perform the actions to need.

docker-compose.yml to start containers on multiple VM's

I have created Docker containers using docker-compose.yml on a single host.
Can anybody tell if docker-compose.yml file can be used to start Docker containers on multiple VMs ? If yes, how?
The compose file cannot be used with the new Docker "Swarm Mode" introduced in June (Docker 1.12). The "legacy" Docker Swarm accepts compose files but you should really focus on learning Docker "Swarm Mode", not the old Docker Swarm. It's much simpler too, except for the missing support for compose files.
"swarm mode" accepts dab files and there is a way to convert compose files to dab, but it's experimental (which means that a lot of what you have put in your compose file won't translate). So the current best way is to create bash scripts with the CLI commands eg: docker service create --name nginx nginx:1.10-alpine.
and do have look at #Matt 's link about learning the basics of Docker swarm mode. http://docs.docker.com/engine/swarm/key-concepts
You can quickly spin up a stack swarm from the external containers and a node list (by ip like 10.0.0.1 or hostname like nodeb):
docker run -d -P --restart=always --name swarm-manager swarm manager \
"nodes://10.0.0.1:2376,nodeb:2376,nodec:2376"
export DOCKER_HOST=$(docker port swarm-manager 2375)
docker-compose up
Before running this, you'd need to configure the engines to listen on 2376 with TLS configured, a client key/certificate, and the appropriate network access. See docker's documentation on TLS for more details on configuring this.

Resources