4g8znw
Last Updated: September 23, 2016
·
22.65K
· murphyrandle
621103 10151814410385600 1552271139 o

Things I learned while writing a Dockerfile

I've been writing a Dockerfile for work that installs Postgresql and sets up a database. I ran into a few gotchas along the way. Here's the documentation of my misconceptions and the solutions.

One Line VS Multiple Lines

I originally was using one RUN command per shell line that I wanted to exectue:

Example:

RUN service postgresql start 
RUN su postgres -c "createuser -d -r -s root" 

The Problem

I wanted to separate the commands in order to optimize recreation of other images. But I'd always get the error that postgres wasn't running. That's exactly because each RUN command is a separate layer of running machine. Starting postgres in a RUN command does nothing because as soon as the next RUN command is reached, I'm in a new VM, and there's no postgres running at all.

The Solution

Join commands that are part of one cohesive set up step into one RUN statement:
(Note, thanks @outrunthewolf for pointing out that line continuations \ can be used to carry the same command across multiple lines for readability).

RUN service postgresql start && \
    su postgres -c "createuser -d -r -s root"

sudo VS su

The Problem

Online guides for installing and setting up postgres instruct the user to run commands as sudo, but this won't work with a Dockerfile because the commands are running as root, and root doesn't have access to the sudo command.

The Solution

Use su {USER} -c "commands go here" instead to execute commands as a different user.

An example Dockerfile

Here's an example Dockerfile that installs postgresql, creates a root role, and creates a database called accounts.

FROM ubuntu
MAINTAINER Murphy Randle, murphy@spacemonkey.com

# Install Postgresql deps
RUN apt-get install -y postgresql postgresql-contrib

# Postgresql setup:
RUN service postgresql start && su postgres -c "createuser -d -r -s root" && createdb accounts && service postgresql stop

ENTRYPOINT ["/bin/bash"]
Say Thanks
Respond

7 Responses
Add your response

12344
C3ebe9f9cff5d0d925e5e52f8f869f49

You should maintain multiple lines for readability by adding && \ and dropping your command to the next line.

over 1 year ago ·
12347
621103 10151814410385600 1552271139 o

That's a good point, @outrunthewolf! Thanks!

over 1 year ago ·
15282
66c0c559b243e2a6d0aafc170642b362

Thanks for the tip on running su from inside a dockerfile. It was exactly what I needed.

over 1 year ago ·
18059
None

Currently docker allows for even cleaner approch. You can just swap to specific user for next run commands. See:

RUN id
USER app
ENV HOME /app
RUN id

PS: I tend to add ENV HOME as some scripts (i.e. bower) want's to edit files in ${HOME}/.config.bla

over 1 year ago ·
18060
None

hmm... unknown text processor. Let's try again :)

RUN id

USER app

ENV HOME /app

RUN id

over 1 year ago ·
18226
None

@munhitsu
The USER command is useful when all RUN statements can be executed as that user. But what about when specific RUN commands need to be done under specific users? Can the USER command be used more than once in a Dockerfile?

Eg:

USER root

RUN echo 'export ORACLE_SID=XE' >> /etc/bash.bashrc

USER oracle

RUN sqplus @my_schema.sql

over 1 year ago ·
18227
None

Yes, that's exactly how it works. You can use USER as many times as you want.

over 1 year ago ·
Filed Under