Vitaliy Yanchuk
Posted on August 5, 2019
In previous post I have described how you can set up your own private docker registry for your secret projects, now we want to add CI to this setup.
Currently I host both on single 5$ VPS, which is decent price, considering amount I would need to pay DockerHub for same number of private docker images and for private TravisCI which costs 69$/month for 1 Concurrent job, which they advertise as "IDEAL FOR HOBBY PROJECTS", well not for 69$ for sure.
Prerequisites
Consider you have a domain example.com
, and want to have CI on drone.example.com
and private registry on registry.example.com
Setting up Drone
Drone requires that you use some external authentication provider, which is actually convenient, I would use GitHub as authentication provider. Also this way drone will import my private repositories on GitHub.
You should check official docs on how to get required credentials if you want to use GitHub as well:
https://docs.drone.io/installation/github/single-machine/
The official doc shows only example how to start Drone with docker run
, but I prefer to put it in the docker-compose.yml
file, so it is easier to start/restart.
So the combined docker-compose.yml
, including Drone and private docker registry would look like:
version: "3"
services:
drone:
image: drone/drone
ports:
- "1080:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/drone:/data
environment:
- DRONE_USER_FILTER=your_user
- DRONE_GITHUB_SERVER=https://github.com
- DRONE_GITHUB_CLIENT_ID=<your id>
- DRONE_GITHUB_CLIENT_SECRET=<your secret>
- DRONE_RUNNER_CAPACITY=2
- DRONE_SERVER_HOST=drone.example.com
- DRONE_SERVER_PROTO=http
- DRONE_TLS_AUTOCERT=true
registry:
restart: always
image: 'registry:2'
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
volumes:
- /root/docker-volumes/registry/registry:/var/lib/registry
- /root/docker-volumes/auth:/auth
Note important environment variable:
DRONE_USER_FILTER
- only this user will be able to use your drone, you should limit it to your user so no other person can use your Drone.
DRONE_SERVER_HOST
- the domain you have used to create OAuth authentication
Running specs
In order to make Drone run specs for your repo you need to add special file to your project .drone.yml
kind: pipeline
name: default
steps:
- name: test
image: registry.example.com/rails_api
commands:
- bundle exec rspec
environment:
RAILS_ENV: 'test'
DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: 'true'
REDIS_URL: redis://redis:6379/
DATABASE_URL: postgres://postgres:@db/ourcodestyle_test
services:
- name: db
image: 'postgres:11.1-alpine'
ports:
- 5432
environment:
POSTGRES_USER: postgres
POSTGRES_DB: rails_api_test
- name: redis
image: 'redis:3.2-alpine'
ports:
- 6379
image_pull_secrets:
- dockerconfigjson
There is several interesting parts in this file:
image: registry.example.com/rails_api
This way you specify which private docker image you would want your build to start. I have this image with all ruby gems already installed, so it dramatically reduces time before tests start to run.
Also note services
section. Drone configuration mimics docker compose syntax so it is easy to configure.
The most important config line is the last one:
image_pull_secrets:
- dockerconfigjson
And it is not well described in the official docs. This setting says how Drone should get credentials for you private repository. You need to have a file /root/.docker/config.json
on the machine where you run Drone. I did not have this file in place. You can create this file by yourself, or there is much easier way, just run:
docker login registry.example.com -u testuser
on the machine which would run Drone and it would create that file.
Domain for Drone
In order to share same server, your drone should have its subdomain, and also it is convenient and nice.
It can be done by adding nginx configuration like this:
upstream drone {
server 127.0.0.1:1080;
}
server {
server_name drone.example.com;
access_log /var/log/nginx/drone.example.com.access.log combined;
error_log /var/log/nginx/drone.example.com.error.log crit;
server_name_in_redirect off;
location / {
proxy_pass http://drone;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
listen 80;
}
Then don't forget to run CertBot in order to get https
certbot --nginx -d drone.example.com
Posted on August 5, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.