## 1. Project Overview & Quickstart (tianon/gosu) # gosu This is a simple tool grown out of the simple fact that `su` and `sudo` have very strange and often annoying TTY and signal-forwarding behavior. They're also somewhat complex to setup and use (especially in the case of `sudo`), which allows for a great deal of expressivity, but falls flat if all you need is "run this specific application as this specific user and get out of the pipeline". The core of how `gosu` works is stolen directly from how Docker/libcontainer itself starts an application inside a container (and in fact, is using the `/etc/passwd` processing code directly from libcontainer's codebase). ```console $ gosu Usage: ./gosu user-spec command [args] eg: ./gosu tianon bash ./gosu nobody:root bash -c 'whoami && id' ./gosu 1000:1 id ./gosu version: 1.1 (go1.3.1 on linux/amd64; gc) ``` Once the user/group is processed, we switch to that user, then we `exec` the specified process and `gosu` itself is no longer resident or involved in the process lifecycle at all. This avoids all the issues of signal passing and TTY, and punts them to the process invoking `gosu` and the process being invoked by `gosu`, where they belong. ## Warning The core use case for `gosu` is to step _down_ from `root` to a non-privileged user during container startup (specifically in the `ENTRYPOINT`, usually). Uses of `gosu` beyond that could very well suffer from vulnerabilities such as CVE-2016-2779 (from which the Docker use case naturally shields us); see [`tianon/gosu#37`](https://github.com/tianon/gosu/issues/37) for some discussion around this point. ## Installation High-level steps: 1. download `gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }')` as `gosu` 2. download `gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }').asc` as `gosu.asc` 3. fetch my public key (to verify your download): `gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4` 4. `gpg --batch --verify gosu.asc gosu` 5. `chmod +x gosu` For explicit `Dockerfile` instructions, see [`INSTALL.md`](INSTALL.md). ## Why? ```console $ docker run -it --rm ubuntu:trusty su -c 'exec ps aux' USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 46636 2688 ? Ss+ 02:22 0:00 su -c exec ps a root 6 0.0 0.0 15576 2220 ? Rs 02:22 0:00 ps aux $ docker run -it --rm ubuntu:trusty sudo ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 3.0 0.0 46020 3144 ? Ss+ 02:22 0:00 sudo ps aux root 7 0.0 0.0 15576 2172 ? R+ 02:22 0:00 ps aux $ docker run -it --rm -v $PWD/gosu-amd64:/usr/local/bin/gosu:ro ubuntu:trusty gosu root ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 7140 768 ? Rs+ 02:22 0:00 ps aux ``` Additionally, due to the fact that `gosu` is using Docker's own code for processing these `user:group`, it has exact 1:1 parity with Docker's own `--user` flag. If you're curious about the edge cases that `gosu` handles, see [`Dockerfile.test-alpine`](Dockerfile.test-alpine) for the "test suite" (and the associated [`test.sh`](test.sh) script that wraps this up for testing arbitrary binaries). (Note that `sudo` has different goals from this project, and it is *not* intended to be a `sudo` replacement; for example, see [this Stack Overflow answer](https://stackoverflow.com/a/48105623/433558) for a short explanation of why `sudo` does `fork`+`exec` instead of just `exec`.) ## Alternatives ### `setpriv` Available in newer `util-linux` (`>= 2.32.1-0.2`, in Debian; https://manpages.debian.org/buster/util-linux/setpriv.1.en.html): ```console $ docker run -it --rm buildpack-deps:buster-scm setpriv --reuid=nobody --regid=nogroup --init-groups ps faux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND nobody 1 5.0 0.0 9592 1252 pts/0 RNs+ 23:21 0:00 ps faux ``` ### `chroot` With the `--userspec` flag, `chroot` can provide similar benefits/behavior: ```console $ docker run -it --rm ubuntu:trusty chroot --userspec=nobody / ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND nobody 1 5.0 0.0 7136 756 ? Rs+ 17:04 0:00 ps aux ``` ### `su-exec` In the Alpine Linux ecosystem, [`su-exec`](https://github.com/ncopa/su-exec) is a minimal re-write of `gosu` in C, making for a much smaller binary, and is available in the `main` Alpine package repository. Versions older than 0.3 had [a pretty severe parser bug](https://github.com/ncopa/su-exec/pull/26), so make sure you're using version 0.3 or above. ### Others I'm not terribly familiar with them, but a few other alternatives I'm aware of include: - `chpst` (part of `runit`) ## 2. Official Technical Reference & Guides (tianon/docs) # What is this? This repository contains the docs for each of the Docker official images. See [docker-library/official-images](https://github.com/docker-library/official-images) for the configuration how the images are built. To see all of the official images go to the [hub](https://hub.docker.com/explore/). All Markdown files here are run through [tianon's fork of `markdownfmt`](https://github.com/tianon/markdownfmt) (only forked to add some smaller-diff preference and minor DockerHub-compatibility changes), and verified as formatted correctly via Travis-CI. - [Travis CI: ](https://travis-ci.org/docker-library/docs) - [Automated `update.sh` and `push.sh`: ](https://doi-janky.infosiftr.net/job/docs/job/update/) # How do I add a new image's docs - create a folder for my image: `mkdir myimage` - create a `README-short.txt` (required, 100 char max) - create a `content.md` (required) - create a `license.md` (required) - create a `github-repo` (required) - add a `logo.png` (recommended) Optionally: - run `./update.sh myimage` to generate `myimage/README.md` for your review. **Note:** do not actually commit the `README.md` file; it is automatically generated/committed before being uploaded to Docker Hub. - run `./markdownfmt.sh -l myimage` to verify whether format of your markdown files is compliant to `tianon/markdownfmt`. In case you see any file names, markdownfmt detected some issues, which might result in a failed build during continuous integration. run `./markdownfmt.sh -d myimage` to see a diff of changes required to pass. # How do I update an image's docs To update `README.md` for a specific image do not edit `README.md` directly. Please edit `content.md` or another appropriate file within the folder. To see the changes, run `./update.sh myimage` from the repo root, but do not add the `README.md` changes to your pull request. See also `markdownfmt.sh` point [above](#how-do-i-add-a-new-images-docs). # What are all these files? ## `update.sh` This is the main script used to generate the `README.md` files for each image. The generated file is committed along with the files used to generate it (see below on what customizations are available). Accepted arguments are which image(s) you want to update or no arguments to update all of them. ## `generate-repo-stub-readme.sh` This is used to generate a simple `README.md` to put in the image's repo. Argument is the name of the image, like `golang` and it then outputs the readme to standard out. ## `push.pl` This is used by us to push the actual content of the READMEs to the Docker Hub as special access is required to modify the Hub description contents. ## `.template-helpers/generate-dockerfile-links-partial.sh` This script is used by `update.sh` to create the "Supported tags and respective `Dockerfile` links" section of each generated `README.md` from the information in the [official-images `library/` manifests](https://github.com/docker-library/official-images/tree/master/library). ## `.template-helpers/template.md` and `.template-helpers/user-feedback.md` These files are the templates used in building the `/README.md` file, in combination with the individual image's files. ## folder `` This is where all the partial and generated files for a given image reside, (ex: `golang/`). ## `/README.md` This file is generated using `update.sh`. ## `/content.md` This file contains the main content of your image's long description. The basic parts you should have are a "What Is" section and a "How To" section. See the doc on [Official Repos](https://docs.docker.com/docker-hub/official_repos/#a-long-description) for more information on long description. The issues and contribution section is generated by the script but can be overridden. The following is a basic layout: ```markdown # What is XYZ? // about what the contained software is %%LOGO%% # How to use this image // descriptions and examples of common use cases for the image // make use of subsections as necessary ``` ## `/README-short.txt` This is the short description for the docker hub, limited to 100 characters in a single line. > Go (golang) is a general purpose, higher-level, imperative programming language. ## `/logo.png` Logo for the contained software. While there are not hard rules on formatting, most existing logos are square or landscape and stay within a few hundred pixels of width. ## `/license.md` This file should contain a link to the license for the main software in the image. Here is an example for `golang`: ```markdown View [license information](http://golang.org/LICENSE) for the software contained in this image. ``` ## `/github-repo` This file should contain the URL to the GitHub repository for the Dockerfiles that become the images. The file should be in a single line ending in a newline with no extraneous whitespace. Only one GitHub repo per image repository is supported. It is used in generating links. Here is an example for `golang`: ```text https://github.com/docker-library/golang ``` ## `/user-feedback.md` This file is an optional override of the default `user-feedback.md` for those repositories with different issue and contributing policies. # Issues and Contributing If you would like to make a new Official Image, be sure to follow the [guidelines](https://docs.docker.com/docker-hub/official_repos/). Feel free to make a pull request for fixes and improvements to current documentation. For questions or problems on this repo come talk to us via the `#docker-library` IRC channel on [Freenode](https://freenode.net) or open up an issue.