Search code examples
dockerdocker-composedocker-swarmrolling-updates

docker service with compose file single node and local image


So I need rolling-updates with docker on my single node server. Until now, I was using docker-compose but unfortunately, I can't achieve what I need with it. Reading the web, docker-swarm seems to be the way to go.

I have found how to run an app with multiple replicas on a single node using swarm:

docker service create --replicas 3 --name myapp-staging myapp_app:latest

myapp:latest being built from my docker-compose.yml:

version: "3.6"

services:
  postgres:
    env_file:
      - ".env"
    image: "postgres:11.0-alpine"
    volumes:
      - "/var/run/postgresql:/var/run/postgresql"
  app:
    build: "."
    working_dir: /app
    depends_on:
      - "postgres"
    env_file:
      - ".env"
    command: iex -S mix phx.server
    volumes:
      - ".:/app"

volumes:
  postgres: {}
  static:
    driver_opts:
      device: "tmpfs"
      type: "tmpfs"

Unfortunately, this doesn't work since it doesn't get the config from the docker-compose.yml file: .env file, command entry etc.

Searching deeper, I find that using

docker stack deploy -c docker-compose.yml <name>

will create a service using my docker-compose.yml config.

But then I get the following error message:

failed to update service myapp-staging_postgres: Error response from daemon: rpc error: code = InvalidArgument desc = ContainerSpec: image reference must be provided

So it seems I have to use the registry and push my image there so that it works. I understand this need in case of a multiple node architecture, but in my case I don't want to do that. (Carrying images are heavy, I don't want my image to be public, and after all, image is here, so why should I move it to the internet?)

How can I set up my docker service using local image and config written in docker-compose.yml?

I could probably manage my way using docker service create options, but that wouldn't use my docker-compose.yml file so it would not be DRY nor maintainable, which is important to me.

docker-compose is a great tool for developers, it is sad that we have to dive into DevOps tools to achieve such common features as rolling updates. This whole swarm architecture seems too complicated for my needs at this stage.


Solution

  • You don't have to use registeries in your single node setup. you can build your "app" image on your node from a local docker file using this command -cd to the directory of you docker file-

    docker build . -t my-app:latest
    

    This will create a local docker image on your node, this image is only visible to your single node which is benefitial in your use case but i wouldn't recommend this in a production setup.

    You can now edit the compose file to be:

    version: "3.6"
    
    services:
      postgres:
        env_file:
          - ".env"
        image: "postgres:11.0-alpine"
        volumes:
          - "/var/run/postgresql:/var/run/postgresql"
      app:
        image: "my-app:latest"
        depends_on:
          - "postgres"
        env_file:
          - ".env"
        volumes:
          - ".:/app"
    
    volumes:
      postgres: {}
      static:
        driver_opts:
          device: "tmpfs"
          type: "tmpfs"
    

    And now you can run your stack from this node and it will use your local app image and benefit from the usage of the image [updates - rollbacks ...etc]

    I do have a side note though on your stack file. You are using the same env file for both services, please mind that swarm will look for the ".env" file relative/next to the ".yml" file, so if this is not intentional please revise the location of your env files.

    Also on a side note this solution is only feasable on a single node cluster and if you scale your cluster you will have to use a registery and registeries dont have to be public, you can deploy a private registery on your cluster and only your nodes can access it -or you can make it public- the accessibility of your registery is your choice.

    Hope this will help with your issue.