Package: dockable
dockabledockable is progressive and modular rendering engine for Dockerfiles. It makes it easier to reuse Dockerfile snippets without having to copy and paste, instead you can share your Dockerfile snippets as pip packages, keeping your Dockerfiles clean and well organized.Progressivedockable is progressive, this means you can adopt it gradually and leverage the parts that you need to solve your problems, without having to rewrite everything from scratch.Example 1: dockable as a simple preprocessordockable can be used as a simple preprocessor for an existing Dockerfile, in this most minimal adoption form it's a simple jinja template engine with values coming from command line arguments or yaml configuration files.# kubectl.dock{%ifdist=="ubuntu"%}FROMubuntu:latestRUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\ca-certificates\wget\&&rm-rf/var/lib/apt/lists/*{%else%}FROMalpine:latestRUNapkadd--no-cache\ca-certificates\wget{%endif%}RUNwgethttps://dl.k8s.io/release/{{version}}/bin/linux/amd64/kubectl-P/tmp/download\&&mv/tmp/download/kubectl/usr/local/bin/kubectl\&&chmod755/usr/local/bin/kubectl\&&rm-rf/tmp/downloadpython-mdockablekubectl.dockDockerfile--set=dist=ubuntu--set=version=1.24.6The rendered dockerfile will look like this# DockerfileFROMubuntu:latestRUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\python3\python3-pip\ca-certificates\wget\&&rm-rf/var/lib/apt/lists/*RUNwgethttps://dl.k8s.io/release/1.24.6/bin/linux/amd64/kubectl-P/tmp/download\&&mv/tmp/download/kubectl/usr/local/bin/kubectl\&&chmod755/usr/local/bin/kubectl\&&rm-rf/tmp/downloadExample 2: Insert dockable snippetsdockable can be used to insert dockable snippets into an existing Dockerfile. A dockable snippet is a short yaml configuration that contains all the information for dockable to render that part of the Dockerfile.# kubernetes.dockFROMubuntu:latestRUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\python3\python3-pip\&&rm-rf/var/lib/apt/lists/*
---
steps:
-dockable.releases.binary:pkg:-name:kubectlversion:1.24.6python-mdockablekubectl.dockDockerfileFROMubuntu:latestRUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\python3\python3-pip\&&rm-rf/var/lib/apt/lists/*RUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\ca-certificates\wget\&&rm-rf/var/lib/apt/lists/*RUNwgethttps://dl.k8s.io/release/v1.24.6/bin/linux/amd64/kubectl-P/tmp/download\&&mv/tmp/download/kubectl/usr/local/bin/kubectl\&&chmod755/usr/local/bin/kubectl\&&rm-rf/tmp/downloadExample 3: dockable filesdockable also supports to write the a complete Dockerfile using yaml# kubernetes.yml
name: kubernetes
from: ubuntu:latest
label:
  MAINTAINER: Martin Zihlmann <martizih@outlook.com>
steps:
- dockable.builtin.apt:
    pkg:
    - python3
    - python3-pip
- dockable.releases.binary:
    pkg:
    - name: kubectl
      version: 1.24.6
    - name: helm
      version: 3.11.0python-mdockablekubernetes.ymlDockerfileFROMubuntu:latestLABELMAINTAINER="Martin Zihlmann <martizih@outlook.com>"RUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\python3\python3-pip\&&rm-rf/var/lib/apt/lists/*RUNapt-getupdate\&&DEBIAN_FRONTEND=noninteractiveapt-getinstall-y--no-install-recommends\ca-certificates\wget\&&rm-rf/var/lib/apt/lists/*RUNwgethttps://dl.k8s.io/release/v1.24.6/bin/linux/amd64/kubectl-P/tmp/download\&&mv/tmp/download/kubectl/usr/local/bin/kubectl\&&chmod755/usr/local/bin/kubectl\&&rm-rf/tmp/downloadRUNwgethttps://get.helm.sh/helm-v3.11.0-linux-amd64.tar.gz-P/tmp/download\&&tar-zxvf/tmp/download/helm-v3.11.0-linux-amd64.tar.gz-C/tmp/download\&&mv/tmp/download/linux-amd64/helm/usr/local/bin/helm\&&chmod755/usr/local/bin/helm\&&rm-rf/tmp/downloadModularThe power of dockable lies in its extensibility. You can write handlers for dockable snippets yourself and reuse them accross all of your projects.Write your own dockable snippet handlerLet's suppose you want to write a handler for compiling git from source, you would start by writing the handler itself:# git.yml.jinja
name: build
steps:
- run:
  - wget {{ url }}/{{ filename }} -P /tmp/download
  - tar -zxvf /tmp/download/{{ filename }} -C /tmp/download
  - cd /tmp/download/{{ folder }}
  - make configure
  - ./configure --prefix=/usr {{ config_options }}
  - make -j all
  - make install
  - cd -
  - rm -rf /tmp/download
  needs:
  - dockable.builtin.apt:
      pkg:
      - ca-certificates
      - wget
      - make
---
name: git-from-source
steps:
- .build:
    url: https://mirrors.edge.kernel.org/pub/software/scm/git
    filename: git-{{ version }}.tar.gz
    folder: git-{{ version }}
  needs:
  - dockable.builtin.apt:
      pkg:
      - gcc
      - dh-autoreconf
      - libcurl4-gnutls-dev
      - libexpat1-dev
      - gettext
      - libz-dev
      - libssl-devAs you can see a handler is just a yml configuration, the handler itself can reference other handlers and hence build upon the ever-growing eco-system of dockable snippets. All you now need to do to register your handler is to add amodule.ymlto your python package.# module.ymldependencies:-dockable.raw-dockable.builtinhandlers:-git.yml.jinjaAnd there you go - you can now use, version and share this snippets as a pip package.steps:
- mymodule.git-from-source:
    version: 2.34.1python handler functionWith dockable you can also register regular python functions as handlers for your dockable snippets. Let's suppose you want to parse a requirements.txt on the host and inline its contents into the dockerfile, rather than copying the file into the container.# pip_handler.pyimportpip_apidefload_requirements(file):res=pip_api.parse_requirements(file)return[str(x)forxinres.values()]definline_requirements(file):reqs=pip_api.parse_requirements(file)pkg=[str(x)forxinreqs.values()]return[{"dockable.builtin.pip":{"pkg":pkg}}]in the module.yml you can reference the function and register it under a new name.dependencies:
- dockable.builtin
handlers:
- pip-inline-requirements: pip_handler:inline_requirementsand then finally you can use it as a dockable snippetsteps:
- mymodule.pip-inline-requirements:
    file: requirements.txtThis kind of pre-processing allows us to do all kinds of magic in the background:Do you care about reproducible builds? How about you freeze the versions of your packages on-the-fly with whatever is currently available. Do you care about keeping your secrets secret? How about downloading assets on the host system and copying them into the Docker image instead of downloading them inside the image?ConclusionWith dockable you have a whole new set of possibilities to work with Dockerfiles, it's a brand new powertool available to you.