Spin Up Your Blog with Jekyll, Docker, Gitlab Part I
STEP1. Install ruby
and rvm
(ruby version manager) and rubygems
Check the previous article: Install Ruby, rvm and rubygems.
Notable facts is that ruby software is packaged in so called gems
.
STEP2. Install Jekyll Static Site Generator
jekyll is itself a
gem
.
Install jekyll’s bundler
package manager (is a gem). Note bundler is expected to run from project folder. Bundler is the equivalent of PHP composer for Ruby world. It writes a file called Gemfile. Gems are locked in a Gemfile.lock. Gems can be fetched from ‘https://rubygems.org’ or any other source specified from Gemfile with keyword source. Bundler is a much more powerful, complex and subtle tool than RubyGems. While gem can be used a system level and at project level, bundle It will replace gem at project level. Install them both at once
gem install jekyll bundler
jekyll -v
STEP4. Spawn the new blog
Create the new blog inside the container:
$ bundle exec jekyll new site
If you look into your project directory, you will see the following structure:
tree
├── 404.html
├── about.markdown
├── _config.yml
├── Gemfile
├── Gemfile.lock
├── index.markdown
└── _posts
└── 2025-04-26-welcome-to-jekyll.markdown
STEP5. Setup the Docker environment
The goal of this article is to build a simple Jekyll blog without installing anything on your machine (using Docker technology) and automate the deployment to a free GitLab page using GitLab CI.
Preliminary step: install
docker
anddocker-compose
: If you don’t know what Docker is read my article Docker Presentation.
Installing docker is optional since you can run at anytime
bundle exec jekyll serve
. Docker will serve the purpose of easing the development.
Create a new file in your root project docker-compose.yml
and then paste inside the following:
services:
jekyll:
image: jekyll/jekyll:latest
command: jekyll serve --watch --force_polling --verbose --config _config.yml _config_dev.yml
ports:
- 4000:4000
volumes:
- .:/srv/jekyll
Set a different port
4001
,4002
etc for various projects to avoid conflicts when working simultaneoulsy to different projects.
Wake it up
docker-compose up -d
At this moment the command: jekyll serve --watch --force_polling --verbose --config _config.yml _config_dev.yml
is being run. If it is necessary to run it manually as shown below.
Build the blog
Run $ docker-compose run jekyll jekyll bash
to get inside the container. Everything you produce here will be mirrored outside in your file structure.
There is no index.html file yet. Run bundle exec jekyll build
in your container prompt.
Now you see the structure has been enriched and a new folder named _site
has emerged. Here is your site that is served locally by your mini server that bundle
incorporates. This is the part that will be copied to your hosting server.
tree
├── 404.html
├── about.markdown
├── _config.yml
├── Gemfile
├── Gemfile.lock
├── index.markdown
├── _posts
│ └── 2025-04-26-welcome-to-jekyll.markdown
└── _site
├── 404.html
├── about
│ └── index.html
├── assets
│ ├── main.css
│ ├── main.css.map
│ └── minima-social-icons.svg
├── feed.xml
├── index.html
└── jekyll
└── update
└── 2025
└── 04
└── 26
└── welcome-to-jekyll.html
Building and previewing the blog
When everything is in place we can build and serve our blog while watching for changes:
There are may ways you can launch the preview of your site:
bundle exec jekyll serve --watch --force_polling
$ docker-compose run --service-ports jekyll jekyll serve --source=site
If you browse to http://localhost:4000
, you will see your new blog!
In a more complex setting you may run
bundle exec jekyll serve --watch --force_polling --verbose --config _config.yml _config_dev.yml --port 4001
I use most often
bundle exec jekyll serve --livereload --trace
Gitlab setup
You need an account on gitlab.com. It’s free.
Add a .gitlab-ci.yml
file at the root of the project, containing the following:
pages:
image: alpine:latest
script:
- cp -R ./dist ./public
artifacts:
paths:
- public
only:
- master
From now, a GitLab CI pipeline will be launched each time there is a push to the master branch and will mount our dist folder content as the root of the GitLab page.
Setup a new Gitlab repository.
Commit and push the changes to the master branch:
$ git init
$ git remote add origin git@gitlab.com:{username}/project.git
$ git add .
$ git commit -m "Initial commit"
$ git push -u origin master
A new pipeline has just been created. Once it’s passed, the blog is available at https://{username}.gitlab.io/project/
.
But, as you can see, asset paths are broken because the base url of the page is /project/.
In order to change it, we need to edit /src/_config.yml:
baseurl: "/project"
We can now rebuild the site:
$ docker-compose run jekyll jekyll build --source=site
When our changes are committed and pushed to the repo, the paths are fixed.
Create a Jekyll Based Blog
Clone a jekyll repository and rename it to projectid.gitlab.io
Create .gitlab-ci.yml
I use image ruby 3.1 to make sure is consistent with the server version.
image: ruby:3.1
variables:
JEKYLL_ENV: production
before_script:
- bundle install
test:
stage: test
script:
- bundle exec jekyll build -d test
artifacts:
paths:
- test
except:
- master
pages:
stage: deploy
script:
- bundle exec jekyll build -d public
artifacts:
paths:
- public
only:
- master
Daily Workflow
When we want to work on the blog, for example, to create a new post, we just need to start Jekyll to build and serve the site:
$ docker-compose run --service-ports jekyll jekyll serve --source=site
The site will be automatically reloaded when there is a change in the src folder
To preview it, we can browse to http://localhost:4000/project/.
When we are happy with the changes, we can push them to the GitLab repo and the live blog will be rebuilt.
bundle exec jekyll serve –livereload –trace
Safe Backup of Your Work
Now let’s push our repository to gitlab. We assume you create that repo in Gitlab. All the instructions are in the README file once you create the repo.
git remote -v
gitlab git@gitlab.com:jazio/jazio.eu.git (fetch)
gitlab git@gitlab.com:jazio/jazio.eu.git (push)
origin git@steve:~/jazio.eu.git (fetch)
origin git@steve:~/jazio.eu.git (push)
git push gitlab