kamidude
kamidude

Reputation: 1321

node monorepo with yarn workspaces and docker without dockerfiles

I'm trying to find a proper setup to create docker images for individual services in a yarn workspaces monorepo such as this one :

packages/
├─ svc1/
│  ├─ package.json
├─ svc2/
│  ├─ package.json
├─ .../
package.json
yarn.lock

There is an issue when trying to use a Dockerfile inside each service package: the lockfile is located at repo root and the packages may reference some other packages in the repo using workspace: protocol. That would make the install step fail.

Therefore I wanted to create a "build" image that preserves the monorepo layout

The I would be able to fetch a given package dependencies from this build image and copy appropriate build artifacts to run my services/apps.

Dockerfile is not an option here because because of the directory layout:

I investigated creating a script at repo root that would

I could not manage to create a proper script to do that, I can't docker cp files in a container I just created using docker create but my docker skills may be low.

Would you know how to create/commit this image using a shell script ?

Thank you

Upvotes: 1

Views: 1371

Answers (1)

kamidude
kamidude

Reputation: 1321

After many trial and errors I managed to do this :

#!/usr/bin/env sh

set -eo pipefail

echo "pulling node:alpine..."
# find . -name node_modules -prune -false -o -name package.json

workdir="/opt/myrepo"

mountpath="$(pwd)/.yarn/cache"
container=$(docker create --tty --workdir "${workdir}" --mount type=bind,source=${mountpath},target=${workdir}/.yarn/cache,readonly node:alpine sh)
echo "container id=\"${container}\""
echo "docker start \"${container}\""
docker start "${container}"

find . -name node_modules -prune -false -o -name package.json | while IFS= read file; do
  path=$(dirname "${file}")
  echo "docker exec \"${container}\" mkdir -p \"${path}\""
  docker exec "${container}" mkdir -p "${path}"
  echo "docker cp \"${file}\" \"${container}:${file}\""
  docker cp "${file}" "${container}:${workdir}/${file}"
done
docker cp .yarnrc.yml "${container}":${workdir}/
docker cp yarn.lock "${container}":${workdir}/
docker cp .yarn/plugins "${container}":${workdir}/.yarn/
docker cp .yarn/releases "${container}":${workdir}/.yarn/
docker exec --workdir "${workdir}" "${container}" yarn workspaces focus --all --production
docker commit "${container}" "myrepo:latest"
docker stop "${container}"

echo "done"

This seem quirky but that worked. Is there a more elegant solution ?

Upvotes: 1

Related Questions