Docker: bad advice

Docker: bad advice

When I learned to drive a car, at the very first lesson, the instructor drove to the intersection in reverse, and then said that it was impossible to do this - never at all. I remembered this rule immediately and for the rest of my life.

You read Grigory Oster's "Bad Advice" to children, and you see how easily and naturally it dawns on them that this is not the way to do it.

A lot of articles have been written about how to write a Dockerfile correctly. But I did not come across instructions on how to write the wrong Dockerfile. I am filling this gap. And maybe in the projects that I receive for support, there will be fewer such dockerfiles.

All characters, situations and Dockerfile are fictitious. If you recognize yourself, sorry.

Create a Dockerfile, ominous and terrible

Peter (Senior java/rubby/php developer): Colleague Vasily, have you uploaded a new module to Docker yet?
Vasily (junior): No, I didn’t have time, I can’t deal with this Docker. So many articles on it, eyes run wide.

Peter: We had a deadline a year ago. Let's help, we'll figure it out in the process. Tell me what you can't do there.

Vasily: I can’t choose a base image so that it’s minimal, but everything you need is there.
Peter: Get the ubuntu image, it has everything you need. And what a lot of superfluous, then it will come in handy. And don't forget to put the latest tag so that the version is always the latest.

And the first line appears in the Dockerfile:

FROM ubuntu:latest

Peter: What's next, on what we wrote our module?
Vasily: So ruby, the web server and a couple of service daemons should be launched there.
Peter: Yeah, what do we need: ruby, bundler, nodejs, imagemagick and what else... And at the same time, do an upgrade to get new packages for sure.
Vasily: And we will not create a user, so as not from under root?
Peter: Oh, well, then you have to fool around with the rights.
Vasily: I need time, about 15 minutes, to mold it all into one command, I read that ...
(Peter rudely interrupts the meticulous and very smart June.)
Peter: Write in separate commands, and it will be easier to read.

Dockerfile grows:

FROM ubuntu:latest
RUN apt-get update
RUN apt-get upgrade
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full
RUN gem install bundler
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
RUN bundle install --without development test --path vendor/bundle
RUN rm -rf /usr/local/bundle/cache/*.gem 
RUN apt-get clean 
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

Then Igor Ivanovich, DevOps (but more Ops than Dev) bursts into the office, shouting:

AI: Petya, your developers broke the database again, when will it be over….

After a small skirmish, Igor Ivanovich cools down and begins to find out what his colleagues are doing here.

AI: What are you doing?
Vasiliy: Piotr helps me compose a Dockerfile for the new module.
AI: Let me see... What did you write here, you clean the repository with a separate command, this is an additional layer... But how do you install dependencies if you haven't copied the Gemfile! And in general, this is no good.
Peter: Please go about your business, we'll figure it out somehow.

Igor Ivanovich sighs sadly and leaves to figure out if someone has broken the database.

Peter: Yes, but he was right about the code, we need to stuff it into the image. And let's immediately install ssh and supervisor, otherwise how will we start the demons.

Vasily: Then I will first copy the Gemfile and Gemfile.lock, then I will install everything, and then I will copy the entire project. If the Gemfile does not change, the layer will be taken from the cache.
Peter: What are you all with these layers, copy everything at once. Copy right away. The very first line.

Dockerfile now looks like this:

FROM ubuntu:latest
COPY ./ /app
WORKDIR /app
RUN apt-get update
RUN apt-get upgrade
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
RUN gem install bundler
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs

RUN bundle install --without development test --path vendor/bundle
RUN rm -rf /usr/local/bundle/cache/*.gem 
RUN apt-get clean 
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 

Peter: So, what's next. Do you have supervisor configs?
Vasily: No, no. But I will do it quickly.
Peter: Then do it. Let's now sketch out an init script that will run everything. So, sir, run ssh with nohup so we can connect to the container and see what went wrong. Then just start supervisor. Well, then just run passenger.
Q: But I read that there should be a single process so Docker knows something went wrong and can restart the container.
P: Do not fill your head with nonsense. And in general, how? How do you run it all in one process? Let Igor Ivanovich think about stability, it is not for nothing that he receives a salary. Our job is to write code. And in general, let him say thank you that we wrote the Dockefile for him.

10 minutes later and two videos about cats.

B: I did everything. Added more comments.
P: Show me!

Latest Dockerfile:

FROM ubuntu:latest

# Копируем исходный код
COPY ./ /app
WORKDIR /app

# Обновляем список пакетов
RUN apt-get update 

# Обновляем пакеты
RUN apt-get upgrade

# Устанавливаем нужные пакеты
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor

# Устанавливаем bundler
RUN gem install bundler

# Устанавливаем nodejs используется для сборки статики
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs

# Устанавливаем зависимости
RUN bundle install --without development test --path vendor/bundle

# Чистим за собой кэши
RUN rm -rf /usr/local/bundle/cache/*.gem 
RUN apt-get clean 
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 

# Запускаем скрипт, при старте контейнера, который запустит все остальное.
CMD [“/app/init.sh”]

P: Great, I like it. And comments in Russian, convenient and readable, everyone would work like that. I taught you everything, then you can do it yourself. Let's go get some coffee...

Well, here we have got an ideally terrible Dockerfile, the sight of which Igor Ivanovich will want to quit and his eyes will hurt for another week. Dockerfile, of course, could be even worse, there is no limit to perfection. But for starters, it will do.

I would like to finish with a quote from Grigory Oster:

If you are not firmly
Chose a path in life
And you don't know why
Start your labor path
Beat the light bulbs in the entrances -
People will say thank you.
you help the people
Save electricity.

Source: habr.com

Add a comment