Asked  9 Months ago    Answers:  5   Viewed   248 times

I have a working swarm setup and rolling-updates deployment. As i have to execute some tasks after deployment (like database migrations) i added a "manager" service to the stack. this service is limited to the node-manager - so i always have a way to find it.

To get the current containerID i use this command:
export MANAGER_ID=$(docker --tls ps --filter label=com.docker.swarm.service.name=projectname-php-manager -q)

This works ... but not during deploy.

The stack deploy exits to soon (befor the container is up) or even befor the manager container gets updated. I also added a sleep 10 befor geting the containerID but the results vary.

Is there a way to wait or to know when a specific service is deployed?

The full deploy looks like this (done in a gitlab-ci job - but this is not the root of the problem):

deploy:staging:
  variables:
    DOCKER_HOST: "tcp://swarm-manager.hostname.tld:2376"
    DOCKER_CERT_PATH: "/home/gitlab-runner/docker/swarm-manager.hostname.tld"
    VERSION_TAG: "$CI_COMMIT_TAG"
    MYSQL_PROD_PASSWORD: "$MYSQL_PROD_PASSWORD"
    SECRET_TOKEN: "$SECRET_TOKEN"
  script:
    - docker --tls stack deploy -c docker-compose.prod.yml project-name --with-registry-auth --prune
    - sleep 10
    - export MANAGER_ID=$(docker --tls ps --filter label=com.docker.swarm.service.name=project-name_php-manager -q)
    - docker --tls exec -t $MANAGER_ID bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration
  stage: deploy
  environment:
    name: staging
    url: http://projectname.com
  only: [tags]
  cache: ~
  dependencies:
    - build:app
  tags:
    - deploy

Part from docker-compose.prod.yml:

php-manager:
    image: dockerhub.mydomain.tld/namespace/projectname/php:${VERSION_TAG}
    environment:
        DATABASE_URL: "mysql://projectname:${MYSQL_PROD_PASSWORD}@mysql:3306/projectname?charset=utf8mb4&serverVersion=5.7"
        APP_ENV: prod
        APP_SECRET: "${SECRET_TOKEN}"
        VERSION: "${VERSION_TAG}"
        REDIS_HOST: redis
    networks:
      - default
    deploy:
      placement:
        constraints: [node.role == manager]
      replicas: 1
      restart_policy:
        condition: on-failure

 Answers

5

Docker stack deploy creates tasks which try to get the system to the state you desire. Sometimes tasks succeed, sometimes they fail and the orchestrator will generate new tasks until the system matches the state described in your yml files.

The bad news: docker stack deploy does not support blocking until the state you desire is reached.

Here some how to get the info you want using the docker cli and basic bash tools (which you can surely implement in a similar way in any other language)

In bash you could do docker service ls --format '{{.ID}} {{.Name}}' | grep ${serviceName} to get the ServiceId of your service (its the first of the two words returned)

according to the docs docker service ps does:

List the tasks of one or more services

Also it adds some information about the task 'current state' which is the information you care about.

Then you use docker service ps ${ServiceId} --format '{{.CurrentState}} {{.Image}}' | grep Running.*${newImageName}

If this command returns something there is a container running with your new image. Hurray :)

I hope this introduces you to all the tools you need. Docker service ps is also helpfull for finding out why a task failed.

FYI: The possible values of task state according to the Swarm task states documentation are:

NEW The task was initialized.

PENDING Resources for the task were allocated.

ASSIGNED Docker assigned the task to nodes.

ACCEPTED The task was accepted by a worker node. If a worker node rejects the task, the state changes to REJECTED.

PREPARING Docker is preparing the task.

STARTING Docker is starting the task.

RUNNING The task is executing.

COMPLETE The task exited without an error code.

FAILED The task exited with an error code.

SHUTDOWN Docker requested the task to shut down.

REJECTED The worker node rejected the task.

ORPHANED The node was down for too long.

Monday, September 20, 2021
 
VieStar
 
3

Ok, as you say in your question, your process is listening to connection on localhost:4200.

Inside a docker container, localhost is the address of the loopback device of the container itself, which is separated and not reachable from your host network.

You need to edit your node process in order to make it listen to all addresses by editing the entrypoint in your Dockerfile as follows:

ENTRYPOINT ["ng", "serve", "-H", "0.0.0.0"]
Saturday, July 31, 2021
 
Eugenie
 
5

Use events - it's what they're designed for.

You don't need to use a boolean variable for this in the Button_Click event handler call your code:

private void Button_Click(object sender, EventArgs e)
{
    // The code you need to execute when the button is pressed
}

As @trickdev points out you will need to subscribe to this event but if you use the Events window in Visual Studio it will add the necessary code - including the empty handler - for you.

With event driven programs you are always waiting until the next "thing" happens. So in your case (if I've understood your application correctly) when you start the program it should simply tell the first button to flash "N" times. If you write that as event then the application will return to the waiting state once the code has completed.

Then in the button click event handler - you can subscribe all the buttons to the same event - you can check that the correct button has been pressed and then tell the next button to flash. If the wrong button was pressed then display a suitable message.

So in pseudo code you have:

public class Form
{
    Initialise()
    {
        this.Loaded += FormLoaded;
    }

    private void FormLoaded(object sender, EventArgs e)
    {
        // pick a button
        pickedButton.Flash();
    }

    private void Button_Click(object sender, EventArgs e)
    {
        if (sender == pickedButton)
        {
            pickedButton = pickButton();
        }
        else
        {
            message = "Sorry wrong button, try again";
        }

        pickedButton.Flash();
    }
}

public class Button
{
    public void Flash()
    {
        // loop N times turning button on/off
    }
}
Monday, August 23, 2021
 
etsous
 
5

As indicated by François Maturel, with a proper healthcheck in place, Docker Swarm will take into account the health status of the container to decide if it will route requests to it.

For Spring Boot applications that have enabled the default actuators, adding this to the Dockerfile is sufficient for a basic healthcheck. When the Spring Boot app is initialized and its health actuator is enabled, the following http request will return a valid http 200 response and the healthcheck will pass.

HEALTHCHECK CMD wget -q http://localhost:8080/health -O /dev/null

This will result in your docker containers being anble to reach a healthy status. When your docker container is started, the service running within it might still be initializing. To do proper load balancing and detect service health, Swarm needs to know when it is able to route reqeusts to a particular service instance (container on a node).

So when Swarm starts a service replica, it fires up a container, it will wait until the health status of the service is "healthy". As your container is starting, it will transition from "starting" :

CONTAINER ID        IMAGE                                                                                                     COMMAND                  CREATED             STATUS                                     PORTS               NAMES
5001e1c46953        ddewaele/springboot.crud.sample@sha256:4ce69c3f50c69640c8240f9df68c8816605c6214b74e6581be44ce153c0f3b7a   "/docker-entrypoin..."   5 seconds ago       Up Less than a second (health: starting)                       springbootcrudsample.2.yt6d38zhhq2wxt1d6qfjz5974

to 'healthy'. Only then will the Swarm load balancer route requests to this endpoint.

[root@centos-a ~]# docker ps
CONTAINER ID        IMAGE                                                                                                     COMMAND                  CREATED              STATUS                        PORTS               NAMES
5001e1c46953        ddewaele/springboot.crud.sample@sha256:4ce69c3f50c69640c8240f9df68c8816605c6214b74e6581be44ce153c0f3b7a   "/docker-entrypoin..."   About a minute ago   Up About a minute (healthy)                       springbootcrudsample.2.yt6d38zhhq2wxt1d6qfjz5974
Monday, October 4, 2021
5

The syntax you used for EC.text_to_be_present_in_element("No data to display")) is wrong.

The syntax is:

class selenium.webdriver.support.expected_conditions.text_to_be_present_in_element(locator, text_)

An expectation for checking if the given text is present in the specified element. locator, text

So, clearly, the locator is missing in your code in which the text to be checked. putting parenthesis also the issue you are facing (in the second edit).

Use as follows (to add locator with correct parenthesis ):

EC.text_to_be_present_in_element((By.ID, "operations_monitoring_tab_current_ct_fields_no_data"), "No data to display")

Note: By.id is just an example. you can use any locator to identify the element supported by selenium

Sunday, October 31, 2021
 
Teno
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share