259

I'm using alpine (or an image that is based on Alpine) as the base image in my Dockerfile. Which instructions do I need to add to create a user?

Eventually I'll use this user to run the application I'll place into the container so that the root user does not.

gunr2171
  • 16,104
  • 25
  • 61
  • 88
Daniel Gartmann
  • 11,678
  • 12
  • 45
  • 60

3 Answers3

442

Alpine uses the command adduser and addgroup for creating users and groups (rather than useradd and usergroup).

FROM alpine:latest

# Create a group and user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# Tell docker that all future commands should run as the appuser user
USER appuser

The flags for adduser are:

Usage: adduser [OPTIONS] USER [GROUP]

Create new user, or add USER to GROUP

        -h DIR          Home directory
        -g GECOS        GECOS field
        -s SHELL        Login shell
        -G GRP          Group
        -S              Create a system user
        -D              Don't assign a password
        -H              Don't create home directory
        -u UID          User id
        -k SKEL         Skeleton directory (/etc/skel)

Add new user official docs

mrroot5
  • 1,811
  • 3
  • 28
  • 33
Daniel Gartmann
  • 11,678
  • 12
  • 45
  • 60
  • 13
    Or alternatively, you can replace the whole snippet above using this: ```USER 405``` which is the guest user within Alpine Linux. – Daniel Gartmann Jun 02 '18 at 12:14
  • 13
    Why not `USER guest`? – user672009 Sep 26 '18 at 22:22
  • 3
    I'd go with creating a new user because I want that user to have the same UID/GID as the one on the host OS, so that there's no permission issue when running docker in Linux. (not an issue with macOS/Windows users) – elquimista Oct 17 '18 at 18:29
  • 17
    Note that since Alpine is based on BusyBox, its `adduser` and `addgroup` commands are different from `adduser` and `addgroup` as provided by Debian and Ubuntu which in turn are front ends to `useradd` and `groupadd`. Notably, the Debian and Ubuntu commands only support long form options. See: https://manpages.debian.org/stretch/adduser/adduser.8.en.html – Jack Mar 03 '19 at 03:43
  • I've already created a docker container, now what command do I need to run to add a user? – Aashish Kumar Dec 16 '19 at 19:33
  • Or Alternatively, you can use https://github.com/docker-library/httpd/issues/102#issuecomment-404637485 – Yogi Ghorecha Dec 19 '19 at 10:17
  • Why are these short hand flags not documented in the official docs? edit: apparently this command is added by busybox: https://busybox.net/downloads/BusyBox.html – 99linesofcode Jun 04 '20 at 11:51
  • 3
    What's a "system" user? – xpmatteo Dec 30 '21 at 13:20
153

The commands are adduser and addgroup.

Here's a template for Docker you can use in busybox environments (alpine) as well as Debian-based environments (Ubuntu, etc.):

ENV USER=docker
ENV UID=12345
ENV GID=23456

RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "$(pwd)" \
    --ingroup "$USER" \
    --no-create-home \
    --uid "$UID" \
    "$USER"

Note the following:

  • --disabled-password prevents prompt for a password
  • --gecos "" circumvents the prompt for "Full Name" etc. on Debian-based systems
  • --home "$(pwd)" sets the user's home to the WORKDIR. You may not want this.
  • --no-create-home prevents cruft getting copied into the directory from /etc/skel

The usage description for these applications is missing the long flags present in the code for adduser and addgroup.

The following long-form flags should work both in alpine as well as debian-derivatives:

adduser

BusyBox v1.28.4 (2018-05-30 10:45:57 UTC) multi-call binary.

Usage: adduser [OPTIONS] USER [GROUP]

Create new user, or add USER to GROUP

        --home DIR           Home directory
        --gecos GECOS        GECOS field
        --shell SHELL        Login shell
        --ingroup GRP        Group (by name)
        --system             Create a system user
        --disabled-password  Don't assign a password
        --no-create-home     Don't create home directory
        --uid UID            User id

One thing to note is that if --ingroup isn't set then the GID is assigned to match the UID. If the GID corresponding to the provided UID already exists adduser will fail.

addgroup

BusyBox v1.28.4 (2018-05-30 10:45:57 UTC) multi-call binary.

Usage: addgroup [-g GID] [-S] [USER] GROUP

Add a group or add a user to a group

        --gid GID  Group id
        --system   Create a system group

I discovered all of this while trying to write my own alternative to the fixuid project for running containers as the hosts UID/GID.

My entrypoint helper script can be found on GitHub.

The intent is to prepend that script as the first argument to ENTRYPOINT which should cause Docker to infer UID and GID from a relevant bind mount.

An environment variable "TEMPLATE" may be required to determine where the permissions should be inferred from.

(At the time of writing I don't have documentation for my script. It's still on the todo list!!)

rexypoo
  • 1,697
  • 1
  • 6
  • 10
  • 28
    +1, using long form for command args increases readability and makes maintenance easier. When writing shell scripts always use the long form (Dockerfile RUN *is* nothing else than a shell script). – Victor Schröder Sep 05 '19 at 20:25
  • Great answer, and thank for sharing your script. I am interested in retaining the host uid/gid: on debian based images my approach consisted in passing these over through env variables or infer from a bound workspace folder. All this was made easier by using commands `useradd/groupadd` with the `--non-unique` flag. Is there anyway to create duplicate id users/groups in alpine? – n1nsa1d00 Jul 01 '21 at 10:37
  • 2
    I found an answer to my question: installing `shadow`. – n1nsa1d00 Jul 01 '21 at 11:22
  • Using this in an entrypoint is probably not sufficient, because you start the container as root. What stops the user from exiting back to root? – The Fool Mar 11 '22 at 21:23
  • 1
    Isn't `--ingroup "$USER"` supposed to be `--ingroup "$GID"`? I'm confused. – Thegerdfather Apr 10 '22 at 06:34
  • Is `RUN adduser` even necessary? Why don't we just use `USER 10001:10001` in the `Dockerfile`? – Jason Rich Darmawan Sep 14 '22 at 00:20
  • 1
    @Thegerdfather you're right. Without that, the build will fail (and `$GID` would be useless). The group needs to exist already, too – TBG May 21 '23 at 14:33
14

There is package shadow that brings useradd & usermod.

adduser has some stupid limitations:

$ sudo adduser --disabled-password root
adduser: user 'root' in use

but usermod doesn't:

$ sudo apk add shadow
$ sudo usermod --unlock root
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 1
    shadow also includes groupadd too and makes alpine consistent in this regard with other distros so if you have a multi distro script (e.g. docker) using these then just install shadow when spinning up an alpine container and your script will work anywhere. – DKebler Apr 13 '23 at 05:35