Florian Ludewig
Florian Ludewig

Reputation: 6002

Build Node.Js Docker Image with Bazel

Motive

I am new to Bazel and cannot find sufficient resources about building Docker images for Node.Js.

So I have a Node.js application written in Typescript depending on two other Typescript packages. My goal is to build a Docker image, which can be deploy to Kubernetes afterwards.

I already have a working Dockerfile:

FROM node:10-alpine
WORKDIR /usr/app/src
COPY package.json .
COPY yarn.lock .
COPY ./packages ./packages
COPY ./services/gateway ./services/gateway
RUN yarn install
COPY ./tsconfig.settings.json ./
COPY ./tsconfig.json ./
WORKDIR /usr/app/src/services/gateway
CMD yarn start

But I'm struggling to replicate it via Bazel.


My Current Setup

WORKSPACE.bazel file in the root of the project:

workspace(name = "learning_bazel_monorepo")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

###############################
# NOEJS                       #
###############################
http_archive(
    name = "build_bazel_rules_nodejs",
    sha256 = "16fc00ab0d1e538e88f084272316c0693a2e9007d64f45529b82f6230aedb073",
    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.42.2/rules_nodejs-0.42.2.tar.gz"],
)

# Setup the NodeJS toolchain
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories", "yarn_install")
node_repositories()

# Setup Bazel managed npm dependencies with the `yarn_install` rule.
# The name of this rule should be set to `npm` so that `ts_library` and `ts_web_test_suite`
# can find your npm dependencies by default in the `@npm` workspace. You may
# also use the `npm_install` rule with a `package-lock.json` file if you prefer.
# See https://github.com/bazelbuild/rules_nodejs#dependencies for more info.
yarn_install(
  name = "npm",
  package_json = "//:package.json",
  yarn_lock = "//:yarn.lock",
)

###############################
# TYPESCRIPT                  #
###############################
http_archive(
    name = "build_bazel_rules_typescript",
    url = "https://github.com/bazelbuild/rules_typescript/archive/0.20.3.zip",
    strip_prefix = "rules_typescript-0.20.3",
)

load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()

# Set up TypeScript toolchain
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()

###############################
# DOCKER                      #
###############################
http_archive(
    name = "io_bazel_rules_docker",
    sha256 = "14ac30773fdb393ddec90e158c9ec7ebb3f8a4fd533ec2abbfd8789ad81a284b",
    strip_prefix = "rules_docker-0.12.1",
    urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.12.1/rules_docker-v0.12.1.tar.gz"],
)

load("@io_bazel_rules_docker//repositories:repositories.bzl", container_repositories = "repositories")
container_repositories()

load("@io_bazel_rules_docker//nodejs:image.bzl", _nodejs_image_repos = "repositories")
_nodejs_image_repos()

BUILD.bazel in the directory of the Node.Js application:

package(default_visibility=["//visibility:public"])

load("@npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
    name = "gateway",
    srcs = [":src/index.ts"],
    module_name = "@learning-bazel-monorepo/gateway",
    deps = [
        "@npm//express"
    ],
)

load("@io_bazel_rules_docker//nodejs:image.bzl", "nodejs_image")
nodejs_image(
    name = "gateway_image",
    entry_point = "services/gateway/dist/index.js",
    node_modules = "@npm//:node_modules",
    data = [":gateway"],
)

I get an error when running bazel build //...:

ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/BUILD.bazel' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:BUILD.bazel'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dev.Dockerfile' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dev.Dockerfile'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dist/index.d.ts' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dist/index.d.ts'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dist/index.d.ts.map' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dist/index.d.ts.map'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dist/index.js' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dist/index.js'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dist/server.d.ts' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dist/server.d.ts'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dist/server.d.ts.map' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dist/server.d.ts.map'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/dist/server.js' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:dist/server.js'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/node_modules/.bin/nodemon' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:node_modules/.bin/nodemon'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/node_modules/.bin/ts-node' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:node_modules/.bin/ts-node'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/node_modules/.bin/tsc' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:node_modules/.bin/tsc'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/node_modules/.bin/tsserver' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:node_modules/.bin/tsserver'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/package.json' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:package.json'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/prod.Dockerfile' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:prod.Dockerfile'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/src/index.ts' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:src/index.ts'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/src/server.ts' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:src/server.ts'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/tsconfig.json' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:tsconfig.json'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/tsconfig.tsbuildinfo' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:tsconfig.tsbuildinfo'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/BUILD.bazel:9:1: Label '@npm//:node_modules/@learning-bazel-monorepo/gateway/yarn-error.log' is invalid because '@npm//node_modules/@learning-bazel-monorepo/gateway' is a subpackage; perhaps you meant to put the colon here: '@npm//node_modules/@learning-bazel-monorepo/gateway:yarn-error.log'?
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/History.md' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/LICENSE' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/Readme.md' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/index.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/application.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/express.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/middleware/init.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/middleware/query.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/request.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/response.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/router/index.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/router/layer.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/router/route.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/utils.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/lib/view.js' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/.cache/bazel/_bazel_flo/0eadfacb2a20f703f8711dd83de17c79/external/npm/express/BUILD.bazel:167:1: Target '@npm//:node_modules/express/package.json' contains an error and its package is in error and referenced by '@npm//express:express__files'
ERROR: /home/flo/Desktop/learning-bazel-monorepo/services/gateway/BUILD.bazel:14:1: Target '@npm//:node_modules' contains an error and its package is in error and referenced by '//services/gateway:gateway_image.binary'
ERROR: Analysis of target '//services/gateway:gateway' failed; build aborted: Analysis failed
INFO: Elapsed time: 0.105s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (1 packages loaded, 0 targets configured)
    Fetching @nodejs_image_base; Restarting.

If you want/need to look at the file structure you can do this here: https://github.com/flolude/learning-bazel-monorepo.

Upvotes: 3

Views: 2925

Answers (2)

mancini0
mancini0

Reputation: 4723

You can't determine the target because both of your rules are named 'gateway'. Change the name of the nodejs_image rule to 'foo', then try bazel build //...

Try using this import in the build file:

load("@npm_bazel_typescript//:index.bzl", "ts_library")

, taken from the rules_nodejs example repo:

https://github.com/bazelbuild/rules_nodejs/blob/master/examples/app/BUILD.bazel

Also, make sure your package.json has the following dev dependencies.

  "devDependencies": {
    "@bazel/bazel": "latest",
    "@bazel/ibazel": "latest",
    "@bazel/buildifier": "latest",
    "@bazel/typescript": "latest",
    "typescript": "~3.4.0"
  },

Also, in your WORKSPACE file, try copying the example's WORKSPACE file:

http_archive(
    name = "build_bazel_rules_nodejs",
    sha256 = "16fc00ab0d1e538e88f084272316c0693a2e9007d64f45529b82f6230aedb073",
    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.42.2/rules_nodejs-0.42.2.tar.gz"],
)

load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install")

yarn_install(
    name = "npm",
    package_json = "//:package.json",
    yarn_lock = "//:yarn.lock",
)

load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")

install_bazel_dependencies()

load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")

ts_setup_workspace()

https://github.com/bazelbuild/rules_nodejs/blob/master/examples/app/WORKSPACE

UPDATE:

See my minimal repo that builds a ts_library and nodejs_image: https://github.com/mancini0/minimal_bazel_docker_nodejs

Note your workspace file's yarn_install rule should point to your package.json, yarn.lock, etc... either ":package.json" if they live at the root of your project, or "//mysubproject:package.json" / "//mysubproject:yarn.lock" if they live in mysubproject.

Upvotes: 3

seasick
seasick

Reputation: 446

I think one problems is, that you are calling yarn_install, while the bazel is looking for npm_install. And that is the reason it cannot find

So you either have to use npm_install instead, or you load the yarn_install rules by changing load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories", "npm_install") to load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories", "yarn_install") in WORKSPACE.bazel

Another problem might be that http_archive is loaded twice.

Upvotes: 1

Related Questions