Capistrano is a framework for building automated deployment scripts. Although Capistrano is written in Ruby, it can easily be used to deploy projects of any language or framework, whether Rails, Java, or PHP. For more details https://github.com/capistrano/capistrano/.
While working on a particular project, we deployed the development environment through docker/ansible, while we used capistrano to deploy the production environment. Deploying to staging and production environments was done manually.
To make it all automatically deploy when the branch is merged to staging or production, we decided to dockerize Capistrano and deploy when the pipeline is triggered.
Here is the basic docker sample of a ruby application we used.
FROM ruby:<version_tag> RUN apk add -U openssh libc6-compat curl ca-certificates build-base git postgresql-dev postgresql-client shared-mime-info yarn WORKDIR /path/to/workdir #.ruby-version is required in GemFile COPY Gemfile Gemfile.lock .ruby-version ./ RUN gem install bundler RUN bundle lock --add-platform ruby && bundle install COPY . . CMD sh -c "/bin/sh deploy.sh"
The script deploy.sh actually does the deployment to the server. Let us look into it in a bit of detail.
- Deploy script
#!/bin/bash which ssh-agent || ( apt update -y && apt install openssh-client -y ) eval ssh-agent chmod 400 key.pem ssh-add key.pem ssh-add -l echo $CI_ENV cap $CI_ENV deploy
Here, firstly it checks if the ssh-agent command is available. If not, it updates the package list and installs the openssh-client package using apt to make sure the SSH client tools are available in the container.
Then it starts the SSH agent, which will handle private key authentication for your Git operations. We then need to change the permissions of the keyfile(key.pem).
We then add the key to the SSH agent, allowing it to be used for authenticating with the remote server, and then verify that the key was added successfully.
The echo part is optional but by doing so, we can be sure that the correct environment is deployed to the server.
Finally, the Capistrano deploy command is deployed to the server in its respective environment. e.g: cap production deploy, the $CI_ENV is passed when the deployment starts.
Now, let us look into implementing it in ci/cd.
stages: - deploy deploy to staging: stage: deploy only: - staging before_script: - cp $PEM_KEY key.pem - docker build -t capistrano-deploy -f Dockerfile-Capistrano . script: - docker run --rm -e CI_ENV=staging capistrano-deploy deploy to production: stage: deploy only: - main before_script: - cp $PEM_KEY key.pem - docker build -t capistrano-deploy -f Dockerfile-Capistrano . script: - docker run --rm -e CI_ENV=production capistrano-deploy
Here, firstly our server keyfile is copied and then docker is built. After finishing building the image, the docker run command will run the container with the appropriate env variables for staging and production according to the branches, and then the container will be removed.
The main reason behind opting for the shell executor over the Docker executor in GitLab CI/CD was due to the existence of several projects reliant on a centralized GitLab runner. Switching the executor would have had an effect on the pipelines of other projects since some are configured to use the shell executor. Additionally, running both shell and Docker executors on a single runner is not feasible.
Gurzu is a full-cycle software development company. Since 2014, we have built for many startups and enterprises from all around the world using Agile methodology. Our team of experienced developers, designers, and test automation engineers can help to develop your next product.