by Bryan Lee

Laravel Continuous Deployment With CircleCI and Deployer

1*FM9PcX3sA-6NyQtKujjblQ
Image from Maxpixel

There are many deployment solutions out there with deploying Laravel, ranging from SSH’ing into your machine and git pulling the files (?) to time-savers like Envoyer or rolling your own with Deployer. I personally love Deployer as it is free, very flexible and can support your projects from infancy to when you scale to multiple machines.

Deployer works by running your deployment scripts locally and we can make this even more convenient by integrating Deployer into your CI pipeline. For a recent project, I used CircleCI to run all my tests and automatically deploy.

Setup Deployer Locally

To save time, I will highly recommend that you have Deployer installed locally and configured and working for your app. This saves a lot of time in having to do debugging on your Deployer config when your CircleCI build fails.

Laravel and CircleCI

If you already have CircleCI setup for your Laravel project tests, skip to the next section. Otherwise, I assume that you at least already have a CircleCI account and a basic project created inside.

Create a .circleci/config.yml and with the below


version: 2
jobs:
  build:
    docker:
      # Specify the version you desire here
      - image: circleci/php:7.1-browsers
      - image: circleci/mysql:5.7
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_USER: root
          MYSQL_ROOT_PASSWORD: ''
          MYSQL_DATABASE: laravel

    working_directory: ~/laravel

    steps:
      - checkout
      - run:
          name: Install PHP exts
          command: |
            sudo docker-php-ext-install zip
            sudo docker-php-ext-install pdo_mysql
            sudo apt install -y mysql-client
      - run: sudo composer self-update

      # Download and cache dependencies
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "composer.json" }}
          # fallback to using the latest cache if no exact match is found
          - v1-dependencies-

      - run: composer install -n --prefer-dist

      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "composer.json" }}

      - run:
          name: Setup Laravel stuffs
          command: |
            php artisan migrate --force
      - run: ./vendor/bin/phpunit

workflows:
  version: 2
  notify_deploy:
    jobs:
      - build

This is a very basic config.yml for Laravel. It will install PHP, MySQL and run PHPunit tests. Feel free to modify this to suit your needs.

CircleCI Deployment

After our tests are run, we want CircleCI to automatically start deploying to our server. Remember that Deployer uses SSH, so in our remote server, we want to create a SSH keypair ssh-keygen -t rsa -b 4096 -C “your@email.com". We want to add this key we created into CircleCI as a deployment key. Take note of the fingerprint, as we will need to add this into our config file later.

Let’s create a new job in our config file:

jobs:
  build: ... # from above
  
  deploy:
    docker:
      - image: circleci/php:7.2-browsers
    working_directory: ~/laravel
    steps:
      - checkout

This tells CircleCI that we have a new job called deploy and to build it based on the php-7.2-browsers docker image.

Remember the fingerprint that we took note of when we added it into CircleCI? We need to reference this in in our config so that the SSH key will be present in our container.

jobs:
  build: ... # from above
  
  deploy:
    docker:
      - image: circleci/php:7.2-browsers
    working_directory: ~/laravel
    steps:
      - checkout
      - add_ssh_keys:
          fingerprints:
            - "YOUR_FINGERPRINT"

So now, CircleCI knows to add this key via the fingerprint into the docker container and this will allow us to run Deployer and SSH into our remote server to deploy.

jobs:
  build: ... # from above
  
  deploy:
    docker:
      - image: circleci/php:7.2-browsers
    working_directory: ~/laravel
    steps:
      - checkout
      - add_ssh_keys:
          fingerprints:
            - "YOUR_FINGERPRINT"
      - run:
          name: Install Deployer
          command: |
            curl -LO https://deployer.org/deployer.phar
            sudo mv deployer.phar /usr/local/bin/dep
            sudo chmod +x /usr/local/bin/dep
      - run:
          name: Deploy
          command: |
            dep deploy www.your_server.com

With the deploy job defined, the last step would be to tell CircleCI to run it after our tests pass. That’s simple, we already have a basic workflow named notify_deploy that we can build upon.

workflows:
  version: 2
  notify_deploy:
    jobs:
      - build
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master

This tells CircleCI that in our notify_deploy workflow, aside from running build, we want to run deploy after it is finished, and to only do it on the master branch.

With everything done, we can now push the config file to our git repository and watch it test and deploy on its own. Do you use a different way of deploying Laravel? Let me know, I’d love to hear about it!