Using Yarn 2 (Berry) for packaging application in a Docker image
Asked Answered
G

2

7

I'm migrating a VueJS application from "classic" Yarn 1.x to Yarn 2. Following the install documentation is straightforward and works without problems.

The tricky part comes when packaging the application in a Docker image.

Current Dockerfile

FROM node:14-alpine AS build-stage

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install

COPY . ./

RUN yarn build --modern \
    && find dist -type f -exec gzip -k "{}" \;

FROM nginx:mainline-alpine as production-stage

RUN apk add --no-cache curl

HEALTHCHECK CMD curl -f http://localhost || exit 1

COPY docker/entrypoint.sh /
RUN chmod +x /entrypoint.sh

COPY docker/app.nginx /etc/nginx/conf.d/default.conf
COPY --from=build-stage /app/dist /usr/share/nginx/html

ENTRYPOINT [ "/entrypoint.sh" ]

Maybe I looked in the wrong places but I couldn't find any information how a Yarn 2 Zero-Install setup would look like for a Docker image.

Do you have any recommendation on how to use the Yarn 2 approach in a Dockerfile?

Guffaw answered 27/8, 2021 at 10:29 Comment(0)
M
12

@Ethan's answer makes sense, and it should work. But for me I was getting this strange error during a build:

 > [ 7/10] RUN yarn --version:                                                                                                               
#11 1.430 internal/modules/cjs/loader.js:905                                                                                                 
#11 1.430   throw err;                                                                                                                       
#11 1.430   ^                                                                                                                                
#11 1.430                                                                                                                                    
#11 1.430 Error: Cannot find module '/base/.yarn/releases/yarn-3.1.1.cjs'
#11 1.430     at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)
#11 1.430     at Function.Module._load (internal/modules/cjs/loader.js:746:27)
#11 1.430     at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
#11 1.430     at internal/main/run_main_module.js:17:47 {
#11 1.430   code: 'MODULE_NOT_FOUND',
#11 1.430   requireStack: []
#11 1.430 }

Even though I definitely copied .yarn to the image, how well.

I had to actually install yarn v2 within the build:

FROM node:14.17.1 as build

WORKDIR /base
COPY package.json .
RUN yarn set version berry

RUN yarn install --frozen-lockfile

UPDATE

Turns out Docker doesn't copy entire directories the way I thought it did.

I had to add an explict COPY for the .yarn:

COPY .yarn ./.yarn

Solved it for me.

Margartmargate answered 5/2, 2022 at 18:11 Comment(1)
thanks for the COPY .yarn ./.yarn hint, that was what i was looking for.Disappointment
L
1

Due to a weird catch-22 with yarn 2's package install process, I've found this to be the most effective method of installing yarn@berry with docker. There's likely a better method of doing it, but I'm not aware of one.

FROM node:latest as build
WORKDIR /app

# copy only the package.json file so yarn set version can
# correctly download its modules for berry without overwriting
# the existing yarnrc and cache files. If the rc is added now,
# yarn will attempt to use the berry module without it being
# installed.
COPY package.json .
RUN yarn set version berry

# and _now_ pull in the rest of the build files overriding
# the rc generated by setting the yarn version
COPY yarn.lock .yarn .yarnrc.yml ./
RUN yarn install
COPY . .

# continue with your build process

However, I will note that yarn is intended to run from the local .yarn/releases folder, so the best method may simply be to install yarn2 in local and add it to the repo as yarn recommends. Then as a preliminary step with pulling in the package.json file, pull the necessary .yarn files with it as shown above. This should work under most circumstances, however it gave me difficulty sometimes, hence the above example.

FROM node:latest as build
WORKDIR /app

# Copy in the package file as well as other yarn
# dependencies in the local directory, assuming the
# yarn berry release module is inside .yarn/releases
# already
COPY package.json yarn.lock .yarn .yarnrc.yml ./

RUN yarn install
COPY . .

# continue with your build process
Lohrman answered 2/9, 2021 at 13:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.