{"id":18825459,"url":"https://github.com/grycap/minicon","last_synced_at":"2025-04-14T01:31:26.191Z","repository":{"id":55887498,"uuid":"112484449","full_name":"grycap/minicon","owner":"grycap","description":"Minimization of the filesystem for containers","archived":false,"fork":false,"pushed_at":"2020-12-09T12:06:45.000Z","size":147,"stargazers_count":82,"open_issues_count":1,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-27T15:49:18.910Z","etag":null,"topics":["application-builder","container-linux","containers","docker","docker-container","filesystem","merge","merge-containers","minify-images","minimization","minimize","packaging","packaging-scripts"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grycap.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-29T14:19:53.000Z","updated_at":"2025-01-19T06:53:55.000Z","dependencies_parsed_at":"2022-08-15T08:40:30.920Z","dependency_job_id":null,"html_url":"https://github.com/grycap/minicon","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Fminicon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Fminicon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Fminicon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grycap%2Fminicon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grycap","download_url":"https://codeload.github.com/grycap/minicon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248807570,"owners_count":21164710,"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","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":["application-builder","container-linux","containers","docker","docker-container","filesystem","merge","merge-containers","minify-images","minimization","minimize","packaging","packaging-scripts"],"created_at":"2024-11-08T00:59:35.770Z","updated_at":"2025-04-14T01:31:25.808Z","avatar_url":"https://github.com/grycap.png","language":"Shell","readme":"# minicon - minimization containers\n\nWhen you run containers (e.g. in Docker), you usually run a system that has a whole Operating System, documentation, extra packages, etc. and your specific application. The result is that the footprint of the container is bigger than needed.\n\n**minicon** is a general tool to analyze applications and executions of these applications to obtain a filesystem that contains all the dependencies that have been detected. In particular, it can be used to reduce Docker containers. The **minicon** package includes **minidock**\nwhich will help to reduce Docker containers by hiding the underlying complexity of running **minicon** inside a Docker container.\n\nThe purpose of **minicon** and **minidock** is better understood with the use cases explained in depth in the section \"[Examples](#4-examples)\": the size of a basic UI that contains bash, ip, wget, ssh, etc. commands is _reduced from 211MB to 10.9MB_; the size of a NodeJS application along with the server is _reduced from 686 MB (using the official node image) to 45.6MB_; the size of an Apache server is _reduced from 216MB to 50.4MB_, and the size of a Perl application in a Docker container is _reduced from 206MB to 5.81MB_.\n\n\u003e [**minidock**](doc/minidock.md) is based on [**minicon**](doc/minicon.md), [**importcon**](doc/importcon.md) and [**mergecon**](doc/mergecon.md), and hides the complexity of creating a container, mapping minicon, guessing parameters such as the entrypoint or the default command, creating the proper commandline, etc.\n\n## 1. Why **minicon** and **minidock**?\n\nReducing the footprint of one container is of special interest, to redistribute the container images.\n\nIt is of special interest in cases such as [SCAR](https://github.com/grycap/scar), that executes containers out of Docker images in AWS Lambda. In that case, the use cases are limited by the size of the container (the ephemeral storage space is limited to 512 Mb., and SCAR needs to pull the image from Docker Hub into the ephemeral storage and then uncompress it; so the maximum size for the container is even more restricted).\n\nBut there are also security reasons to minimize the unneeded application or environment available in one container image. In the case that the application fails, not having other applications reduces the impact of an intrusion (e.g. if the container does not need a compiler, why should it be there? maybe it would enable to compile a rootkit). \n\nIn this sense, the recent publication of the NIST \"[Application Container Security Guide](https://doi.org/10.6028/NIST.SP.800-190)\" suggests that \"_An image should only include the executables and libraries required by the app itself; all other OS functionality is provided by the OS kernel within the underlying host OS_\".\n\n**minicon** is a tool that enables a fine grain minimization for any type of filesystem, but it is possible to use it to reduce Docker images following the next pipeline:\n\n1. Preparing a Docker container with the dependencies of **minicon**\n1. Guessing the entrypoint and the default command for the container.\n1. Running **minicon** for these commands (maping the proper folders to get the resulting tar file).\n1. Using **importcon** to import the resulting file to copy the entrypoint and other settings.\n1. etc.\n\n**minidock** is a one-liner that automates that procedure to make that reducing a container consist in just to convert a\n\n```bash\n$ docker run --rm -it myimage myapp\n``` \n\ninto\n\n```bash\n$ minidock -i myimage -t myimage:minicon -- myapp\n``` \n\n## 2. Installation\n\n### 2.1 From packages\n\nYou can get the proper package (.deb o .rpm) from the [Releases page](https://github.com/grycap/minicon/releases) and install it using the appropriate package manager.\n\n**Ubuntu/Debian**\n\n```bash\n$ apt update\n$ apt install ./minicon-1.2-1.deb\n```\n\n[![asciicast](https://asciinema.org/a/165792.png)](https://asciinema.org/a/165792)\n\n**CentOS/Fedora/RedHat**\n\n```bash\n$ yum install epel-release\n$ yum install ./minicon-1.2-1.noarch.rpm\n```\n\n[![asciicast](https://asciinema.org/a/166107.png)](https://asciinema.org/a/166107)\n\n### 2.2 From sources\n\n**minicon** are a set of bash scripts. So you just simply need to have a working linux with bash and the other dependencies installed and get the code:\n\n```bash\n$ git clone https://github.com/grycap/minicon\n```\n\nIn that folder you'll have the **minicon**, **minidock** and other applications. The commands in the _minicon_ distribution must be in the PATH. So I would suggest to put it in the _/opt_ folder and set the proper PATH var. Otherwise leave it in a folder of your choice and set the PATH variable:\n\n```bash\n$ mv minicon /opt\n$ export PATH=$PATH:/opt/minicon\n```\n\n#### 2.2.1 Dependencies\n\n**minidock** depends on the commands _minicon_, _importcon_ and _mergecon_, and the packages _jq_, _tar_ and _docker_. **minicon** and the others have dependencies on other packages. So, you need to install the proper packages in your system:\n\n**Ubuntu**\n\n```bash\n$ apt-get install jq tar libc-bin tar file strace rsync\n```\n\n**CentOS**\n```bash\n$ yum install tar jq glibc-common file strace rsync which\n```\n\n## 3. Usage\n\nThe **minidock suite** enables to prepare filesystems for running containers. The suite consists in the next commands: \n\n1. **minidock** ([doc](doc/minidock.md)) analyzes one existing Docker image, reduces its footprint and leaves the new version in the local Docker registry. It makes use of the other tools in the _minicon_ package.\n\n1. **minicon** ([doc](doc/minicon.md)) aims at reducing the footprint of the filesystem for the container, just adding those files that are needed. That means that the other files in the original container are removed.\n\n1. **importcon** ([doc](doc/importcon.md)) importcon is a tool that imports the contents from a tarball to create a filesystem image using the \"docker import\" command. But it takes as reference an existing docker image to get parameters such as ENV, USER, WORKDIR, etc. to set them for the new imported image.\n\n1. **mergecon** ([doc](doc/mergecon.md)) is a tool that merges the filesystems of two different container images. It creates a new container image that is built from the combination of the layers of the filesystems of the input containers.\n\nPlease refer to the documentation of each command to get help about them.\n\n## 4. Examples\n\nIn this section we are including examples on using **minidock**, that makes use of all the other commands. Please refer to the documentation of each command to get examples about each individual command.\n\n### 4.1 Basic Ubuntu UI in less than 11 Mb.\n\nIn this example we will create a basic user interface, from ubuntu, that include commands like `wget`, `ssh`, `cat`, etc.\n\nThe `ubuntu:latest` image do not contain such commands. So we need to create a Docker file that installs `wget`, `ssh`, `ping` and others. We will use this Dockerfile:\n\n```dockerfile\nFROM ubuntu:latest\nRUN apt-get update \u0026\u0026 apt-get install -y ssh iproute2 iputils-ping wget\n```\n\nAnd now, we will build the image by issuing the next command:\n\n```bash\n$ docker build . -t minicon:ex1fat\n```\n\n\u003e At this point you can check the image, and the commands that it has. You just need to create a container and issue the commands that you want to check: `docker run --rm -it minicon:ex1fat bash`\n\nOnce that we have the image, we will minimize it by issuing the next command:\n\n```bash\n$ minidock -i minicon:ex1fat -t minicon:ex1 --apt -E bash -E 'ssh localhost' \\\n-E ip -E id -E cat -E ls -E mkdir \\\n-E 'ping -c 1 www.google.es' -- wget www.google.es\n```\n\n* Each `-E` flag includes an example of the execution that we want to be able to make in the minimized image.\n* The `--apt` flag is included because we want to minimize an apt-based image (that instructs **minidock** to resolve the dependencies inside the container, using apt commands)\n* The command after `--` is one of the command lines that we should be able to execute in the resulting image.\n\nFinally you can verify that the image has drammatically reduced its size:\n\n```bash\n$ docker images minicon\nREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE\nminicon             ex1                 42a532b9c262        28 minutes ago      10.9MB\nminicon             ex1fat              d3498d9cf260        30 minutes ago      211MB\n```\n\nAt this point you should be able to run one container, using the resulting image:\n\n```dockerfile\n$ docker run --rm -it minicon:ex1 bash\n```\n\nThe whole procedure can be seen in the next asciicast:\n\n[![asciicast](https://asciinema.org/a/165798.png)](https://asciinema.org/a/165798)\n\n### 4.2 Basic CentOS 7 in about 16 Mb.\n\nIn this example we will create the same use-case than in the previous one, but based on a CentOS image: a basic CentOS-based user interface, that include commands like `wget`, `ssh`, `cat`, etc.\n\nThe `centos:latest` image do not contain the needed commands. So we need to create a Docker file that installs `wget`, `ssh`, `ping` and others. We will use this Dockerfile:\n\n```dockerfile\nFROM centos:latest\nRUN yum -y update \u0026\u0026 yum install -y iproute iputils openssh-clients wget\n```\n\nAnd now, we will build the image by issuing the next command:\n\n```bash\n$ docker build . -t minicon:ex1fat\n```\n\n\u003e At this point you can check the image, and the commands that it has. You just need to create a container and issue the commands that you want to check: `docker run --rm -it minicon:ex1fat bash`\n\nOnce that we have the image, we will minimize it by issuing the next command:\n\n```bash\n$ minidock -i minicon:ex1fat -t minicon:ex1 --yum -E bash -E 'ssh localhost' \\\n-E ip -E id -E cat -E ls -E mkdir \\\n-E 'ping -c 1 www.google.es' -- wget www.google.es\n```\n\n* Each `-E` flag includes an example of the execution that we want to be able to make in the minimized image.\n* The `--yum` flag is included because we want to minimize a yum-based image (that instructs **minidock** to resolve the dependencies inside the container used for simulation, using yum commands)\n* The command after `--` is one of the command lines that we should be able to execute in the resulting image.\n\nFinally you can verify that the image has drammatically reduced its size:\n\n```bash\n$ docker images\nREPOSITORY          TAG                 IMAGE ID            CREATED              SIZE\nminicon             ex1                 43d11b4837dd        About a minute ago   16MB\nminicon             ex1fat              66c5aa5bb77b        3 minutes ago        362MB\ncentos              latest              ff426288ea90        7 weeks ago          207MB\n```\n\nAt this point you should be able to run one container, using the resulting image:\n\n```dockerfile\n$ docker run --rm -it minicon:ex1 bash\n```\n\nThe whole procedure can be seen in the next asciicast:\n\n[![asciicast](https://asciinema.org/a/166112.png)](https://asciinema.org/a/166112)\n\n### 4.3 NodeJS application\n\nIn this example, we will start from the default NodeJS image and will pack our freshly created application.\n\nIn first place we are creating an application using express (for our purposes, we are using the default application):\n\n```bash\n$ express myapp\n```\n\nTo dockerize this nodejs application, you can use the default [node image at docker hub](https://hub.docker.com/_/node/), which is based on Debian, and use the next Dockerfile:\n\n```dockerfile\nFROM node\nCOPY myapp /usr/app/myapp\nWORKDIR /usr/app/myapp\nRUN npm install\nENTRYPOINT node ./bin/www\nEXPOSE 3000\n```\n\nNow we can build our application and test it:\n\n```bash\n$ docker build . -t minicon:ex2fat\n$ docker run --rm -id -p 10000:3000 minicon:ex2fat\n5cb83644120c074f799e2ba802f09690054eae48fdb44d92094550de4f895702                                                                                    $ wget -q -O- http://localhost:10000\n\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003ctitle\u003eExpress\u003c/title\u003e\u003clink rel=\"stylesheet\" href=\"/stylesheets/style.css\"\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003eExpress\u003c/h1\u003e\u003cp\u003eWelcome to Express\u003c/p\u003e\u003c/body\u003e\u003c/html\u003e\n```\n\nOnce that we have our application, we can minimize it:\n\n```bash\n$ minidock --apt -i minicon:ex2fat -t minicon:ex2 -I /usr/app/myapp\n```\n\n* The `--apt` flag is included because the original image is based on debian (that instructs **minidock** to resolve the dependencies inside the container, using apt commands)\n* We do not need to include any command to simulate because the original image has an entrypoint defined, which will be simulated.\n* In this example we are not running all the possibilities of our application during the simulation, but we know that the application is stored in `/usr/app/myapp` and that the global modules \n\nWe can test the image:\n\n```bash\n$ docker run --rm -id -p 10001:3000 minicon:ex2 \nfedb5c972e8e47ac02c09661f767156aa88328b1ce72646e717bd60624adefda     \n$ wget -q -O- http://localhost:10001\n\u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003ctitle\u003eExpress\u003c/title\u003e\u003clink rel=\"stylesheet\" href=\"/stylesheets/style.css\"\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003eExpress\u003c/h1\u003e\u003cp\u003eWelcome to Express\u003c/p\u003e\u003c/body\u003e\u003c/html\u003ecalfonso@ubuntu:~/ex2$                  \n```\n\nIf we check the size of the original and the minimized images, we can see that it has been reduced from 686 MB. to 45.6MB. (which is even less than the official node:alpine image).\n```bash\n$ docker images                                                      \nREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE\nminicon             ex2                 1080e761a83c        38 seconds ago      45.6MB                                             \nminicon             ex2fat              7f8bef02d321        4 minutes ago       686MB\nnode                alpine              a88ff852e3d4        4 days ago          68MB\nnode                latest              29831ba76d93        4 days ago          676MB\n```\n\nThe whole procedure can be seen in the next asciicast:\n\n[![asciicast](https://asciinema.org/a/166058.png)](https://asciinema.org/a/166058)\n\n\n### 4.4 Apache server\n\nIn order to have an apache server, according to the Docker docs, you can create the following Dockerfile:\n\n```docker\nFROM ubuntu\nRUN apt-get update \u0026\u0026 apt-get install -y --force-yes apache2\nEXPOSE 80 443\nVOLUME [\"/var/www\", \"/var/log/apache2\", \"/etc/apache2\"]\nENTRYPOINT [\"/usr/sbin/apache2ctl\", \"-D\", \"FOREGROUND\"]\n```\n\nThen you can build it and run it:\n\n```bash\n$ docker build . -t minicon:uc5fat\n...\n$ docker run -id -p 10000:80 minicon:uc5fat\nfe20ebce12f2d5460bb0191975450833117528987c32c95849315bc4330c0f2a\n$ wget -q -O- localhost:10000 | head -n 3\n\n\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"\u003e\n\u003chtml xmlns=\"http://www.w3.org/1999/xhtml\"\u003e\n```\n\nIn this case, the size of the image is about 261MB:\n\n```bash\n$ docker images\nREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE\nminicon             uc5fat              ff6f2573d73b        9 days ago          261MB\n```\n\nIn order to reduce it, you just need to issue the next command:\n```bash\n$ ./minidock -i minicon:uc5fat -t minicon:uc5 --apt\n...\n```\n\n\u003e The flag _--apt_ instructs **minidock** to install the dependencies of minicon using apt-get commands, inside one ephemeral container that will be used for the analysis. It is also possible to use _--yum_, instead of _--apt_.\n\nAnd you will have the minimized apache ready to be run:\n\n```bash\n$ docker run --rm -id -p 10001:80 minicon:uc5\n0e0ef746586fd632877f1c9344b42b4dbb00f52dc2a5d06028cbfa72bd297d6c\n$ wget -q -O- localhost:10001 | head -n 3\n\n\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"\u003e\n\u003chtml xmlns=\"http://www.w3.org/1999/xhtml\"\u003e\n```\n\nBut in this case, the footprint of the apache image has been reduced to 50.4MB:\n\n```bash\n$ docker images\nREPOSITORY          TAG                 IMAGE ID            CREATED              SIZE\nminicon             uc5                 f577e1f6e3f8        About a minute ago   50.4MB\nminicon             uc5fat              ff6f2573d73b        9 days ago           261MB\n```\n\n### 4.5 cowsay: Docker image with Entrypoint with parameters\n\nIn order to have a simple cowsay application you can create the following Dockerfile:\n\n```docker\nFROM ubuntu\nRUN apt-get update \u0026\u0026 apt-get install -y cowsay\nENTRYPOINT [\"/usr/games/cowsay\"]\n```\n\nThen you can build it and run it:\n\n```bash\n$ docker build . -t minicon:uc6fat\n...\n$ docker run --rm -it minicon:uc6fat i am a cow in a fat container\n _______________________________\n\u003c i am a cow in a fat container \u003e\n -------------------------------\n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n                ||----w |\n                ||     ||\n```\n\nIn this case, the entrypoint needs some parameters to be run. If you try to analyze the container simply issuing a command like the next one:\n\n```bash\n$ ./minidock -i minicon:uc6fat -t minicon:uc6 --apt\n...\n$ docker run --rm -it minicon:uc6 i am a cow in a not properly minimized container\ncowsay: Could not find default.cow cowfile!\n```\n\nIt does not work properly, because the execution of the entrypoint has not been successfully simulated (cowsay needs some parameters to run).\n\nIn this case, you should run a **minidock** commandline that include the command that we used to test it, and we will be able to run it:\n\n```bash\n$ ./minidock -i minicon:uc6fat -t minicon:uc6 --apt -- i am a cow in a fat container\n...\n$ docker run --rm -it minicon:uc6 i am a cow in a minimized container\n _____________________________________\n\u003c i am a cow in a minimized container \u003e\n -------------------------------------\n        \\   ^__^\n         \\  (oo)\\_______\n            (__)\\       )\\/\\\n                ||----w |\n                ||     ||\n```\n\n\u003e after the -- flag, we can include those parameters that we use in a docker run execution.\n\nWe can check the differences in the sizes:\n\n```bash\n$ docker images minicon\nREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE\nminicon             uc6                 7c85b5a104f5        5 seconds ago       5.81MB\nminicon             uc6fat              1c8179d3ba94        4 hours ago         206MB\n```\n\nIn this case, the size has been reduced from 206MB to about 5.81MB.\n","funding_links":[],"categories":["Shell"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrycap%2Fminicon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrycap%2Fminicon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrycap%2Fminicon/lists"}