Linking Vessel Projects Together

December 2017

Vessel is a fantastic project put together by Chris Fidao under the Shipping Docker label. (if you’re looking to get started with Docker you should really check out Shipping Docker) One of the things I love about Vessel is that its tightly focused and will jump-start local Laravel development with Docker in minutes.

I’m not going to go into detail about how to get started with Vessel in this article, go check out the docs.

Diving In

Let's say we have two Laravel projects that we need to communicate together at a server level. For the purpose of this article, we’ll have a web app that needs to consume a back-end service user account service.

Vessel will generate a docker-compose.yml file that looks like:

version: '2'
services:
  app:
    build:
      context: ./docker/app
      dockerfile: Dockerfile
    image: vessel/app
    ports:
     - "${APP_PORT}:80"
    environment:
      CONTAINER_ENV: "${APP_ENV}"
      XDEBUG_HOST: "${XDEBUG_HOST}"
      WWWUSER: "${WWWUSER}"
    volumes:
     - .:/var/www/html
    networks:
     - vessel
  node:
    build:
      context: ./docker/node
      dockerfile: Dockerfile
      args:
        uid: "${WWWUSER}"
    image: vessel/node
    user: node
    volumes:
     - .:/var/www/html
    networks:
     - vessel
  mysql:
    image: mysql:5.7
    ports:
     - "${MYSQL_PORT}:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
      MYSQL_DATABASE: "${DB_DATABASE}"
      MYSQL_USER: "${DB_USERNAME}"
      MYSQL_PASSWORD: "${DB_PASSWORD}"
    volumes:
     - vesselmysql:/var/lib/mysql
     # - ./docker/mysql/conf.d:/etc/mysql/conf.d
     # - ./docker/mysql/logs:/var/log/mysql
    networks:
     - vessel
  redis:
    image: redis:alpine
    volumes:
     - vesselredis:/data
    networks:
     - vessel
networks:
  vessel:
    driver: "bridge"
volumes:
  vesselmysql:
    driver: "local"
  vesselredis:
    driver: "local"

In order to link the two projects together, we will need to create a docker network that both projects can use to communicate through.

Now we need to update both projects docker-compose.yml to use the new network.

We will need to add:

  • The superapp network to the list of project networks (line 56,57 note the external: true)
  • The superapp network to the app services (line 19)
  • Add a container_name parameter to the app services (line 4, this will make it much easier to target the service using Dockers internal DNS)

Web App Compose File

version: '2'
services:
  app:
    container_name: superwebapp
    build:
      context: ./docker/app
      dockerfile: Dockerfile
    image: vessel/app
    ports:
     - "${APP_PORT}:80"
    environment:
      CONTAINER_ENV: "${APP_ENV}"
      XDEBUG_HOST: "${XDEBUG_HOST}"
      WWWUSER: "${WWWUSER}"
    volumes:
     - .:/var/www/html
    networks:
     - vessel
     - superapp
  node:
    build:
      context: ./docker/node
      dockerfile: Dockerfile
      args:
        uid: "${WWWUSER}"
    image: vessel/node
    user: node
    volumes:
     - .:/var/www/html
    networks:
     - vessel
  mysql:
    image: mysql:5.7
    ports:
     - "${MYSQL_PORT}:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
      MYSQL_DATABASE: "${DB_DATABASE}"
      MYSQL_USER: "${DB_USERNAME}"
      MYSQL_PASSWORD: "${DB_PASSWORD}"
    volumes:
     - vesselmysql:/var/lib/mysql
     # - ./docker/mysql/conf.d:/etc/mysql/conf.d
     # - ./docker/mysql/logs:/var/log/mysql
    networks:
     - vessel
  redis:
    image: redis:alpine
    volumes:
     - vesselredis:/data
    networks:
     - vessel
networks:
  vessel:
    driver: "bridge"
  superapp:
    external: true
volumes:
  vesselmysql:
    driver: "local"
  vesselredis:
    driver: "local"

User Account Service Compose File

version: '2'
services:
  app:
    container_name: superaccountservice
    build:
      context: ./docker/app
      dockerfile: Dockerfile
    image: vessel/app
    ports:
     - "${APP_PORT}:80"
    environment:
      CONTAINER_ENV: "${APP_ENV}"
      XDEBUG_HOST: "${XDEBUG_HOST}"
      WWWUSER: "${WWWUSER}"
    volumes:
     - .:/var/www/html
    networks:
     - vessel
     - superapp
  node:
    build:
      context: ./docker/node
      dockerfile: Dockerfile
      args:
        uid: "${WWWUSER}"
    image: vessel/node
    user: node
    volumes:
     - .:/var/www/html
    networks:
     - vessel
  mysql:
    image: mysql:5.7
    ports:
     - "${MYSQL_PORT}:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
      MYSQL_DATABASE: "${DB_DATABASE}"
      MYSQL_USER: "${DB_USERNAME}"
      MYSQL_PASSWORD: "${DB_PASSWORD}"
    volumes:
     - vesselmysql:/var/lib/mysql
     # - ./docker/mysql/conf.d:/etc/mysql/conf.d
     # - ./docker/mysql/logs:/var/log/mysql
    networks:
     - vessel
  redis:
    image: redis:alpine
    volumes:
     - vesselredis:/data
    networks:
     - vessel
networks:
  vessel:
    driver: "bridge"
  superapp:
    external: true
volumes:
  vesselmysql:
    driver: "local"
  vesselredis:
    driver: "local"

With this configuration, you will be able to target the account service using the value of the container_name field.

For example, you could test this configuration, from your web app project root, by running docker-compose exec app curl superaccountservice you should get a response from the user account service.

I would also recommend adding some sort of environmental configuration option to your .env to make it easy to configure the account services root host e.g. ACCOUNT_SERVICE_HOST=http://superaccountservice. This way you can easily update the host in production vs development.

Big thanks to Chris Fidao for putting the Vessel project together!