0

Background

I'm trying to maintain some websites running in a Docker Swarm. I want to do security updates on them.

In a non-Docker environment, like a VPS, my simple process is that I would connect in and git pull updates and run any database updates associated with these.

I want to do the same with websites that are running in a Docker Swarm as Docker Containers that belong to a respective Docker Service.

But it seems to be a disproportionate of effort to find the Docker commands to help me with this.

Specifically my question is:

If I know the Docker Service name or ID, what Docker command can I run to find out the IDs of all the containers to be able to connect into them.

The reason why I start with the Docker Service when I list them on the Docker master node, using docker service ls I get a "user friendly" list of services, which helps me pick out the particular service for the site to maintain, e.g.:

    $ docker service ls
    ID                  NAME                       MODE                REPLICAS            IMAGE                      PORTS
    sr2w12kl8bg1        site1_db                    replicated          1/1                 animage2/mariadb:latest        *:13306->3306/tcp
    e083ij8abje1        site1_drupal                replicated          1/1                 animage2/drupal:d7             *:7150->80/tcp
    sejb0f2mfo22        site1_drush                 replicated          0/1                 drush/drush:latest         
    kbae02doa8rs        site1_haproxy               replicated          2/2                 haproxy:alpine             
    khgmnu1566rb        site2_db                    replicated          1/1                 mariadb:latest             
    notoc1fam1gk        site3_drupal                replicated          1/1                 animage1/drupal:d8             *:7160->80/tcp
    0xtxx4jmmwa3        site4_db                    replicated          1/1                 mariadb:latest            

etc...

I can look at this list above, and pick out a line and say "that's the site".

So here's the blocker:

Having picked out a line, I've got an ID, say e083ij8abje1 for a service running Drupal.

Now I want to ssh into a Docker container inside that Docker Service to do the upgrade.

There's this command for ssh-ing into a Docker container:

docker exec -it <container_id> /bin/bash 

Where container is a Hexadecimal number e.g. a1b2c3d4ee8 so it would e.g. look like docker exec -it a1b2c3d4ee8 /bin/bash

But I don't have the Docker container ID, I have the Docker Service ID which is an alphanumeric number, as in the above example e083ij8abje1 - this won't work for the above docker exec command.

So I need a docker command that lists the Docker Container IDs that belong to a Docker Service.

To my surprise, there doesn't seem to be one!

I know I can also list the Docker Containers

$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
d5d45a94d45e        haproxy:alpine         "/docker-entrypoint.…"   3 days ago          Up 3 days                                    db_proxy_haproxy.2.91aw0apofd3iw537d249pyi62
6a4676df2b3a        22dbb7890585           "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site2_db.1.xxizdccg9a2hgf83tcgg1tkaej
538172a86a57        site1/drupal:asite      "docker-php-entrypoi…"  3 days ago          Up 3 days           80/tcp                   site3.1.uofsfssl72aj867r0hfs86i7m24linae8
2d487ea3788e        22dbb7890585           "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site4_db.1.3lnd0f9sl027f0skgza3kq373c0
d671069584d7        mariadb:latest         "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site5.1.xoy0r6720362hlkhksu2qd
beb6bcb66f43        mariadb:latest         "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site2.1.kobk423624kljfs1uhpflfs3

But this doesn't tell me what Service a Docker Container is running in. Neither command gives me the full information and that's frustrating.

Research done already

  • How to get container id of a docker service Various answers that don't seem to work for me and they are convoluted not simple commands, I'm using Docker 19.03

  • Swarm mode: getting Container ID from Task ID Nothing definitive here stands out. And they've introduced the idea of "Task" - what is that in relation to Docker, Service, Containe?

  • I also found several similar question / answers that were just wordy and pointing to the general documentation. Not very helpful as they don't show by example.

I'm trying my best to understand these concepts and have drawn a diagram below. ( Please confirm that Docker Containers belong to a Service. )

Yes, I understand that Docker Swarm is declarative and can allocate Containers where it decides are best, in terms of running them on a particular node. That seems to be the approach encountered whenever I've been trying to find this answer, answers seem to want to give too much information for the reader, when what the reader needs is specific practical examples, not loads of theory and concepts.

So to summarise what I am looking for is a simple command or 2 that enables me to:

  • list the Docker Containers by ID that belong to a Service, given the Service ID / name to start with
  • for a given Docker Container and ID, find out what Docker Service it belongs to.

I am aware about Docker Swarm end-of-life so don't want answers telling me to use something else. please.

How I think Docker is organised

1
+50

As a little addition to such extensive answer, with docker ps you can --filter containers by label. One of the labels in swarm is a service name, so:

docker ps --filter "label=com.docker.swarm.service.name=<service_name>"

Should give you service containers on current node. To find more labels for possible filters hit

docker  ps --format "table {{.Names}}\t{{ .Labels }}"
5
  • thank you @anemye ! I will check this out and feedback – therobyouknow Dec 11 '20 at 13:49
  • 1
    +1 upvote and accepted thank you @anemye ! This did the job anemye I just tried out your answer, mindful of the approaching bounty deadline, so you could have the bounty. Your answer reduces the steps from 6 to 3: the maximum I would now need are steps 1) 2) and 5). Step 2) is needed because I need to see which Docker Node in the Swarm that the service is on. Though with that I would image that further labels as you suggest would show me the node, too. Thanks again! – therobyouknow Dec 13 '20 at 20:31
  • The first command docker ps --filter "label=com.docker.swarm.service.name=<service_name>" only shows the headings. The second command docker ps --format "table {{.Names}}\t{{ .Labels }}" does seem to be useful: it looks like it shows service id associated with each docker container id on that node. This command is the best as it gives the container id for the service: stackoverflow.com/a/53633189/227926 though it doesn't show which node the container is on. – therobyouknow Dec 23 '20 at 11:30
  • 1
    The first command gives only headings when there are no containers that match <service_name>. It looks at the labels on each container and if one matches key=value given to the filter - it appears in the output. The second command is for you to see what other labels can be there. Some labels are there from swarm, other can be put via compose file or Dockerfile. I added this so that you can explore more options to use filter by label. – anemyte Dec 23 '20 at 13:35
  • +1 thank you @anemyte - yes: "The first command gives only headings when there are no containers that match <service_name>" - i.e. no containers on that Docker Swarm node that match <service_name> . So this is fine - my command in step 3) is equivalent to this. In actual fact, and to corroborate my earlier sentence, when I ran your command on a node where the container for the service was there, I got a container ID, as I would expect. So all fine - I stand corrected on my earlier comment about headings only. Thank you. – therobyouknow Dec 24 '20 at 21:42
1

Answering my own question & accepting it because it works - this is the solution:

Step 1: So I start by finding the Docker Service I recognise as my Drupal site "that's the site"

node1 $ docker service ls

As before, shown in the question, the output of that command is:

ID                  NAME                       MODE                REPLICAS            IMAGE                      PORTS
sr2w12kl8bg1        site1_db                    replicated          1/1                 animage2/mariadb:latest        *:13306->3306/tcp
e083ij8abje1        site1_drupal                replicated          1/1                 animage2/drupal:d7             *:7150->80/tcp
sejb0f2mfo22        site1_drush                 replicated          0/1                 drush/drush:latest         
kbae02doa8rs        site1_haproxy               replicated          2/2                 haproxy:alpine             
khgmnu1566rb        site2_db                    replicated          1/1                 mariadb:latest             
notoc1fam1gk        site3_drupal                replicated          1/1                 animage1/drupal:d8             *:7160->80/tcp
0xtxx4jmmwa3        site4_db                    replicated          1/1                 mariadb:latest

        

I pick out the site animage1/drupal:d8, second from bottom in the list above and find the corresponding Service ID, notoc1fam1gk

Step 2:

I use this, Service ID, notoc1fam1gk, to list all the tasks for that Service, by doing this command

node1 $ docker service ps notoc1fam1gk

The output of that command is:

ID                  NAME                 IMAGE                      NODE                DESIRED STATE       CURRENT STATE          ERROR               PORTS
yiofs723gc89        site3_drupal.1       animage1/drupal:d8         node2               Running             Running 6 days ago                         
pgdgf783ff9v         \_ site3_drupal.1   animage1/drupal:d8         node2               Shutdown            Shutdown 2 weeks ago                       
1gfdsgcb0p2q         \_ site3_drupal.1   animage1/drupal:d8         node2               Shutdown            Shutdown 2 weeks ago                       
175lfds2jbjy         \_ site3_drupal.1   animage1/drupal:d8         node2               Shutdown            Shutdown 2 weeks ago                       
qo312e143p1q         \_ site3_drupal.1   animage1/drupal:d8         node2               Shutdown            Shutdown 3 weeks ago    

               

Step 3:

Now for the crucial bit - I still don't have a Container ID to be able to ssh into.

So This command will do it for me:

docker inspect -f "{{.Status.ContainerStatus.ContainerID}}" <task_id>

( Credit: https://stackoverflow.com/a/42465558/227926 )

In my example, this looks like:

node1 $ docker inspect -f "{{.Status.ContainerStatus.ContainerID}}" yiofs723gc89

The output of the above command is just:

72d6a20c3d15dd9f0db4b1a60d93a91c0514946881f2dc00ca62d6a7a9ef1290

This is the container ID in the format of the 64 character SHA-256 ID.

But I'm familiar with the 12 character length Container IDs that docker ps shows.

The explaination is that the 12 character Container ID is just a truncated version of the full length 64 character ID - it takes the first 12 characters.

So in my case, 72d6a20c3d15dd9f0db4b1a60d93a91c0514946881f2dc00ca62d6a7a9ef1290 will be 72d6a20c3d15 in the 12 character format.

Step 4:

So now, when I docker ps on node1 to go looking for that container ID I can use the 12 character format for the ID, 72d6a20c3d15

I'm on my Docker Swarm Node node1 and I do a docker ps:

node1 $ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
d5d45a94d45e        haproxy:alpine         "/docker-entrypoint.…"   3 days ago          Up 3 days                                    db_proxy_haproxy.2.91aw0apofd3iw537d249pyi62
6a4676df2b3a        22dbb7890585           "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site2_db.1.xxizdccg9a2hgf83tcgg1tkaej
538172a86a57        site1/drupal:asite     "docker-php-entrypoi…"   3 days ago          Up 3 days           80/tcp                   site3.1.uofsfssl72aj867r0hfs86i7m24linae8
2d487ea3788e        22dbb7890585           "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site4_db.1.3lnd0f9sl027f0skgza3kq373c0
d671069584d7        mariadb:latest         "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site5.1.xoy0r6720362hlkhksu2qd
beb6bcb66f43        mariadb:latest         "docker-entrypoint.s…"   3 days ago          Up 3 days           3306/tcp                 site2.1.kobk423624kljfs1uhpflfs3

But 72d6a20c3d15 isn't in the list. Why is that?

Well, in my case it is on the node2 of my Docker Swarm. How do I know this?

I know because the earlier command docker service ps notoc1fam1gk listed the task as node2, so I know that this task's corresponding container will be on node2.

Step 5:

So I connect to node2 where my container is located

node1$ ssh node2

Then list the Docker Containers, by ID. And I can see 72d6a20c3d15 in this list, bottom entry:

node2$ docker ps

CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS               NAMES
2e3bc7158d61        89up/drupal:unity          "docker-php-entrypoi…"   7 days ago          Up 7 days           80/tcp              someothersite_drupal.1.tg33od888aj6krqqhdx0tp8ta
53122123d035        haproxy:alpine             "/docker-entrypoint.…"   7 days ago          Up 7 days                               someothersite_haproxy.1.t1x7exq98huu8q3aaok57d22
9348345f84cb        haproxy:alpine             "/docker-entrypoint.…"   10 days ago         Up 10 days                              something-m_haproxy.2.02haarnwe1ssfo0x9rypx2yud
72d6a20c3d15        animage1/drupal:d8         "docker-entrypoint.s…"   2 weeks ago         Up 2 weeks          80/tcp              site3_drupal.1.5fqfizaxt0plh1tzt6caq0zon

Step 6:

I can now ssh into that container:

node2$ docker exec -it 72d6a20c3d15 /bin/bash

Triumph!

(In your case, your Container ID may be on your node1, or whatever. I've only added this extra step for node2 to illustrate the point that one should be aware of the node that the task (and corresponding container is running on))

1
  • ^ This answer is still valid and works even though I accepted anemyte's answer. – therobyouknow Dec 13 '20 at 23:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.