Wątek przeniesiony 2021-09-26 02:38 z Nietuzinkowe tematy przez somekind.

Czy moja optymalizacja pliku Dockerfile ma sens?

1

Na wstępie chciałbym zaznaczyć, że mam bardzo podstawową wiedzę z Dockera. Mam taki plik Dockerfile, którego nie jestem autorem, zatem nie wiem w 100% jaki zamysł miał autor:

FROM node:16-alpine as builder
ENV NODE_ENV build
USER node
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build-ts

FROM node:16-alpine
ENV NODE_ENV production
USER node
WORKDIR /app
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/dist/ ./dist
RUN npm ci

EXPOSE 3000

CMD ["node", "dist/app.js"]

W kontenerze builder najpierw kopiujemy package.json, potem instalujemy paczki a dopiero potem kopiujemy kod. Z tego, co wiem to pozwoli to Dockerowi utworzyć cache i zmiany w kodzie źródłowym nie będą wymuszać instalowania paczek od początku za każdym razem. W tym kroki instalowane są wszystkie paczki, również te "devDependencies". W docelowym kontenerze kopiujemy package.json, wynik kompilacji/transpilacji TS->JS (katalog dist) oraz musimy zainstalować paczki jeszcze raz. Za drugim razem zostaną zainstalowane tylko paczki produkcyjne (dzięki ustawieniu NODE_ENV na production).

Chciałem sprawdzić z ciekawości, czy taka optymalizacja pozwoli skrócić czas budowania obrazu:

FROM node:16-alpine as builder
ENV NODE_ENV build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build-ts
RUN npm prune --production # tutaj zmiana

FROM node:16-alpine
ENV NODE_ENV production
USER node
WORKDIR /app
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules/ ./node_modules # tutaj zmiana
COPY --from=builder /app/dist/ ./dist

EXPOSE 3000

CMD ["node", "dist/app.js"]

Główna zmiana polega na tym, że w kontenerze builder robię npm prune --production, a potem w tym drugim docelowym kontenerze kopiuję zawartość katalogu node_modules zamiast instalować paczki jeszcze raz (npm ci). Również i w tym przypadku w docelowym kontenerze będą tylko paczki produkcyjne bez "devDependencies", ponieważ te zostały usunięte poprzez npm prune po zbudowaniu aplikacji. Niestety musiałem usunąć linię USER node w builder, bo inaczej npm prune nie chciało się wykonać.

Przy okazji zapytam, dlaczego korzysta się tutaj z USER node?

Wynik tego zabiegu to zmniejszenie rozmiaru końcowego obrazu ze 181 MB do 168 MB oraz skrócenie czasu budowania z 39s do 34s. Wiem, że to niewiele, ale chodzi tutaj, żeby sobie poeksperymentować ;) W bardzo dużych projektach ta różnica może będzie bardziej widoczna.

Przyjmijmy, że mamy ogromny projekt, który ma bardzo dużo paczek. Pytanie jest, czy to, co zrobiłem ma jakiś sens?

0

Plików docerfile sie nie optymalizuje, dodajesz to co potrzebujesz

4

Właściwie sam sobie odpowiedziałeś na to pytanie. 8% mniejszy rozmiar obrazu i 13% krótszy czas budowania. Do tego jeszcze jakieś odciążenie ruchu sieciowego. W perspektywie jednego projektu i jednej osoby pewnie mało to imponujące, ale jeśli będziesz pracować w dużej firmie, aplikacja będzie działać na tysiącach serwerów to zrobi to różnicę. Podobnie jeśli będziesz tak robić we wszystkich twoich projektach. Biorąc pod uwagę całkiem ładne procenty i praktycznie zerowy wysiłek, warto.

Edit. co do tego usera, sprawia, że aplikacja nie chodzi na roocie. Pewnie dodaje trochę bezpieczeństwa, ale w obrębie tylko tej jednej aplikacji. Na ile konkretnie jest to ważne, trudno mi określić.

1 użytkowników online, w tym zalogowanych: 0, gości: 1