DevOps Guidebook
This repository contains the source for the UIS DevOps Guidebook
Hosting
The guidebook is hosted via GitLab pages. readthedocs.org (RTD) and is automatically deployed on each commit to master. The GitLab pages-managed URL is at https://uis.uniofcam.dev/devops/docs/guidebook/.
To support a custom domain, the guidebook.devops.uis.cam.ac.uk
DNS record is a CNAME pointing to
uis.uniofcam.dev.io
following the custom domain
documentation.
Local Development
The guidebook uses mkdocs to convert Markdown source into a static website. You can run it from either the dockerised setup or your own local environment.
To begin development, install pre-commit and clone the repo locally:
git clone git@gitlab.developers.cam.ac.uk:uis/devops/docs/guidebook.git
pre-commit install
Start the guidebook via:
docker-compose up --build
The local documentation is now available at http://localhost:8000/.
Adding a page
- Create a Markdown file in the relevant directory under
docs
. - Add this file's path to the
nav
configuration inmkdocs.yml
.
Service Information
Service & team information is encoded in services.yml.
When adding or updating a Service page, you must update that file to define such information.
Comments in the file itself describe each section's format.
The file is exposed at endpoint /api/services.yml
for consumption by other apps/services,
via a script in the Gitlab CI config.
NOTE:
-
The canonical source of DevOps teams and team-service mappings is this Google Doc.
-
This YAML configuration simply encodes the information in a machine-parsable format, and must be manually updated to remain in-sync with that document.
Site-Relative URLs
Site-relative URLs can be specified using site:path/to/some-page
.
This functionality is provided by a custom hook in hooks/site_urls.py
These are preferable to relative URLs, since:
- A page containing
site:
URLs needn't change if it's relocated.- Whereas, a page containing relative URLs would need all of them updated.
- A page referenced by
site:
URLs can be relocated, then a single search-and-replace performed to update all references.- Whereas, a page referenced by different relative URLs requires that they all be updated, and each becomes defferent.
Such site:
urls are translated as follows,
depending on whether the code is running locally or in Gitlab CI,
where flag --no-directory-urls
is passed to mkdocs build
:
Example site: URL |
Doc Path | Local URL | CI Artifact URL with --no-directory-urls
|
---|---|---|---|
site:path/to/page |
docs/path/to/page.md |
/path/to/page/ |
$SITE_ROOT/path/to/page.html |
site:path/to/page/ |
docs/path/to/page.md |
/path/to/page/ |
$SITE_ROOT/path/to/page/index.html |
Custom Plugin Syntax
Some MkDocs extensions & plugins used (see mkdocs.base.yml) provide custom syntax to utilise their new visual elements.
Here's a summary of the custom syntax we utilise, provided by our configured extensions & plugins:
Extension / Plugin | Notation | Meaning |
---|---|---|
Admonitions |
!!! note , ??? tip , etc. |
A styled callout, which may be collapsible |
PymdownX > Snippets | --8<-- "path/to/file.(md|ext)" |
Insert contents of the specified file. |
Neoteroi > Cards | [cards cols=2 smaller(path/to/cards.(json|yml))] |
Insert the visual cards defined in specified file. |
Site-Relative URLs (see section below) | site:path/to/some-page |
Site-relative URL (in our case docs/path/to/some-page.md ) |
Macros
The guidebook uses a set of macros to provide a consistent look and feel to the documentation.
Also to auto-generate certain information based on static configuration (.yml
) files.
The MkDocs-Macros plugin is used to simplify this process.
- It loads main.py to access & apply all custom macros.
- Those are stored within macros/.
- To add a new macro, either add to or create a file in macros/.py.
Create a New Template Variable
If you want to add a new template variable,
simply define it in TEMPLATE_VARIABLES
within macros/constants.py.
It will then be available within all .md
files as {{ my_variable }}
.
Create a Macro Mixin
If adding macros for a new context, create a new file macros/{my-context}.py
:
from ..render import hyperlink # etc
def define_env(env):
env.macro(my_macro)
# ..wrap all other macros too..
def my_macro(...):
pass # return render result here e.g. hyperlink(...)
Then import and invoke your module's define_env
in macros/__init__.py
:
from . import (..., my_context, ...)
def define_env(env):
# ...
my_context.define_env(env)
# ...
In similar fashion, add to macros/render any needed context-specific HTML rendering (see existing examples there).
Your macro(s) will then be available within all .md
files as {{ my_macro(..args..) }}
.