Migration of docker-compose labels

Am I right in thinking that there is no tool or command in traefik-migration-tool that will automatically migrate my (many and complex) docker-compose file labels from v1 to v2 form?

I'm afraid you're right.
Took me a full weekend and a bit of headache to sift through docs, blogs and faq's just to get started. After that, it all proved to be pretty straight forward.
Once you have the traefik's own service labels figured out and working, and once you have converted one other service to the new format, then basically the same labels concerning routers -> middleware -> services apply to all your other services that are behind traefik.
I also made use of examples posted here and elsewhere.

My example:

version: "3.3"

services:
  traefik:
    image: traefik:v2.0.2
    depends_on:
      - consul-leader
    command:
      # --providers.consul=true
      # --providers.consul.endpoint="consul-leader:8500"
      - --api=true # set to 'false' on production
      - --api.dashboard=true # see https://docs.traefik.io/v2.0/operations/dashboard/#secure-mode for how to secure the dashboard
      # --api.debug=true # enable additional endpoints for debugging and profiling # not recommended
      - --log.level=DEBUG # debug while we get it working, for more levels/info see https://docs.traefik.io/observability/logs/
      - --providers.docker=true
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - --providers.docker.swarmMode=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=traefik-public
      - --entrypoints.web.address=:80
      - --entrypoints.web-secured.address=:443
      - "--certificatesresolvers.mytlschallenge.acme.httpchallenge=true"
      - --certificatesresolvers.mytlschallenge.acme.httpChallenge.entrypoint=web
      - --certificatesresolvers.mytlschallenge.acme.email=$EMAIL
      - --certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json
    ports:
      - "80:80"
      # "8080:8080" # traefik dashboard
      - "443:443"
    volumes:
      - traefik-certificates:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - traefik-public
    deploy:
      placement:
        constraints:
          - node.role == manager
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
        - "traefik.http.routers.http-catchall.entrypoints=web"
        - "traefik.http.routers.http-catchall.middlewares=redirect-to-https@docker"
        - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
        - "traefik.http.routers.api-secured.rule=Host(`api.$DOMAIN`)"
        - "traefik.http.routers.api-secured.entrypoints=web-secured"
        - "traefik.http.routers.api-secured.tls.certresolver=mytlschallenge"
        - "traefik.http.routers.api.rule=Host(`api.$DOMAIN`)"
        - "traefik.http.routers.api.service=api@internal" # Let the dashboard access the traefik api
        - "traefik.http.routers.api.middlewares=auth"
        - "traefik.http.middlewares.auth.basicauth.users=$USER:$HASHED_PASSWORD"
    # Dummy service for Swarm port detection. The port can be any valid integer value.
        - "traefik.http.services.api.loadbalancer.server.port=8080"
#...
  portainer:
    image: portainer/portainer
    deploy:
      placement:
        constraints:
          - node.role == manager
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.portainer.rule=Host(`ptr.$DOMAIN`)"
        - "traefik.http.routers.portainer.entrypoints=web"
        - "traefik.http.services.portainer.loadbalancer.server.port=9000" # give real port where service listens
        - "traefik.http.routers.portainer-secured.rule=Host(`ptr.$DOMAIN`)"
        - "traefik.http.routers.portainer-secured.entrypoints=web-secured"
        - "traefik.http.routers.portainer-secured.tls.certresolver=mytlschallenge"

    volumes:
        - /var/run/docker.sock:/var/run/docker.sock
        - /var/data/portainer:/portainerdata
    command: -H unix:///var/run/docker.sock
    networks:
      - traefik-public
      - agent_network
#...
  agent:
    image: portainer/agent
    environment:
      AGENT_CLUSTER_ADDR: tasks.agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    networks:
      - agent_network
    ports:
      - target: 9001
        published: 9001
        protocol: tcp
        mode: host
    deploy:
      mode: global
      placement:
#        constraints:
#          - node.role == manager
        preferences:
          - spread: node.id
#...
I hope this helps...

I recommend to not enable the --api.debug because it's related to profiling. You can see the related endpoints starting by /debug/ in the documentation https://docs.traefik.io/v2.1/operations/api/#debug
This flag is useless for the majority of the users and have ac CPU and memory cost.

Yes I'm aware of that. Just wanted to post a working example to help the OP getting started with v2 labels. I have hashed out the code in the example above, don't want to be guilty of providing a bad example :slight_smile:
Thanks for the heads-up.
By the way, could you explain in short what 'profiling' means? Thanks.