{"id":18445884,"url":"https://github.com/voronenko/devops-docker-baseimage-demo","last_synced_at":"2025-10-14T20:32:19.343Z","repository":{"id":145345105,"uuid":"103697174","full_name":"Voronenko/devops-docker-baseimage-demo","owner":"Voronenko","description":"Approach for using ansible-container to build your next application base image","archived":false,"fork":false,"pushed_at":"2017-09-20T13:58:49.000Z","size":36,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-18T07:27:33.918Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Voronenko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-15T20:11:46.000Z","updated_at":"2017-09-20T13:49:53.000Z","dependencies_parsed_at":"2023-07-03T09:17:05.978Z","dependency_job_id":null,"html_url":"https://github.com/Voronenko/devops-docker-baseimage-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Voronenko/devops-docker-baseimage-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Voronenko%2Fdevops-docker-baseimage-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Voronenko%2Fdevops-docker-baseimage-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Voronenko%2Fdevops-docker-baseimage-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Voronenko%2Fdevops-docker-baseimage-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Voronenko","download_url":"https://codeload.github.com/Voronenko/devops-docker-baseimage-demo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Voronenko%2Fdevops-docker-baseimage-demo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279020905,"owners_count":26086948,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T07:07:43.558Z","updated_at":"2025-10-14T20:32:19.325Z","avatar_url":"https://github.com/Voronenko.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Using ansible-container to build your next application base image\n\nMost Dockerfiles start from a parent image. If you need to completely control the contents of your image,\nyou at some moment understand, that you need your own base image. Application baseimage is a special\n[Docker](https://www.docker.com) image that is configured for correct use within Docker containers and aware\nabout your application requirements, expectations + set of additional tools.\n\nUsually those include, but not limited to:\n\n * Modifications for Docker-friendliness.\n * Application specific libraries and frameworks\n * Some administration tools, that are especially useful for troubleshouting inside docker\n * Mechanisms for easily running multiple processes, without violating the Docker philosophy\n\nPerhaps every company or agency dealing with dockerized applications have or implemented such one.\nUntil now you could find it in a form of complex shell and makefiles, especially if baseimage is released\nfor multiple OS-es.\n\nThe closer `ansible-container` 1.0.0 release is, the more chances that you would give a try to ansible to take\ncare on your next dockerized application base image.\n\nLet's briefly dive into components you might use in such image.\n\n\n## Image building boilerplate with ansible-container\n\n### Folders and files organization\n\nYou can launch building process using any tool you like.  From my experience - I've come so far with the following approach: https://github.com/Voronenko/container-image-boilerplate\n\n`requirements.txt` - define any specific py tools \u0026 libs you want to use together with ansible-container.\n`.projmodules` - list of dependencies (roles, deployables, etc) needed to compile base image. Format similar to gitmodules, but without direct links to commit. Example:\n\n```\n\n[submodule \"roles/sa-nginx-container\"]\n        path = roles/softasap.sa-nginx-container\n        url = https://github.com/softasap/sa-nginx-container.git\n[submodule \"roles/sa-uwsgi-container\"]\n        path = roles/softasap.sa-uwsgi-container\n        url = https://github.com/softasap/sa-uwsgi-container.git\n[submodule \"roles/sa-include\"]\n        path = roles/softasap.sa-include\n        url = https://github.com/softasap/sa-include.git\n[submodule \"deployables/application\"]\n        path = deployables/application\n        url = https://github.com/voronenko-p/django-sample.git\n\n```\n\n`init.sh` \u0026\u0026 `init_quick.sh` - resolve external dependencies under specified locations (roles under roles, deployables under deployables, etc)\n\n`ansible.cfg` - by default empty, but you can adjust parameters for your build process according to documentation.\n\n`version.txt` - information file gitflow based releasing (x.y.z)\n\n`image.txt` - additional information about image constructed for tagging and pushing parts.\n\n`Makefile` \u0026\u0026 `docker-helper.sh` - orchestration utilities, discussed in the next chapter.\n\n`docker-compose.yml` - usually I also provide docker-compose configuration, so the image can be immediately tried.\n\n`container.yml` - definition of the image you are going to build\n\nAnd, of course, `.gitignore` - we definitely do not want to commit external resources. `p-env` - virtual environment created during the build, `ansible-deployment` - transient output produced by ansible-container itself.\n```\nroles/*\nansible-deployment/*\np-env/*\ndeployables/*\n*.retry\n```\n\n### Build process orchestration\n\nMakefile implement following phases: `initialize`\n\n#### clean\n\nResets project to initial state by removing all build directories and artifacts\n\n```\nclean:\n        @rm -rf .Python p-env roles ansible-deployment\n```\n\n\n#### Initialize \nParses .projmodules and checks out necessary roles and deployables\n```\ninitialize:\n        @init_quick.sh\n```\n\n#### p-env/bin/ansible-container\nInternal task - creates and initializes virtual environment with ansible-container under p-env/ directory.\n\n```\np-env/bin/ansible-container: p-env/bin/pip\n        @touch $@\n\np-env/bin/pip: p-env/bin/python\n        p-env/bin/pip install -r requirements.txt\n\np-env/bin/python:\n        virtualenv -p $(python) --no-site-packages p-env\n        @touch $@\n```\n\n#### build\nExecutes ansible-container for container.yml, providing path to roles. Project name influences how produced image will be named.\n\n```\nbuild:  p-env/bin/ansible-container\n        @p-env/bin/ansible-container --debug --project-name $(ROLE_NAME) build --roles-path ./roles/ -- -vvv\n        @echo \"Application docker image was build\"\n```\n\n#### run and stop\nPotentially, ansible-container allows immediatelly to run and stop images in a way like docker-compose does. From my experience, that is not always working,\n+ container.yml is based on 2nd version of the docker-compose spec, while I usually need at least 3.1 in production. Anyway steps are provided - they might work in your case. I usually end with the separate docker-compose.yml v3.1+ in the directory.\n\n```\nrun:  p-env/bin/ansible-container\n        @echo p-env/bin/ansible-container --debug --project-name $(ROLE_NAME) run --roles-path ./roles/ -- -vvv\n        @p-env/bin/ansible-container --debug --project-name $(ROLE_NAME) run --roles-path ./roles/ -- -vvv\n        @echo \"Application environment was started\"\n\nstop:   p-env/bin/ansible-container\n        @echo p-env/bin/ansible-container --debug --project-name $(ROLE_NAME) stop\n        @p-env/bin/ansible-container --debug --project-name $(ROLE_NAME) stop\n        @echo \"Application environment was stopped\"\n```\n\n#### tag and push\nUsually as a result of successful build, you want to push artifact to some registry.\nThis highly depends on your project, and you most likely adjust it for your needs.\n\nProviding example: properly tags api and nginx images built and pushes them to docker hub.\n```\ntag:\n        @docker tag $(ROLE_NAME)-api:latest softasap/sa-container-box-examples:$(ROLE_NAME).api.$(ROLE_VERSION)\n        @docker tag $(ROLE_NAME)-api:latest softasap/sa-container-box-examples:$(ROLE_NAME).api.latest\n        @docker tag $(ROLE_NAME)-nginx:latest softasap/sa-container-box-examples:$(ROLE_NAME).nginx.$(ROLE_VERSION)\n        @docker tag $(ROLE_NAME)-nginx:latest softasap/sa-container-box-examples:$(ROLE_NAME).nginx.latest\n\npush:\n        @docker push softasap/sa-container-box-examples:$(ROLE_NAME).api.$(ROLE_VERSION)\n        @docker push softasap/sa-container-box-examples:$(ROLE_NAME).api.latest\n        @docker push softasap/sa-container-box-examples:$(ROLE_NAME).nginx.$(ROLE_VERSION)\n        @docker push softasap/sa-container-box-examples:$(ROLE_NAME).nginx.latest\n\n\n```\n\n#### compose helpers\n\nLaunching, stoppling and dismounting docker-compose managed containers.\n\n```\ncompose-up:\n        @docker-compose up --no-recreate\n\ncompose-stop:\n        @docker-compose stop\n\ncompose-down: compose-stop\n        @docker-compose rm --force\n```        \n\nThat's all.  Back to primary target.\n\n# Building base image with ansible container.\n\nFor base image, I usually want: \n* agreed folder organization (I do not want to guess each time where and how I need to put logic to run), \n* robust init system.  \n* optional support for running multiple processes per container (as long as container remains single logical unit - it does not contradict with \nDocker philosophy). \n* Depending on project I want to be able to use different base images and do not want to dive into compilation specifics each time.\n* Possibility to run logic under custom users inside container and synchronize, if necessary files and folders with host system.\n\nAnd final point: as long as possible I want to keep my code organized better, than series of bash command that usually are hard to read and hard to adjust\nin a way we usually do with programs.  And this is where `ansible-container` will help.\n\n\n## Why valid init for containers is important\n\nAlthough people say, that proper docker microservice should run single dedicated process, it is not always achievable in real world.\nMore correct to say, that Docker suggests the philosophy of running a single logical service per container. A logical service can\nconsist of multiple OS processes. Sometimes you really need to run more than one service in a docker container.  This is especially true, if you are adapting some application that previously was running in standalone vps environment.\n\nWhy init process is important: running processes can be visualized are ordered in a tree: each process can spawn child processes, and each process has a parent except for the top-most process. This top-most process is the init process. It is started when you start your container and always has PID 1. This init process is responsible for starting the rest of the system, including starting your application.\nWhen some process terminates, it turns into smth referred as \"defunct process\", also known as a \"zombie process\" (https://en.wikipedia.org/wiki/Zombie_process). In simple words, these are ones that are terminated but have not (yet) been waited for by their parent processes.\n\nBut what if parent process terminates (intentionally, or unintentionally)?  What happens then to its spawned processes? They no longer have a parent process, so they become \"orphaned\" (https://en.wikipedia.org/wiki/Orphan_process).\n\nAnd this is where the init process kicks in. It becomes new parent (adopts) orphaned child processes, even though they were never created directly by the init process. The operating system kernel automatically handles adoption. Moreover: the operating system expects the init process to reap adopted children too.\n\nWhat if not? As long as a zombie is not removed from the system via a wait, it will consume a slot in the kernel process table, and if this table fills, it will not be possible to create further processes in the host system itself. Also, init system implemented wrong often leads to incorrect handling of processes and signals, and can result in problems such as containers which can't be gracefully stopped, or leaking containers which should have been destroyed.\n\nMore reading on a topic:\n\n* https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86\n* https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/\n\nUpstart, Systemd, SysV usually are too heavy (overkill) to be used inside docker (+ not always easily possible).\nWhat are the options ?\n\n## Candidates for container init process\n\nAt a time of article writing, most often used init approaches were:\n\n### Custom written init script\n\nas per docker documentation,  https://docs.docker.com/engine/admin/multi-service_container/\nTake a look on a Proof-of-concept example of such script below\n```\n#!/bin/bash\n\n# Start the first process\n./my_first_process -D\nstatus=$?\nif [ $status -ne 0 ]; then\n  echo \"Failed to start my_first_process: $status\"\n  exit $status\nfi\n\n# Start the second process\n./my_second_process -D\nstatus=$?\nif [ $status -ne 0 ]; then\n  echo \"Failed to start my_second_process: $status\"\n  exit $status\nfi\n\n# Naive check runs checks once a minute to see if either of the processes exited.\n# This illustrates part of the heavy lifting you need to do if you want to run\n# more than one service in a container. The container will exit with an error\n# if it detects that either of the processes has exited.\n# Otherwise it will loop forever, waking up every 60 seconds\n\nwhile /bin/true; do\n  ps aux |grep my_first_process |grep -q -v grep\n  PROCESS_1_STATUS=$?\n  ps aux |grep my_second_process |grep -q -v grep\n  PROCESS_2_STATUS=$?\n  # If the greps above find anything, they will exit with 0 status\n  # If they are not both 0, then something is wrong\n  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then\n    echo \"One of the processes has already exited.\"\n    exit -1\n  fi\n  sleep 60\ndone\n```\n\nWill work, but really does not guarantee reaping...\nLet's examine more robust alternatives.\n\n### Dumb-init\n\ndumb-init is a simple process supervisor and init system designed to run as PID 1 inside minimal container environments (such as Docker). It is deployed as a small, statically-linked binary written in C.\n\ndumb-init enables you to simply prefix your command with dumb-init. It acts as PID 1 and immediately spawns your command as a child process, taking care to properly handle and forward signals as they are received.\n\nProject repo:  https://github.com/Yelp/dumb-init\n\n### Tini\n\nTini advertises itself as a tiny but valid init for containers. Promises:\n* protection from software that accidentally creates zombie processes\n* ensures the default signal handlers work for the software you run in your Docker image.\n* easy to inject: Docker images that work without Tini will work with Tini without any changes.\n\nShipped as precompiled binary for hugh variety of platforms.\n\nProject repo: https://github.com/krallin/tini\n\n### Runit\nRunit is a cross-platform Unix init scheme with service supervision, a replacement for sysvinit, and other init schemes. It runs on GNU/Linux, BSD, can easily be adapted to other Unix operating systems. The program runit is intended to run as Unix process no 1, it is automatically started by the runit-init /sbin/init-replacement if this is started by the kernel.\n\nProject website:  http://smarden.org/runit/\n\n\n### S6\nS6 is project, actually sibling of the RUnit by http://skarnet.org/software/s6/overview.html. S6 contains collection of utilities \nrevolving around process supervision and management, logging, and system initialization.\nMore over, specifically for a docker exists helper project, so-called \"s6-overlay\" https://github.com/just-containers/s6-overlay\n\nS6 provides:\n* lightweight init process with support of initialization (cont-init.d), finalization (cont-finish.d) as well as fixing ownership permissions (fix-attrs.d).\n* The s6-overlay provides proper PID 1 functionality inside docker container. Zombie processes will be properly cleaned up.\n* Support for multiple processes in a single container (\"services\")\n* Usable with all base images - Ubuntu, CentOS, Fedora\n* Distributed as a single .tar.gz file, to keep your image's number of layers small.\n* A whole set of utilities included in s6 and s6-portable-utils. They include handy and composable utilities.\n* Log rotating out-of-the-box through logutil-service which uses s6-log under the hood.\n\n\n### My_Init\nPart of the Phusion baseimage project https://github.com/phusion/baseimage-docker, which currently targets Ubuntu 16:04, Ubuntu 14:04\nOS-es. Consists of custom written py file and wrapped optional runit.\n\nProvides\n* protection from software that accidentally creates zombie processes - reaping is implemented as a part of control script.\n* in addition supports startup files in init.d and rc.local directories.\n* supports additional optional services inside container via runit: cron, ssh\n* handles additional magic with environment\n\nRequires: python inside your container.  In present form limited to Ubuntu base system only.\n\n### Supervisord ?\nThis is known process manager usually used with python applications. I often saw people trying to use it as init system.\nBut: supervisor explicitly mentions that it is not meant to be run as your init process. If you have some subprocess fork itself off, \nit won’t be cleaned up by Supervisor. Thus you anyway would need to choose different init system.\n\nGood if you anyway used it with your application earlier.\n\n### More ?\n\nIf you know more candidates, please comment.\n\n## Candidates for running multiple services inside container.\nFrom mentioned above and at the same time lightweight, worse to mention:\n\n### SupervisorD\n\nClassic supervisor which does not even require root privileges. Ctl script that acts similar to systemd's systemctl.\nSupports processes restarting, as well as event handlers based on shell protocols.\n\n### RUnit\nRunit ships with swiss-knife set of utilities, one of them is `runsvdir` (http://smarden.org/runit/runsvdir.8.html)\nIt allows defining set of \"service definitions\" in some directory, and makes care on launching them at startup.\n\nTypical interaction examples:\n\n`/usr/bin/sv status /etc/service/`  - get status of services listed in configuration folder\n\n`/usr/bin/sv -w 10 down /etc/service/*` - shutdown all services with timeout 10\n\n### S6 (in scope of S6-overlay project)\n\nUnlike supervisor, s6 uses a folder structure to control services, similar to RUnit. \nS6-overlay requires them under /etc/services.d before running init (it then copies them over to /var/run/s6/services). \n\n```\nservices\n    └ nginx\n        └ run\n```\n\nNow, each of those run files is an executable that s6 executes to start the process. \n\n```bash\n#!/bin/bash\nset -e\nexec nginx -c /etc/nginx/nginx.conf\n```\n\nServices are controlled by s6-svc binary. It has number of options, but the main idea is that you give it the directory of the service. So for example, if I wanted to send SIGHUP to nginx, I would do s6-svc -h /var/run/s6/services/nginx. Note: that it’s /var/run and not /etc/services.d; \nThis is hugh difference from RUnit. And lastly, the -h is for SIGHUP. \n\ns6-overlay comes with a number of built versions, so you can download the one that matches your Linux setup. If you want to use s6 directly, users of Alpine and a few other flavors of Linux can just install it from their package manager. We’re running Debian and there’s no PPA for it, so we would have to compile s6 on our own\n\n### More ?\n\nIf you know more candidates, please comment.\n\n## Running processes as a different user\n\nBy default, Docker containers run as the root user. This is bad because:\n* Application might modify up things that it shouldn't be\n* If application shares folder with base host, all created files will be owned by root\n* If container is compromised - well, still it is bad if they're root.\n\nIf you want to understand, how uid and gid work in Docker containers, take a look on that article:  https://medium.com/@mccode/understanding-how-uid-and-gid-work-in-docker-containers-c37a01d01cf\n\nWhat are the options:\n\n### Docker's native\n\nSet on the level of Dockerfile\n\n```\n# Create an app user so our program doesn't run as root.\nRUN groupadd -r app \u0026\u0026\\\n    useradd -r -g app -d /home/app -s /sbin/nologin -c \"Docker image user\" app\n...\nUSER app\n```    \n\nor pass as the params on docker run\n\n```\ndocker run --rm --group-add audio --group-add nogroup --group-add 777 busybox id\nuid=0(root) gid=0(root) groups=10(wheel),29(audio),99(nogroup),777\n```\n\nSuccess scenario, but not always possible, if container communicates with the host.\n\n### chpst\nThis is utility which is shipped with RUnit (http://smarden.org/runit/chpst.8.html) - you can easily use it if you already have RUnit as part of your init system.\n\n### Phusion's setuser\nIf you have chosen phusion image as a basis, you have a `setuser` in path  \nhttps://github.com/phusion/baseimage-docker/blob/master/image/bin/setuser\n\n### sudo\nWell, you can install sudo inside container. Some people do. But do you want?\n\n\n# Your own baseimage built with ansible-container\n\nWith information above you have already few ideas for constructing your base image.\n\nSorry for repeating, but let me emphasize once more: if you want alternative to custom makefiles and tons of hard-to-read shell files, give a try to\nansible-container. Ansible-container provides better alternative to the `command \u0026\u0026 command \u0026\u0026 command` (and so on) syntax you’ve been struggling with to build containers. Since Ansible is at the heart of Ansible Container, you can make container builds completely predictable and repeatable, and more over readable.\n\nI have to admit, that although it is already passed 0.9.1, ansible-container is still at it's early ages  with some cumbersome side effects from time to time (https://medium.com/@V_Voronenko/evaluating-ansible-container-as-a-tool-for-custom-docker-containers-build-500a0395a4c8),\nbut it really becomes more robust each minor release, thus if you try it now - your production will be ready for concept when it is released...\n\nPreviously running ansible inside container required installing a lot of unnecessary packages, which was causing bigger image sizes. Ansible-cointainer\nintroduced different approach: combination of conductor (managing container with ansible and necessary tools installed) and target container. This allows\nto keep target image size small and this approach will work on any base image, which allows ansible and python to be installed.\n\n\nAim of the current proof of concept:  build bootstrap role for building base application image, and thus simplify application play itself.\n\nWe want: select preferred init system: tini, dumb-init or init approach by Phusion (phusion-init)\n\n```yaml\ncontainer_init: \"phusion-init\" # \"dumb-init\" \"tini-init\" \ncontainer_init_directory: /etc/my_init.d\n```\n\nWe want: have possibility to choose internal service layer:  runit, supervisor or s6.\n```yaml\ncontainer_svc: \"runit\" # \"supervisord\"\n```\n\nFollowing the Phusion's base image concept, we want optional cron, sshd, and syslog services inside container.  \n\n```yaml\noption_container_cron: true\noption_container_sshd: true\noption_container_syslog_ng: true\n```\n\nIf we ever wanted ssh inside container, let's provide keypair to trust.\n\n```yaml\ncontainer_ssh_private_key: \"{{role_dir}}/files/keys/insecure_key\"\ncontainer_ssh_public_key: \"{{role_dir}}/files/keys/insecure_key.pub\"\n```\n\nResulting play is compact and readable like your usual ansible play.\n```yaml\n  - include: tasks_system_services.yml\n\n  - include: tasks_cron.yml\n    when: option_container_cron\n\n  - include: tasks_sshd.yml\n    when: option_container_sshd\n\n  - include: tasks_syslog_ng.yml\n    when: option_container_syslog_ng\n```\n\nMore over - we are not limited to some single approach - we are free to select init system and service system from list of supported.\nYou can always add the new one.\n\nIn order to provide some compatibility between systems, I usually\n\na) put services runners into /etc/service/\u003cservicename\u003e/run  - this supports both running via shell, runit, s6. Supervisord might re-execute the same script.\nb) put image pre-initialization into /etc/myinit.d/*.sh\nc) always name entry point as docker-entrypoint.sh\nd) your role, thanks to ansible, migth detect and target multiple basesystems - thus you can choose, for example, often used Alpine or Jessie.\n\nTake a look on role example, that might be used to build such base image:  https://github.com/softasap/sa-container-bootstrap\n\nTypical ansible-container play used to build application image using your base play one might look as:\n\n### tini init system based, with supervisor as service manager\n\n```\nversion: \"2\"\nsettings:\n  conductor_base: ubuntu:16.04\n  volumes:\n   - temp-space:/tmp   # Used to copy static content between containers\n\nservices:\n\n   tini-supervisord:\n     from: ubuntu:16.04\n     container_name: api\n     roles:\n       - {\n           role: \"softasap.sa-container-bootstrap\",\n           container_init: \"tini-init\",\n           container_svc: \"supervisord\"\n         }\n       - {\n           role: \"softasap.sa-nginx-container\",\n           container_init: \"tini-init\",\n           container_svc: \"supervisord\"\n         }\n       - {\n           role: \"../custom-roles/app-nginx-stub-deploy\",\n           container_init: \"tini-init\",\n           container_svc: \"supervisord\"\n         }\n     expose:\n       - '8000'\n       - '22'\n     volumes:\n        - temp-space:/tmp   # Used to copy static content between containers\n     environment:\n        IN_DOCKER: \"1\"         \n\nvolumes:\n  temp-space:\n    docker: {}\n\n```\n\n### tini init system based, with supervisor as service manager\n\n```\nversion: \"2\"\nsettings:\n  conductor_base: ubuntu:16.04\n  volumes:\n   - temp-space:/tmp   # Used to copy static content between containers\n\nservices:\n\n   dumb-runit:\n     from: ubuntu:16.04\n     container_name: api\n     roles:\n       - {\n           role: \"softasap.sa-container-bootstrap\",\n           container_init: \"dumb-init\"\n         }\n       - {\n           role: \"softasap.sa-nginx-container\",\n           container_init: \"dumb-init\" # optionally uses runit for services management and upstart.\n         }\n       - {\n           role: \"../custom-roles/app-nginx-stub-deploy\",\n           container_init: \"dumb-init\"\n         }\n     expose:\n       - '8000'\n       - '22'\n     volumes:\n        - temp-space:/tmp   # Used to copy static content between containers\n     environment:\n        IN_DOCKER: \"1\"         \n\nvolumes:\n  temp-space:\n    docker: {}\n```    \n\n### Close to Phusion's base image\n\n```\nversion: \"2\"\nsettings:\n  conductor_base: ubuntu:16.04\n  volumes:\n   - temp-space:/tmp   # Used to copy static content between containers\n\nservices:\n\n   phusion-runit:\n     from: ubuntu:16.04\n     container_name: api\n     roles:\n       - {\n           role: \"softasap.sa-container-bootstrap\"\n         }\n       - {\n           role: \"softasap.sa-nginx-container\",\n           container_init: \"phusion-init\" # uses runit for services management and upstart.\n         }\n       - {\n           role: \"../custom-roles/app-nginx-stub-deploy\"\n         }\n     expose:\n       - '8000'\n       - '22'\n     volumes:\n        - temp-space:/tmp   # Used to copy static content between containers\n     environment:\n        IN_DOCKER: \"1\"         \n\nvolumes:\n  temp-space:\n    docker: {}\n```    \n\nMore examples on https://github.com/Voronenko/devops-docker-baseimage-demo\n\n## Few figures on produced sizes\n\n```\n\nBase system:                               ubuntu 16.04\nInit system:                               phusion_init\nBase image with all services:              268 MB / 101 MB on docker.hub \nBase image with demo nginx app installed:  313 MB / 133 MB on docker hub\n\nphusion/baseimage:                         225 MB / 84 MB on docker hub\n\n```\n\n## Summary\n\nAnsible-container, once it reaches stable version hopefully this year, appears to be very promising tool for introducing complex docker based build \npipelines. In addition, ansible community allows you to re-use number of available roles - that potentially can streamline your deployment implementation path.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoronenko%2Fdevops-docker-baseimage-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoronenko%2Fdevops-docker-baseimage-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoronenko%2Fdevops-docker-baseimage-demo/lists"}