{"id":15698969,"url":"https://github.com/developer-guy/tini-and-distroless-poc","last_synced_at":"2025-10-26T17:55:22.590Z","repository":{"id":54670175,"uuid":"334627166","full_name":"developer-guy/tini-and-distroless-poc","owner":"developer-guy","description":"Demonstration of how you can use tini-static and the distroless base image for go","archived":false,"fork":false,"pushed_at":"2021-02-04T17:58:16.000Z","size":474,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-09T02:16:59.828Z","etag":null,"topics":["distroless","go","golang","init-system","tini"],"latest_commit_sha":null,"homepage":"","language":"Go","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/developer-guy.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}},"created_at":"2021-01-31T10:22:25.000Z","updated_at":"2025-03-24T22:34:32.000Z","dependencies_parsed_at":"2022-08-13T23:30:25.151Z","dependency_job_id":null,"html_url":"https://github.com/developer-guy/tini-and-distroless-poc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/developer-guy/tini-and-distroless-poc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developer-guy%2Ftini-and-distroless-poc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developer-guy%2Ftini-and-distroless-poc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developer-guy%2Ftini-and-distroless-poc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developer-guy%2Ftini-and-distroless-poc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/developer-guy","download_url":"https://codeload.github.com/developer-guy/tini-and-distroless-poc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/developer-guy%2Ftini-and-distroless-poc/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259835380,"owners_count":22918975,"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":["distroless","go","golang","init-system","tini"],"created_at":"2024-10-03T19:36:52.025Z","updated_at":"2025-10-26T17:55:17.549Z","avatar_url":"https://github.com/developer-guy.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tini-and-distroless-poc\nDemonstration of how you can use tini-static and the distroless base image for go\n\n![syscallvsexec](./syscall_vs_exec.png)\n\n## Statically vs Dynamically Linking\nA statically linked program has all of it's dependencies compiled into the executable. In this case it does not need to load or utilize any other libraries or code. While a dynamically linked program has external dependencies that need to be present and are loaded during execution.\n\nOne of the reasons I love working with GO is because I can compile go code into a statically linked binary. Why bother? Well, it's hard to answer but simply putting it everything is needs is right inside the binary as opposed to a dynamically linked binary. A dynamically linked binary is usually smaller in size as it dynamically links to it's dependencies installed on an OS. Lets take LibC for example, LibC contain certain library functions required by the application code, when I run a dynamically linked binary, it will link to whatever LibC found on the system whereas a statically linked binary has LibC (and other dependent libraries) embeded inside the binary itself hence statically linked binary is larger in size but does not use any of the system libraries. It has many advantages but those are out of scope of this article. This article answers How and assumes you know Why.\n\n\u003e Credit: https://oddcode.daveamit.com/2018/08/16/statically-compile-golang-binary/\n\n### Container init process\nA container’s main running process is the ENTRYPOINT and/or CMD at the end of the Dockerfile. It is generally recommended that you separate areas of concern by using one service per container. That service may fork into multiple processes (for example, Apache web server starts multiple worker processes). It’s ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application. You can connect multiple containers using user-defined networks and shared volumes.\n\nThe container’s main process is responsible for managing all processes that it starts. In some cases, the main process isn’t well-designed, and doesn’t handle “reaping” (stopping) child processes gracefully when the container exits. If your process falls into this category, you can use the --init option when you run the container. The --init flag inserts a tiny init-process into the container as the main process, and handles reaping of all processes when the container exits. Handling such processes this way is superior to using a full-fledged init process such as sysvinit, upstart, or systemd to handle process lifecycle within your container.\n\n\u003e Credit: https://docs.docker.com/config/containers/multi-service_container/\n\n### \"Distroless\" Docker Images\n\"Distroless\" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.\n\n### Hands On\nIn this demo, we are going to demonstrate how we use an init-system for our container with the distroless base image at the final layer.To do so, we need to use an init-system which is statically linked and also a Go binary which is also statically linked. We are going to use [Tini as a init-system](https://github.com/krallin/tini) for our container and a [static-debian distroless image](gcr.io/distroless/static-debian10) as our base image for final image.\n\nLet's see what is inside of our Dockerfile.\n```Dockerfile\n# Specify base image\nFROM golang:1.15.7-alpine as builder\n\n# Specify working directory\nWORKDIR /app\n\n# Add Tini init-system\nENV TINI_VERSION v0.19.0\nADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static /tini\nRUN chmod +x /tini\n\n# Define environment variables for go build time\nENV CGO_ENABLED=0 \\\n    GOOS=linux \\\n    GOARCH=amd64\n\n# Efficient cache usage\nCOPY go.mod go.sum ./\nRUN go mod download\n\n# Copy everything from host to the image\nCOPY . .\n\n# Build statically compiled binary\nRUN go build -o hello-world\n\nFROM gcr.io/distroless/static-debian10\n\nCOPY --from=builder /app/hello-world ./\nCOPY --from=builder /tini /tini\n\nENTRYPOINT [\"/tini\", \"--\"]\nCMD [\"./hello-world\"]\n```\nYou should notice that we are using a tini-static binary instead of tini because we are using an static-debian image for our final image,so we need a statically linked version of tini, also, we disable the CGO using CGO_ENABLED environment variable to be able to build statically linked Go binary.\n\nThen look inside of the Go program, it is very straightforward. We'll start a sleep process then we'll display the parent and child  relationship of it using [go-ps package](https://github.com/mitchellh/go-ps).\n\n```golang\npackage main\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/mitchellh/go-ps\"\n)\n\nfunc main() {\n\tlist, err := ps.Processes()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfor _, p := range list {\n\t\tlog.Printf(\"Process %s with PID %d and PPID %d\", p.Executable(), p.Pid(), p.PPid())\n\t}\n\n\ttime.Sleep(3600 * time.Second)\n}\n\n```\n\nLet's build our docker image and start the container.\n```bash\n$ docker buildx build -t tini-with-distroless:0.0.1 .\n[+] Building 1.8s (18/18) FINISHED\n=\u003e [internal] load build definition from Dockerfile     0.0s                                                                    \n=\u003e transferring dockerfile: 32B                         0.0s\n=\u003e [internal] load .dockerignore                        0.0s                                                                        ...\n\n$ docker container run tini-with-distroless:0.0.1\n2021/01/31 10:50:57 Process tini with PID 1 and PPID 0\n2021/01/31 10:50:57 Process hello-world with PID 8 and PPID 1\n```\nYou should see the similar output above.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeveloper-guy%2Ftini-and-distroless-poc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeveloper-guy%2Ftini-and-distroless-poc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeveloper-guy%2Ftini-and-distroless-poc/lists"}