Docker Relocation

All services are not chaos compliant. For some services it is also preferable not to involve storage and network virtualization nor ingress gateways, to beneficit from the best performance and reliability. For those services a failover OpenSVC service, with or without automatic failover (orchestrate=ha), is a valid solution.

With such services, the running instance can be easily relocated, proactively or in reaction to:

  • A hardware or software failure involving downtime.

  • A planned downtime (hardware tech refresh, firmware updates, os upgrades, …)

This relocation capability is more important the higher the number of services.

This tutorial explains how to setup a relocatable dockerized postgresql service, with no network virtualization and a dedicated SAN disk.

Pre-requisites

Two nodes with:

  • network attachments on the same ip subnet, with free ip addresses

  • shared storage : same block device seen from operating system

  • OpenSVC agent installed

  • Docker installed

Service details

  • The service data will be stored in a xfs formatted single logical volume of a volume group build on the shared disk.

  • The service ip address will be plumbed using ipvlan l2 on a veth given to a “pause” container holding a service-wide netns. This veth will be linked to a node’s bonding interface.

  • The postgresql database will run in a second container sharing the pause container netns.

Create the service

$ cat - << EOF | om db1 deploy --config=-
{
    "DEFAULT": {
        "nodes": "{clusternodes}"
    },
    "disk#0": {
        "name": "{svcname}",
        "pvs": "{env.dev}",
        "shared": "true",
        "type": "vg"
    },
    "disk#1": {
        "name": "data",
        "shared": "true",
        "size": "100%FREE",
        "type": "lv",
        "vg": "{svcname}"
    },
    "fs#1": {
        "dev": "/dev/{svcname}/data",
        "mnt": "/srv/{svcname}/data",
        "shared": "true",
        "type": "xfs"
    },
    "ip#0": {
        "gateway": "{env.gateway}",
        "ipdev": "{env.intf}",
        "ipname": "{env.ipaddr}",
        "netmask": "{env.netmask}",
        "netns": "container#0",
        "mode": "ipvlan-l2",
        "type": "netns"
    },
    "container#0": {
        "image": "ghcr.io/opensvc/pause",
        "rm": "true",
        "type": "docker"
    },
    "container#1": {
        "image": "postgres",
        "netns": "container#0",
        "rm": "true",
        "run_args": "-v /srv/{svcname}/data/postgresql:/var/lib/postgresql:rw --user={env.uid}:{env.gid}",
        "type": "docker"
    },
    "env": {
        "dev": "/dev/mapper/36589cfc000000e969988ca11344cabb0",
        "gateway": "192.168.100.1",
        "gid": "999",
        "intf": "bond0",
        "ipaddr": "192.168.100.14",
        "netmask": "24",
        "uid": "999"
    }
}
EOF

Note

You can change the value of the keywords in the env section using svcmgr --env <kw>=<value> options.

After a few seconds, the service will be up and running on the cluster first node.

$ svcmon -s db1 --sections services
Services               node-1-1 node-1-2
 db1     up failover | O^       X

Details on node-1-1

$ db1 print status
db1
`- instances
   |- node-1-2                   down       idle
   `- node-1-1                   up         idle, started
      |- ip#0           ........ up         netns bridge 192.168.100.14/24 br-prd@container#0
      |- disk#0         ........ up         vg db1
      |- disk#1         ........ up         lv db1/data
      |- fs#1           ........ up         xfs /dev/db1/data@/srv/db1/data
      |- container#0    ........ up         docker container db1.container.0@ghcr.io/opensvc/pause
      |- container#1    ........ up         docker container db1.container.1@postgres
      `- sync#i0        ...O./.. up         rsync svc config to nodes

Relocate Service

$ om db1 switch
node-1-1.db1             service db1 target state set to placed@node-1-2

You can follow the progress of this asynchronous action with svcmon -w -s db1.

After a few seconds, the service is switched

$ svcmon -s db1 --sections services
Services                node-1-1 node-1-2
 db1     up^ failover | X^       O

Switch logs

For reference and timings, here are the logs of this action

$ om db1 logs

# orchestrator logs
20:35:50,004 node-1-1.db1             INFO    service db1 target state set to placed@node-1-2
20:35:50,175 node-1-1.db1             INFO    stop failover up instance to satisfy the placed@node-1-2 target

# on the source node, stop instance
20:35:50,434 node-1-1.db1             INFO    do stop --local (daemon origin)
20:35:50,522 node-1-1.db1.container#1 INFO    docker stop b196b8204a5add752680de49f8c9a306888c41db489063455924ada4febb6905
20:35:50,630 node-1-1.db1.container#1 INFO    output:
20:35:50,631 node-1-1.db1.container#1 INFO    b196b8204a5add752680de49f8c9a306888c41db489063455924ada4febb6905
20:35:50,663 node-1-1.db1.container#1 INFO    docker rm db1.container.1
20:35:50,664 node-1-1.db1.container#1 INFO    wait for down status
20:35:51,001 node-1-1.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/21c851c4646b ip addr del 192.168.100.14/24 dev eth0
20:35:51,008 node-1-1.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/21c851c4646b ip link del dev eth0
20:35:51,023 node-1-1.db1.ip#0        INFO    checking 192.168.100.14 availability
20:35:52,210 node-1-1.db1.container#0 INFO    docker stop 0363bb5834f23b394065b9a1e31b911e8d848bf01c8e697b55afa926e7849570
20:35:52,305 node-1-1.db1.container#0 INFO    output:
20:35:52,307 node-1-1.db1.container#0 INFO    0363bb5834f23b394065b9a1e31b911e8d848bf01c8e697b55afa926e7849570
20:35:52,363 node-1-1.db1.container#0 INFO    docker rm db1.container.0
20:35:52,363 node-1-1.db1.container#0 INFO    wait for down status
20:35:52,986 node-1-1.db1.fs#1        INFO    umount /srv/db1/data
20:35:53,249 node-1-1.db1.disk#1      INFO    lvchange -a n db1/data
20:35:53,391 node-1-1.db1.disk#0      INFO    vg db1 is already down

# on the destination node, start instance
20:35:53,880 node-1-2.db1             INFO    start failover down instance to satisfy the placed@node-1-2 target
20:35:54,076 node-1-2.db1             INFO    do start --local (daemon origin)
20:35:54,252 node-1-2.db1.ip#0        INFO    checking 192.168.100.14 availability
20:35:59,323 node-1-2.db1.disk#0      INFO    vgchange --deltag @node-1-1 db1
20:35:59,370 node-1-2.db1.disk#0      INFO    Volume group "db1" successfully changed
20:35:59,370 node-1-2.db1.disk#0      INFO    output:
20:35:59,372 node-1-2.db1.disk#0      INFO    vgchange --addtag @node-1-2 db1
20:35:59,426 node-1-2.db1.disk#0      INFO    output:
20:35:59,427 node-1-2.db1.disk#0      INFO    Volume group "db1" successfully changed
20:35:59,539 node-1-2.db1.disk#0      INFO    vgchange -a y db1
20:35:59,616 node-1-2.db1.disk#0      INFO    1 logical volume(s) in volume group "db1" now active
20:35:59,616 node-1-2.db1.disk#0      INFO    output:
20:35:59,766 node-1-2.db1.disk#1      INFO    lv db1/data is already up
20:35:59,861 node-1-2.db1.fs#1        INFO    mount -t xfs /dev/db1/data /srv/db1/data
20:36:00,160 node-1-2.db1.container#0 INFO    docker run --name=db1.container.0 --detach --net=none ghcr.io/opensvc/pause
20:36:00,436 node-1-2.db1.container#0 INFO    output:
20:36:00,437 node-1-2.db1.container#0 INFO    8d4947414095d12186ea250b966cb8666d8734b5b8d481739ab1722e79927114
20:36:00,462 node-1-2.db1.container#0 INFO    wait for up status
20:36:00,506 node-1-2.db1.container#0 INFO    wait for container operational
20:36:00,671 node-1-2.db1.ip#0        INFO    bridge mode
20:36:00,773 node-1-2.db1.ip#0        INFO    /sbin/ip link add name veth0pl25524 mtu 1500 type veth peer name veth0pg25524 mtu 1500
20:36:00,798 node-1-2.db1.ip#0        INFO    /sbin/ip link set veth0pl25524 master br-prd
20:36:00,812 node-1-2.db1.ip#0        INFO    /sbin/ip link set veth0pl25524 up
20:36:00,824 node-1-2.db1.ip#0        INFO    /sbin/ip link set veth0pg25524 netns 25524
20:36:00,835 node-1-2.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/2bbcf661b019 ip link set veth0pg25524 name eth0
20:36:00,843 node-1-2.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/2bbcf661b019 ip addr add 192.168.100.14/24 dev eth0
20:36:00,850 node-1-2.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/2bbcf661b019 ip link set eth0 up
20:36:00,867 node-1-2.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/2bbcf661b019 ip route replace default via 192.168.100.1
20:36:00,874 node-1-2.db1.ip#0        INFO    /usr/bin/nsenter --net=/var/run/docker/netns/2bbcf661b019 /usr/bin/python /usr/share/opensvc/lib/arp.py eth0 192.168.100.14
20:36:01,267 node-1-2.db1.container#1 INFO    docker run --name=db1.container.1 -v /srv/db1/data/postgresql:/var/lib/postgresql:rw --user=999:999 --detach --net=container:db1.container.0 postgres
20:36:01,480 node-1-2.db1.container#1 INFO    output:
20:36:01,481 node-1-2.db1.container#1 INFO    ee21ce46ffd922582228cb86d2cabc098e7d02141b87b65b210ec4c40f382d43
20:36:01,536 node-1-2.db1.container#1 INFO    wait for up status
20:36:01,624 node-1-2.db1.container#1 INFO    wait for container operational

Activate Automatic Failover

$ om db1 set --kw orchestrate=ha