mkdkrMake + Docker + Shell = CI Pipeline

联合创作 · 2023-09-30 04:27


mkdkr


Build Status Build Status pipeline status CircleCI GitHub license GitHub release kcov CodeFactor Docker Pulls GitHub all releases



mkdkr = Makefile + Docker



Super small and powerful framework for build CI pipeline, scripted with Makefile and isolated with docker.




Table of contents



Usage


Makefile


Create a file with name Makefile and paste the following content.


Download .mkdkr dynamically.



# Required header
include $(shell [ ! -f .mkdkr ] && curl -fsSL https://git.io/JOBYz > .mkdkr; bash .mkdkr init)

# without shorten url
# include $(shell [ ! -f .mkdkr ] && curl -fsSL https://github.com/rosineygp/mkdkr/releases/latest/download/mkdkr > .mkdkr; bash .mkdkr init)

job:
@$(dkr)
instance: alpine
run: echo "hello mkdkr dynamic!"


OR keep .mkdkr locally.



# Download .mkdkr
curl -fsSL https://github.com/rosineygp/mkdkr/releases/latest/download/mkdkr > .mkdkr



# Required header
include $(shell bash .mkdkr init)

job:
@$(dkr)
instance: alpine
run: echo "hello mkdkr local!"


.gitignore (optional)



.tmp
.mkdkr # only in dynamic config


Execute



# execute
make job


Result



start: job


instance: alpine
20498831fe05f5d33852313a55be42efd88b1fb38b463c686dbb0f2a735df45c

run: echo hello mkdkr!
hello mkdkr!

cleanup:
20498831fe05

completed:
0m0.007s 0m0.000s
0m0.228s 0m0.179s


Export


Run your current Makefile in another engine, like travis or github actions, use the dynamic include exporter.


Demonstration


My Workflow - Configuración automática de CI/CD


My Workflow - Configuración automática de CI/CD


Author: Martin Algañaraz


Reason


Build pipeline for a dedicated platform can take a lot of time to learn and test, with mkdkr you can test all things locally and run it in any pipeline engine like Jenkins, Actions, Gitlab-ci and others.


standards


Functions


@$(dkr)


Load docker layer for mkdkr, use inside a target of Makefile.



shell-only:
echo "my local shell job"

mkdkr-job:
@$(dkr) # load all deps of mkdkr
intance: alpine
run: echo "my mkdkr job"


instance:


Create docker containers, without special privileges.



my-instance:
@$(dkr)
instance: ubuntu:20.04 # create a instance


Parameters:



  • String, DOCKER_IMAGE *: any docker image name

  • String|Array, ARGS: additional docker init args like (--cpus 1 --memory 64MB)


Return:



  • String, Container Id



Calling instance: twice, it will replace the last container.



service:


Create a docker container in detached mode. Useful to bring up a required service for a job, like a webserver or database.



my-service:
@$(dkr)
service: nginx # up a nginx
instance: alpine


Is possible start more than one service.



multi-service:
@$(dkr)
service: mysql
service: redis
instance: node:12
run: npm install
run: npm test



* Instance and services are connected in same network
** The name of service is the same of image name with safe values
































Image Name Network Name
nginx nginx
nginx:1.2 nginx_1_2
redis:3 redis_3
project/apache_1.2 project_apache_1_2
registry/my/service:latest registry_my_service_latest


replace role 's/:|\.|\/|-/_/g'



Parameters:



  • String, DOCKER_IMAGE *: any docker image name

  • String|Array, ARGS: additional docker init args like (--cpus 1 --memory 64MB)


Return:



  • String, Container Id



instance or dind created after a service, will be automatically linked.



dind:


Create a docker instance with daemon access. Useful to build docker images.



my-dind:
@$(dkr)
dind: docker:19
run: docker build -t my/dind .


Parameters:



  • String, DOCKER_IMAGE *: any docker image name

  • String|Array, ARGS: additional docker init args like (--cpus 1 --memory 64MB)


Return:



  • String, Container Id


run:


Execute a command inside docker container [instance: or dind:] (the last one).



Is not possible to execute commands in a service.



Parameters:



  • String|Array, command: any sh command eg. 'apk add nodejs'


Return:



  • String, Command(s) output


Usage



my-run:
@$(dkr)
instance: alpine
# run a command inside container
run: apk add curl

instance: debian
# avoid escape to host bash, escapes also can be used (eg. \&\&)
run: 'apt-get update && \
apt-get install -y curl'

# run a command inside container and redirect output to host
run: ls -la > myfile

# run a command inside container and redirect output to container
run: 'ls -la > myfile'


var-run:


Execute a command inside docker container [instance: or dind:] and return stdout at named var.



After created var it is passed to next run: or var-run: execution.



Parameters:



  • String, var: any bash valid variable name

  • String|Array, command: any sh command eg. 'apk add nodejs'


Return:



  • String, Command(s) output


Usage



my-var-run:
@$(dkr)
instance: alpine
# run a command inside container
var-run: myvar hostname
run: echo '$$myvar'
var-run: mynewvar echo '$$myvar'
run: echo "$$myvar $$mynewvar"


login:


Execute docker login in a private registry. If docker instance exist, execute login inside container otherwise at host.


Parameters:



  • String, domain: private registry domain.

  • String| user: registry username.

  • String| password: registry password.


Return:



  • None.


Usage



private-registry:
@$(dkr)
login: my.private.registry foo $(MKDKR_PASSWORD)
instance: my.private.registry/alpine



Execute login at host and download image from private registry (login before instance creation)




private-registry:
@$(dkr)
dind: docker:19
login: my.private.registry foo $(MKDKR_PASSWORD)
instance: my.private.registry/alpine



Execute login inside instance and download image from private registry (login after instance creation)



retry:


Execute a command inside docker container [instance: or dind:] (the last one), with retry options.



Is not possible to execute commands in a service.



Parameters:



  • Number|Int, attempts: number of attempts before crash.

  • Number|Int, sleep: time sleeping before retry.

  • String|Array, command: any sh command eg. 'curl https://tomcat:8080'


Return:



  • String, Command(s) output


Usage



deploy:
@$(dkr)
instance: oc
retry: 3 10 oc apply -f build.yml
#the job can run 3 times with a delay of ten seconds

npm:
instance: alpine
run: apk add curl
service: my-slow-service
retry: 60 1 curl http://my-slow-service:8080


log:


All output steps executed in a job (except log:) is stored and can be reused during future steps.


Parameters:



  • Number: The number represent the step in a job and start with 0.


Return:



  • Text, Multiline text.


Usage



my-log:
@$(dkr)
instance: alpine
run: apk add curl jq
run: curl http://example.com
log: 1 \| jq '.'


push:


Push files/folders to a container job from local filesystem.


Parameters:



  • String, from: Target files/folders in local filesystem.

  • String, to: Destiny of files/folders inside container.


Return



  • None.


Usage



push:
@$(dkr)
instance: ansible
push: /etc/ansible/inventory/hosts.yml
run: ansible-playbook main.yml


Example


pull:


Pull files/folders from a container job to local filesystem.


Parameters:



  • String, from: Target files/folders inside container.

  • String, to: Destiny of files/folders in local filesystem.


Return



  • None.


Usage



pull:
@$(dkr)
instance: debian
run: curl https://example.com -o /tmp/out.html
pull: /tmp/out.html .


Example


cd:


Move folder context.


Parameters:



  • String, workdir: Set workdir.


Return



  • None.



change-folder:
@$(dkr)
instance: debian
cd: /tmp
run: pwd
# /tmp


Includes


Is possible create jobs or fragments of jobs and reuse it in another projects, like a code package library.


There are two major behavior of includes:


Explicit


A fragment of job (eg. define) and needs to be called explicitly to work.



TAG=latest

define docker_build =
@$(dkr)
dind: docker:19
run: docker build -t $(REGISTRY)/$(PROJECT)/$(REPOS):$(TAG) .
endef


All definitions will be load at start of makefile, after it is possible to call at your custom job.



my-custom-build:
$(docker-build)


Implicit


Just a full job in another project.



TAG=latest

docker_build:
@$(dkr)
dind: docker:19
run: docker build -t $(REGISTRY)/$(PROJECT)/$(REPOS):$(TAG) .


The jobs will be load at start and can be called directly.



make docker_build




  • No needs to implement the job at main Makefile.

  • Very useful for similar projects.



mkdkr.csv


A file with name mkdkr.csv, that contains the list of remote includes.


Needs to be at same place o main Makefile.



commitlint,https://github.com/rosineygp/mkdkr_commitlint.git,master,main.mk
docker,https://github.com/rosineygp/mkdkr_docker.git


The file contains four values per line in following order
































# Name Definition
1 alias * unique identifier of include and clone folder destiny
2 reference * any git clone reference
3 checkout branch, tag or hash that git can checkout (default master)
4 file the fragment of Makefile that will be included (default main.mk)


* required



Collection























Name Description
docker Build and Push Docker images.
commit lint Validate commit message with semantic commit.
exporter Generate pipeline definitions files from Makefile.


Small collection, use it as example



Builtin Targets


_list


List all targets in Makefile, include extensions.



$ make _list

include

alias: exporter, repos: https://github.com/rosineygp/mkdkr_exporter.git, checkout: v1.5.0, file: main.mk

replace: MKDKR_EXPORTER_TAG=latest to v1.5.0
bash.v4-0:
bash.v4-1:
bash.v4-2:
bash.v4-3:
bash.v4-4:
bash.v5-0:
_coverage.report:
examples.dind:
examples.escapes:
examples.pipeline:
examples.retry:
examples.service:
examples.shell:
examples.simple:
examples.stdout:
_exporter_bitbucket-pipelines:
_exporter_circle-ci:
_exporter_github:
_exporter_gitlab-ci:
_exporter_jenkins_pipeline:
_exporter_shell:
_exporter_travis:
lint.commit:
lint.hadolint:
lint.shellcheck:
test.unit:



The result are sorted by name.


First char target name: [a-zA-Z_]



Helpers


A set of small functions to common pipelines process.





























































Name Description Usage Output
slug Replace unsafe values from a string slug <string> string
urlencode Encode a string to URL format urlencode <string> string
urldecode Decode a string from URL format urldecode <string> string
uuid Generate UUID uuid string
ssh-cp-key Copy ssh private key for current user ssh-cp-key <key-path> none
ssh-host-check Set StrictHostKeyChecking=no ssh-host-check <hostname:port> none
git-user Configure git.user and git.email git-user <email> none
git-ssh Configure ssh and git [ssh-cp-key, ssh-host-check, git-user] git-ssh <key-path> <hostname:port> <email> none


autocommit:
@$(dkr)
instance: alpine/git
git-ssh: ~/.ssh/id_rsa github.com auto@mkdkr.com
run: git clone git@github.com:rosineygp/mkdkr.git /auto
run: echo "my new file" \> /auto/my-new-file.txt
run: git -C /auto add my-new-file.txt
run: git -C /auto commit -m "my automatic change"
run: git -C /auto push origin master:feat/auto-push


Examples


Simple



simple:
@$(dkr)
instance: alpine
run: echo "hello mkdkr!"



Is possible to mix images during job, see in example



Makefile


Service



service:
@$(dkr)
service: nginx
instance: alpine
run: apk add curl
run: curl -s nginx


Makefile


DIND


Privileged job



dind:
@$(dkr)
dind: docker:19
run: docker build -t project/repos .


Makefile


Escapes



pipes:
@$(dkr)
instance: ubuntu:18.04
run: "find . -iname '*.mk' -type f -exec cat {} \; | grep -c escapes"



More examples at file



Makefile


Shell


Switch to another shell



shell:
@$(dkr)
instance: ubuntu
export MKDKR_SHELL=bash
run: 'echo $$0'



More examples at file



Makefile


Stdout


Get output by id


Use to filter or apply some logic in last command executed



stdout:
@$(dkr)
instance: alpine
run: echo "hello mkdkr!"
run: ps -ef
log: 1



log: 1 return stout form second command ps -ef




stdout:
@$(dkr)
instance: debian
run: apt-get update
run: apt-get install curl -y
run: dpkg -l
log: 2 | grep -i curl && echo "INSTALLED"



log: 2 return stdout from third command dpkg -l and apply filter



Makefile


Pipelines


Group of jobs for parallel and organization execution



pipeline:
make test -j 3 # parallel execution
make build
make pack
make deploy


Makefile


Environment Variables






























































Name Default Description
MKDKR_TTL 3600 The time limit to a job or service run
MKDKR_SHELL sh Change to another shell eg. bash, csh
MKDKR_JOB_STDOUT last stdout Path of file, generated with last stdout output
MKDKR_JOB_NAME* (job|service)_target-name_(uuid) Unique job name, used as container name suffix
MKDKR_INCLUDE_CLONE_DEPTH 1 In the most of case you no need change history for includes
MKDKR_BRANCH_NAME Return current git branch, if it exist
MKDKR_BRANCH_NAME_SLUG Return current git branch, if it exist, with safe values
MKDKR_NETWORK_ARGS Arguments of docker create networks
MKDKR_DOCKER_IMAGE_PULL missing Set "always" to force pull images before docker instance creation
MKDKR_FORCE_DOWNLOAD_INCLUDE "true" for download include files even it already dowloaded [no cached]



  • to overwrite the values use: export <var>=<value>

  • * auto generated



Migration


Migration from release-0.26, just execute the following script on your terminal at root of your project.



curl https://raw.githubusercontent.com/rosineygp/mkdkr/master/.mkdkr > .mkdkr

mkdkr_migration() {
sed -i 's/\.\.\.\ job\ /instance:\ /g;s/\.\.\.\ service\ /service:\ /g;s/\.\.\.\ privileged\ /dind:\ /g;s/\.\.\.\ /instance:\ /g;s/\.\.\ /run:\ /g;s/@\$(\.)/@\$(dkr)/g' ${1}
}

export -f mkdkr_migration

mkdkr_migration Makefile

find . -iname *.mk -exec bash -c 'mkdkr_migration "$0"' {} \;

浏览 15
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报