Last summer I did a series of posts in conjunction with a talk I gave at WPCampus on Lafayette’s WordPress deployment methodology. At the time the missing piece was a truly automated deployment. We implemented that at the end of August, but I never got around to writing it up until now. We retained our Capistrano methodology, but had GitLab execute the deployment from a container.
Tag: GitLab
I maintain about a dozen plugins in the Moodle plugins repository. I use Moodlerooms’ moodle-plugin-ci project to test all of them on Travis CI. It’s a fantastic tool and rely heavily on it.
This fall I’ve been working on a plugin which, because of various hooks into Lafayette’s internal infrastructure, I’m not releasing publicly. I’d still like to test it in the usual way, so I decided to run the tests on our internal GitLab infrastructure.
I’ve been building a CI/deployment stack with GitLab CI, Docker, and Capistrano. I’m hoping to give a talk on this in the near future, but I wanted to add a brief note on a problem I solved using SSH agent forwarding in Docker in case anyone else runs into it.
In brief, I have code flowing like this:
- Push from local development environment to GitLab
- GitLab CI spins up a Docker container running Capistrano
- Capistrano deploys code to my staging environment via SSH
To do this elegantly requires a deploy user on the staging environment whose SSH key has read access to the repository on GitLab. I don’t want to deploy the private key to the remote staging server. The deploy tasks fire from the Docker container so we bake the private key into it:
# setup deploy key RUN mkdir /root/.ssh ADD repo-key /root/.ssh/id_rsa RUN chmod 600 /root/.ssh/id_rsa ADD config /root/.ssh/config
That part is relatively straightforward. Copy the private key into wherever you’re building the docker image (do not version it) and you’re good to go. Forwarding the key is trickier. First, you’ll have to tell Capistrano to use key forwarding in each deploy step. In 3.4.0 that looks like this:
set :ssh_options, { forward_agent: true }
Next, you’ll have to bootstrap agent forwarding in your CI task. In a CI environment the docker container starts fresh every time and has even less state than usual. You need to start the agent and add your identity every time the task runs. See StackOverflow for a long discussion of agents and identifies. TLDR; add this step:
before_script: - eval `ssh-agent -s` && ssh-add
I experimented with adding that command to my Dockerfile but it didn’t work. This was the most common error: “Could not open a connection to your authentication agent.” The command has to be executed in the running container, which means in this case the CI task configuration, or the key won’t be forwarded and clones on the staging environment will fail with publickey denied.