{"id":13416465,"url":"https://github.com/djosephsen/skinnywhale","last_synced_at":"2026-01-22T02:29:24.595Z","repository":{"id":34782369,"uuid":"38765440","full_name":"djosephsen/skinnywhale","owner":"djosephsen","description":"Skinnywhale helps you make smaller (as in megabytes) Docker containers","archived":false,"fork":false,"pushed_at":"2017-10-30T02:24:02.000Z","size":157,"stargazers_count":183,"open_issues_count":3,"forks_count":11,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-07-31T21:56:53.176Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/djosephsen.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":"2015-07-08T16:17:54.000Z","updated_at":"2024-07-12T09:24:04.000Z","dependencies_parsed_at":"2022-09-15T07:02:38.961Z","dependency_job_id":null,"html_url":"https://github.com/djosephsen/skinnywhale","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/djosephsen%2Fskinnywhale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/djosephsen%2Fskinnywhale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/djosephsen%2Fskinnywhale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/djosephsen%2Fskinnywhale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/djosephsen","download_url":"https://codeload.github.com/djosephsen/skinnywhale/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243667680,"owners_count":20328032,"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":[],"created_at":"2024-07-30T21:00:59.213Z","updated_at":"2026-01-22T02:29:24.585Z","avatar_url":"https://github.com/djosephsen.png","language":"Shell","funding_links":[],"categories":["Docker Images","Optimizing Images","Infrastructure \u0026 DevOps","Shell"],"sub_categories":["Builder"],"readme":"# skinnywhale\nSkinnywhale helps you make smaller (as in megabytes) Docker containers\n\n```\n--- Skinny whale is positively starving ---\n\n                    ##        .\n              ## ## ##       ==\n           ## ## ## ##      ===\n       /\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\\___/ ===\n      /\trX\n  ~~~{ /\\ ~ ~~~ ~~~~ ~~ ~ /  ===- ~~~\n       \\______////////////__/\n```\n\nIf, for example, you want to run a python script in a container, normally you'd\nhave to download a 600MB image that had the python interpretor along with most\nof an OS inside it. Skinnywhale helps you isolate runtime environments like\npython, ruby, and java, and throw the rest of the stuff away, so the images you\nmake with it are normally hundreds of megs smaller than their bloated\ncounterparts. Starting from a generic Ubuntu Docker image, my Skinnywhale\nPython images usually come out to be around 30MB. Here's how you use it:\n\n## step 1. Start with a normal fat image\n\n``` docker run -ti ubuntu ```\n\n## step 2. Add the stuff you need to it (creates a new container)\n\n``` \napt-get update\napt-get install python3\nexit\n\ndocker ps -a\n\u003ccopy the container ID you just created eg.. 8efbc5497abb\u003e\n```\n\n## step 3. use skinnywhale to isolate the stuff you just added\n\n```\nskinnywhale 8efbc5497abb\n```\n\nSkinnywhale requires that you're using an *aufs-backed* docker that is version\n1.6 or later (there are bugs earlier than that which cause \"file not found\"\nerrors on images imported from tarballs)\n\nYou can see what kind of back-end you have with:\n\n```\n#  docker info\nContainers: 2\nImages: 7\nStorage Driver: aufs\n Root Dir: /var/lib/docker/aufs\n Backing Filesystem: extfs\n Dirs: 11\n Dirperm1 Supported: false\n```\n\nIf you're on ubuntu and your docker is not using aufs, it's probably because\nyou're missing the linux-image-extra package. Try running: \n\n```\napt-get -y install linux-image-extra-$(uname -r)\nservice docker restart\ndocker info\n```\n\nANYWAY if everything went ok, skinnywhale will write a \"skinny\" version of the\ncontainer you listed as an image. You should see it listed in *docker images*.\nYou can specify this image in a Dockerfile like so:\n\n```\nFROM skinny_8efbc5497abb\nADD  myPythonScript.py /\nCMD [\"/usr/bin/python\", \"myPythonScript.py\"]\n```\nNow build it: \n\n```\ndocker build -t myTeensyAppContainer .\n```\n...and now you have a dockerized version of your app that contains only your\nscript and the runtime needed to execute it (and not the entire rest of ubuntu\nor whatever). \n\n## A few Options\nSkinnywhale uses environment variables to control a few options: \n\n* DEBUG : enable debug mode\n* NOCLEANUP : don't clean up the working directories in /tmp\n* BRUTELIB : brute-force copy the entire /lib directory from the fat image (try this if you're having name resolver issues etc..\n* BRUTEUSRLIB : brute-force copy the entire /usr/lib directory from the fat image. \n\n## How does this work?\nSkinnywhale is pretty simple, it finds the aufs path for the container ID you\ngive it, and walks through it looking for binary files that are dynamically\nlinked. Skinnywhale resolves each of these dependencies by copying the linked\nlibrary files in from the parent image. It then tars up the resulting\nfilesystem and *docker import*s it. \n\nThere are two caveats to this process. First, some binary-distributed runtime\nenvironments (like the oracle JDK), contain files that link to libs that may\nnot be installed on the client (if, for example you're using a base-image that\ndoesn't have Xorg installed, the JDK WILL have binary files that are linked to\nX11 libs that don't exist on your base image). This is not usually a problem;\nas long as your app works with the base image you're trying to use, it should\nalso work post-skinnywhale. \n\nSecond, Skinnywhale can't detect if your runtime uses dlOpen(). You're on\nyour own there I'm afraid. FWIW I've been using skinnywhale for python and\njava stuff at work, and in practice I've found this not to be an issue.  If\nyou're having trouble getting stuff to run after it's been skinnywhaled, try\nsetting the BRUTE variables described above.  Chances are, if someone is using\ndlOpen(), those libs are going to be part of the distribution files for the\nruntime (ie you aren't going to assume a lib file is lying around somewhere\nunless *you* put it there, (unless you're silly or mean)), and since\nskinnywhale grabs the entire runtime, it *ought* to be pretty safe with respect\nto dlOpen'd stuff. YMMV.  Caveat emptor. etc...\n\n## No I mean *HOW* does this work?\nOh. Pretty well I guess? Java images are still stupid big, because java is\nstupid big. Skinnywhale is irrelevant for Go because static binaries. It gets a\npython runtime down to about 33MB, but yeah, the jvm environments are still\nlike 370MB (it is what it is.  Still beats the gigabyte-sized java images\nfloating around in the public registries).\n\nSince skinnywhale is really just using the diff functionality built-in to aufs,\nit's completely agnostic to factors like the OS of your base-image. So if you\nstart with a busy-box image, and use skinnywhale to isolate the java-runtime\nfrom that, you may end up with something smaller. The relevant factor is how\nmuch crap the package-manager in your base-image vomits into the file system\nwhen you use it to install something like Java. Good luck!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdjosephsen%2Fskinnywhale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdjosephsen%2Fskinnywhale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdjosephsen%2Fskinnywhale/lists"}