Giter VIP home page Giter VIP logo

rules_docker's Introduction

Bazel Container Image Rules

Bazel CI
Build status

Status

๐Ÿšจ rules_docker is no longer maintained and deprecated. Please see rules_oci for a better designed and maintained alternative.

Basic Rules

These rules used to be docker_build, docker_push, etc. and the aliases for these (mostly) legacy names still exist largely for backwards-compatibility. We also have early-stage oci_image, oci_push, etc. aliases for folks that enjoy the consistency of a consistent rule prefix. The only place the format-specific names currently do any more than alias things is in foo_push, where they also specify the appropriate format as which to publish the image.

Overview

This repository contains a set of rules for pulling down base images, augmenting them with build artifacts and assets, and publishing those images. These rules do not require / use Docker for pulling, building, or pushing images. This means:

  • They can be used to develop Docker containers on OSX without boot2docker or docker-machine installed. Note use of these rules on Windows is currently not supported.
  • They do not require root access on your workstation.

Also, unlike traditional container builds (e.g. Dockerfile), the Docker images produced by container_image are deterministic / reproducible.

To get started with building Docker images, check out the examples that build the same images using both rules_docker and a Dockerfile.

NOTE: container_push and container_pull make use of google/go-containerregistry for registry interactions.

Language Rules

It is notable that: cc_image, go_image, rust_image, and d_image also allow you to specify an external binary target.

Docker Rules

This repo now includes rules that provide additional functionality to install packages and run commands inside docker containers. These rules, however, require a docker binary is present and properly configured. These rules include:

Overview

In addition to low-level rules for building containers, this repository provides a set of higher-level rules for containerizing applications. The idea behind these rules is to make containerizing an application built via a lang_binary rule as simple as changing it to lang_image.

By default these higher level rules make use of the distroless language runtimes, but these can be overridden via the base="..." attribute (e.g. with a container_pull or container_image target).

Note also that these rules do not expose any docker related attributes. If you need to add a custom env or symlink to a lang_image, you must use container_image targets for this purpose. Specifically, you can use as base for your lang_image target a container_image target that adds e.g., custom env or symlink. Please see go_image (custom base) for an example.

Setup

Add the following to your WORKSPACE file to add the external repositories:

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

http_archive(
  # Get copy paste instructions for the http_archive attributes from the
  # release notes at https://github.com/bazelbuild/rules_docker/releases
)

# OPTIONAL: Call this to override the default docker toolchain configuration.
# This call should be placed BEFORE the call to "container_repositories" below
# to actually override the default toolchain configuration.
# Note this is only required if you actually want to call
# docker_toolchain_configure with a custom attr; please read the toolchains
# docs in /toolchains/docker/ before blindly adding this to your WORKSPACE.
# BEGIN OPTIONAL segment:
load("@io_bazel_rules_docker//toolchains/docker:toolchain.bzl",
    docker_toolchain_configure="toolchain_configure"
)
docker_toolchain_configure(
  name = "docker_config",
  # OPTIONAL: Bazel target for the build_tar tool, must be compatible with build_tar.py
  build_tar_target="<enter absolute path (i.e., must start with repo name @...//:...) to an executable build_tar target>",
  # OPTIONAL: Path to a directory which has a custom docker client config.json.
  # See https://docs.docker.com/engine/reference/commandline/cli/#configuration-files
  # for more details.
  client_config="<enter Bazel label to your docker config.json here>",
  # OPTIONAL: Path to the docker binary.
  # Should be set explicitly for remote execution.
  docker_path="<enter absolute path to the docker binary (in the remote exec env) here>",
  # OPTIONAL: Path to the gzip binary.
  gzip_path="<enter absolute path to the gzip binary (in the remote exec env) here>",
  # OPTIONAL: Bazel target for the gzip tool.
  gzip_target="<enter absolute path (i.e., must start with repo name @...//:...) to an executable gzip target>",
  # OPTIONAL: Path to the xz binary.
  # Should be set explicitly for remote execution.
  xz_path="<enter absolute path to the xz binary (in the remote exec env) here>",
  # OPTIONAL: Bazel target for the xz tool.
  # Either xz_path or xz_target should be set explicitly for remote execution.
  xz_target="<enter absolute path (i.e., must start with repo name @...//:...) to an executable xz target>",
  # OPTIONAL: List of additional flags to pass to the docker command.
  docker_flags = [
    "--tls",
    "--log-level=info",
  ],

)
# End of OPTIONAL segment.

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

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

container_deps()

load(
    "@io_bazel_rules_docker//container:container.bzl",
    "container_pull",
)

container_pull(
  name = "java_base",
  registry = "gcr.io",
  repository = "distroless/java",
  # 'tag' is also supported, but digest is encouraged for reproducibility.
  digest = "sha256:deadbeef",
)

Known Issues

  • Bazel does not deal well with diamond dependencies.

If the repositories that are imported by container_repositories() have already been imported (at a different version) by other rules you called in your WORKSPACE, which are placed above the call to container_repositories(), arbitrary errors might occur. If you get errors related to external repositories, you will likely not be able to use container_repositories() and will have to import directly in your WORKSPACE all the required dependencies (see the most up to date impl of container_repositories() for details).

  • ImportError: No module named moves.urllib.parse

This is an example of an error due to a diamond dependency. If you get this error, make sure to import rules_docker before other libraries, so that six can be patched properly.

See #1022 for more details.

  • Ensure your project has a BUILD or BUILD.bazel file at the top level. This can be a blank file if necessary. Otherwise you might see an error that looks like:
Unable to load package for //:WORKSPACE: BUILD file not found in any of the following directories.
  • rules_docker uses transitions to build your containers using toolchains the correct architecture and operating system. If you run into issues with toolchain resolutions, you can disable this behaviour, by adding this to your .bazelrc:
build --@io_bazel_rules_docker//transitions:enable=false

Using with Docker locally.

Suppose you have a container_image target //my/image:helloworld:

container_image(
    name = "helloworld",
    ...
)

You can load this into your local Docker client by running: bazel run my/image:helloworld.

For the lang_image targets, this will also run the container using docker run to maximize compatibility with lang_binary rules.

Arguments to this command are forwarded to docker, meaning the command

bazel run my/image:helloworld -- -p 8080:80 -- arg0

performs the following steps:

  • load the my/image:helloworld target into your local Docker client
  • start a container using this image where arg0 is passed to the image entrypoint
  • port forward 8080 on the host to port 80 on the container, as per docker run documentation

You can suppress this behavior by passing the single flag: bazel run :foo -- --norun

Alternatively, you can build a docker load compatible bundle with: bazel build my/image:helloworld.tar. This will produce a tar file in your bazel-out directory that can be loaded into your local Docker client. Building this target can be expensive for large images. You will first need to query the ouput file location.

TARBALL_LOCATION=$(bazel cquery my/image:helloworld.tar \
    --output starlark \
    --starlark:expr="target.files.to_list()[0].path")
docker load -i $TARBALL_LOCATION

These work with both container_image, container_bundle, and the lang_image rules. For everything except container_bundle, the image name will be bazel/my/image:helloworld. The container_bundle rule will apply the tags you have specified.

Authentication

You can use these rules to access private images using standard Docker authentication methods. e.g. to utilize the Google Container Registry. See here for authentication methods.

See also:

Once you've setup your docker client configuration, see here for an example of how to use container_pull with custom docker authentication credentials and here for an example of how to use container_push with custom docker authentication credentials.

Varying image names

A common request from folks using container_push, container_bundle, or container_image is to be able to vary the tag that is pushed or embedded. There are two options at present for doing this.

Stamping

The first option is to use stamping. Stamping is enabled when bazel is run with --stamp. This enables replacements in stamp-aware attributes. A python format placeholder (e.g. {BUILD_USER}) is replaced by the value of the corresponding workspace-status variable.

# A common pattern when users want to avoid trampling
# on each other's images during development.
container_push(
  name = "publish",
  format = "Docker",

  # Any of these components may have variables.
  registry = "gcr.io",
  repository = "my-project/my-image",
  # This will be replaced with the current user when built with --stamp
  tag = "{BUILD_USER}",
)

Rules that are sensitive to stamping can also be forced to stamp or non-stamp mode irrespective of the --stamp flag to Bazel. Use the build_context_data rule to make a target that provides StampSettingInfo, and pass this to the build_context_data attribute.

The next natural question is: "Well what variables can I use?" This option consumes the workspace-status variables Bazel defines in bazel-out/stable-status.txt and bazel-out/volatile-status.txt.

Note that changes to the stable-status file cause a rebuild of the action, while volatile-status does not.

You can add more stamp variables via --workspace_status_command, see the bazel docs. A common example is to provide the current git SHA, with --workspace_status_command="echo STABLE_GIT_SHA $(git rev-parse HEAD)"

That flag is typically passed in the .bazelrc file, see for example .bazelrc in kubernetes.

Make variables

The second option is to employ Makefile-style variables:

container_bundle(
  name = "bundle",

  images = {
    "gcr.io/$(project)/frontend:latest": "//frontend:image",
    "gcr.io/$(project)/backend:latest": "//backend:image",
  }
)

These variables are specified on the CLI using:

   bazel build --define project=blah //path/to:bundle

Debugging lang_image rules

By default the lang_image rules use the distroless base runtime images, which are optimized to be the minimal set of things your application needs at runtime. That can make debugging these containers difficult because they lack even a basic shell for exploring the filesystem.

To address this, we publish variants of the distroless runtime images tagged :debug, which are the exact-same images, but with additions such as busybox to make debugging easier.

For example (in this repo):

$ bazel run -c dbg testdata:go_image
...
INFO: Build completed successfully, 5 total actions

INFO: Running command line: bazel-bin/testdata/go_image
Loaded image ID: sha256:9c5c2167a1db080a64b5b401b43b3c5cdabb265b26cf7a60aabe04a20da79e24
Tagging 9c5c2167a1db080a64b5b401b43b3c5cdabb265b26cf7a60aabe04a20da79e24 as bazel/testdata:go_image
Hello, world!

$ docker run -ti --rm --entrypoint=sh bazel/testdata:go_image -c "echo Hello, busybox."
Hello, busybox.

Examples

container_image

container_image(
    name = "app",
    # References container_pull from WORKSPACE (above)
    base = "@java_base//image",
    files = ["//java/com/example/app:Hello_deploy.jar"],
    cmd = ["Hello_deploy.jar"]
)

Hint: if you want to put files in specific directories inside the image use pkg_tar rule to create the desired directory structure and pass that to container_image via tars attribute. Note you might need to set strip_prefix = "." or strip_prefix = "{some directory}" in your rule for the files to not be flattened. See Bazel upstream issue 2176 and rules_docker issue 317 for more details.

cc_image

To use cc_image, add the following to WORKSPACE:

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

container_repositories()

load(
    "@io_bazel_rules_docker//cc:image.bzl",
    _cc_image_repos = "repositories",
)

_cc_image_repos()

Then in your BUILD file, simply rewrite cc_binary to cc_image with the following import:

load("@io_bazel_rules_docker//cc:image.bzl", "cc_image")

cc_image(
    name = "cc_image",
    srcs = ["cc_image.cc"],
    deps = [":cc_image_library"],
)

cc_image (external binary)

To use cc_image (or go_image, d_image, rust_image) with an external cc_binary (or the like) target, then your BUILD file should instead look like:

load("@io_bazel_rules_docker//cc:image.bzl", "cc_image")

cc_binary(
    name = "cc_binary",
    srcs = ["cc_binary.cc"],
    deps = [":cc_library"],
)

cc_image(
    name = "cc_image",
    binary = ":cc_binary",
)

If you need to modify somehow the container produced by cc_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example below.

py_image

To use py_image, add the following to WORKSPACE:

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

container_repositories()

load(
    "@io_bazel_rules_docker//python:image.bzl",
    _py_image_repos = "repositories",
)

_py_image_repos()

Then in your BUILD file, simply rewrite py_binary to py_image with the following import:

load("@io_bazel_rules_docker//python:image.bzl", "py_image")

py_image(
    name = "py_image",
    srcs = ["py_image.py"],
    deps = [":py_image_library"],
    main = "py_image.py",
)

If you need to modify somehow the container produced by py_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example below.

If you are using py_image with a custom base that has python tools installed in a location different to the default base, please see Python tools.

py_image (fine layering)

For Python and Java's lang_image rules, you can factor dependencies that don't change into their own layers by overriding the layers=[] attribute. Consider this sample from the rules_k8s repository:

py_image(
    name = "server",
    srcs = ["server.py"],
    # "layers" is just like "deps", but it also moves the dependencies each into
    # their own layer, which can dramatically improve developer cycle time. For
    # example here, the grpcio layer is ~40MB, but the rest of the app is only
    # ~400KB.  By partitioning things this way, the large grpcio layer remains
    # unchanging and we can reduce the amount of image data we repush by ~99%!
    layers = [
        requirement("grpcio"),
        "//examples/hellogrpc/proto:py",
    ],
    main = "server.py",
)

You can also implement more complex fine layering strategies by using the py_layer or java_layer rules and their filter attribute. For example:

# Suppose that we are synthesizing an image that depends on a complex set
# of libraries that we want to break into layers.
LIBS = [
    "//pkg/complex_library",
    # ...
]
# First, we extract all transitive dependencies of LIBS that are under //pkg/common.
py_layer(
    name = "common_deps",
    deps = LIBS,
    filter = "//pkg/common",
)
# Then, we further extract all external dependencies of the deps under //pkg/common.
py_layer(
    name = "common_external_deps",
    deps = [":common_deps"],
    filter = "@",
)
# We also extract all external dependencies of LIBS, which is a superset of
# ":common_external_deps".
py_layer(
    name = "external_deps",
    deps = LIBS,
    filter = "@",
)
# Finally, we create the image, stacking the above filtered layers on top of one
# another in the "layers" attribute.  The layers are applied in order, and any
# dependencies already added to the image will not be added again.  Therefore,
# ":external_deps" will only add the external dependencies not present in
# ":common_external_deps".
py_image(
    name = "image",
    deps = LIBS,
    layers = [
        ":common_external_deps",
        ":common_deps",
        ":external_deps",
    ],
    # ...
)

py3_image

To use a Python 3 runtime instead of the default of Python 2, use py3_image, instead of py_image. The other semantics are identical.

If you need to modify somehow the container produced by py3_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example below.

If you are using py3_image with a custom base that has python tools installed in a location different to the default base, please see Python tools.

nodejs_image

It is notable that unlike the other image rules, nodejs_image is not currently using the gcr.io/distroless/nodejs image for a handful of reasons. This is a switch we plan to make, when we can manage it. We are currently utilizing the gcr.io/google-appengine/debian9 image as our base.

To use nodejs_image, add the following to WORKSPACE:

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

http_archive(
    name = "build_bazel_rules_nodejs",
    # Replace with a real SHA256 checksum
    sha256 = "{SHA256}"
    # Replace with a real release version
    urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/{VERSION}/rules_nodejs-{VERSION}.tar.gz"],
)


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

# Install your declared Node.js dependencies
npm_install(
    name = "npm",
    package_json = "//:package.json",
    yarn_lock = "//:yarn.lock",
)

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()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite nodejs_binary to nodejs_image with the following import:

load("@io_bazel_rules_docker//nodejs:image.bzl", "nodejs_image")

nodejs_image(
    name = "nodejs_image",
    entry_point = "@your_workspace//path/to:file.js",
    # npm deps will be put into their own layer
    data = [":file.js", "@npm//some-npm-dep"],
    ...
)

nodejs_image also supports the launcher and launcher_args attributes which are passed to container_image and used to prefix the image's entry_point.

If you need to modify somehow the container produced by nodejs_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example below.

go_image

To use go_image, add the following to WORKSPACE:

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

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

container_repositories()

load(
    "@io_bazel_rules_docker//go:image.bzl",
    _go_image_repos = "repositories",
)

_go_image_repos()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite go_binary to go_image with the following import:

load("@io_bazel_rules_docker//go:image.bzl", "go_image")

go_image(
    name = "go_image",
    srcs = ["main.go"],
    importpath = "github.com/your/path/here",
)

Notice that it is important to explicitly build this target with the --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 flag as the binary should be built for Linux since it will run in a Linux container.

If you need to modify somehow the container produced by go_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see example below.

go_image (custom base)

To use a custom base image, with any of the lang_image rules, you can override the default base="..." attribute. Consider this modified sample from the distroless repository:

load("@rules_pkg//pkg:tar.bzl", "pkg_tar")

# Create a passwd file with a root and nonroot user and uid.
passwd_entry(
    username = "root",
    uid = 0,
    gid = 0,
    name = "root_user",
)

passwd_entry(
    username = "nonroot",
    info = "nonroot",
    uid = 1002,
    name = "nonroot_user",
)

passwd_file(
    name = "passwd",
    entries = [
        ":root_user",
        ":nonroot_user",
    ],
)

# Create a tar file containing the created passwd file
pkg_tar(
    name = "passwd_tar",
    srcs = [":passwd"],
    mode = "0o644",
    package_dir = "etc",
)

# Include it in our base image as a tar.
container_image(
    name = "passwd_image",
    base = "@go_image_base//image",
    tars = [":passwd_tar"],
    user = "nonroot",
)

# Simple go program to print out the username and uid.
go_image(
    name = "user",
    srcs = ["user.go"],
    # Override the base image.
    base = ":passwd_image",
)

java_image

To use java_image, add the following to WORKSPACE:

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

container_repositories()

load(
    "@io_bazel_rules_docker//java:image.bzl",
    _java_image_repos = "repositories",
)

_java_image_repos()

Then in your BUILD file, simply rewrite java_binary to java_image with the following import:

load("@io_bazel_rules_docker//java:image.bzl", "java_image")

java_image(
    name = "java_image",
    srcs = ["Binary.java"],
    # Put these runfiles into their own layer.
    layers = [":java_image_library"],
    main_class = "examples.images.Binary",
)

If you need to modify somehow the container produced by java_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example.

war_image

To use war_image, add the following to WORKSPACE:

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

container_repositories()

load(
    "@io_bazel_rules_docker//java:image.bzl",
    _java_image_repos = "repositories",
)

_java_image_repos()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite java_war to war_image with the following import:

load("@io_bazel_rules_docker//java:image.bzl", "war_image")

war_image(
    name = "war_image",
    srcs = ["Servlet.java"],
    # Put these JARs into their own layers.
    layers = [
        ":java_image_library",
        "@javax_servlet_api//jar:jar",
    ],
)

The produced image uses Jetty 9.x to serve the web application. Servlets included in the web application need to follow the API specification 3.0. For best compatibility, use a Servlet dependency provided by the Jetty project.

A Servlet implementation needs to declare the @WebServlet annotation to be auto-discovered. The use of a web.xml to declare the Servlet URL mapping is not supported.

If you need to modify somehow the container produced by war_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example.

scala_image

To use scala_image, add the following to WORKSPACE:

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

# You *must* import the Scala rules before setting up the scala_image rules.
http_archive(
    name = "io_bazel_rules_scala",
    # Replace with a real SHA256 checksum
    sha256 = "{SHA256}"
    # Replace with a real commit SHA
    strip_prefix = "rules_scala-{HEAD}",
    urls = ["https://github.com/bazelbuild/rules_scala/archive/{HEAD}.tar.gz"],
)

load("@io_bazel_rules_scala//scala:scala.bzl", "scala_repositories")

scala_repositories()

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

container_repositories()

load(
    "@io_bazel_rules_docker//scala:image.bzl",
    _scala_image_repos = "repositories",
)

_scala_image_repos()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite scala_binary to scala_image with the following import:

load("@io_bazel_rules_docker//scala:image.bzl", "scala_image")

scala_image(
    name = "scala_image",
    srcs = ["Binary.scala"],
    main_class = "examples.images.Binary",
)

If you need to modify somehow the container produced by scala_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example.

groovy_image

To use groovy_image, add the following to WORKSPACE:

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

# You *must* import the Groovy rules before setting up the groovy_image rules.
http_archive(
    name = "io_bazel_rules_groovy",
    # Replace with a real SHA256 checksum
    sha256 = "{SHA256}"
    # Replace with a real commit SHA
    strip_prefix = "rules_groovy-{HEAD}",
    urls = ["https://github.com/bazelbuild/rules_groovy/archive/{HEAD}.tar.gz"],
)

load("@io_bazel_rules_groovy//groovy:groovy.bzl", "groovy_repositories")

groovy_repositories()

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

container_repositories()

load(
    "@io_bazel_rules_docker//groovy:image.bzl",
    _groovy_image_repos = "repositories",
)

_groovy_image_repos()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite groovy_binary to groovy_image with the following import:

load("@io_bazel_rules_docker//groovy:image.bzl", "groovy_image")

groovy_image(
    name = "groovy_image",
    srcs = ["Binary.groovy"],
    main_class = "examples.images.Binary",
)

If you need to modify somehow the container produced by groovy_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example.

rust_image

To use rust_image, add the following to WORKSPACE:

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

# You *must* import the Rust rules before setting up the rust_image rules.
http_archive(
    name = "rules_rust",
    # Replace with a real SHA256 checksum
    sha256 = "{SHA256}"
    # Replace with a real commit SHA
    strip_prefix = "rules_rust-{HEAD}",
    urls = ["https://github.com/bazelbuild/rules_rust/archive/{HEAD}.tar.gz"],
)

load("@rules_rust//rust:repositories.bzl", "rust_repositories")

rust_repositories()

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

container_repositories()

load(
    "@io_bazel_rules_docker//rust:image.bzl",
    _rust_image_repos = "repositories",
)

_rust_image_repos()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite rust_binary to rust_image with the following import:

load("@io_bazel_rules_docker//rust:image.bzl", "rust_image")

rust_image(
    name = "rust_image",
    srcs = ["main.rs"],
)

If you need to modify somehow the container produced by rust_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example.

d_image

To use d_image, add the following to WORKSPACE:

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

# You *must* import the D rules before setting up the d_image rules.
http_archive(
    name = "io_bazel_rules_d",
    # Replace with a real SHA256 checksum
    sha256 = "{SHA256}"
    # Replace with a real commit SHA
    strip_prefix = "rules_d-{HEAD}",
    urls = ["https://github.com/bazelbuild/rules_d/archive/{HEAD}.tar.gz"],
)

load("@io_bazel_rules_d//d:d.bzl", "d_repositories")

d_repositories()

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

container_repositories()

load(
    "@io_bazel_rules_docker//d:image.bzl",
    _d_image_repos = "repositories",
)

_d_image_repos()

Note: See note about diamond dependencies in setup if you run into issues related to external repos after adding these lines to your WORKSPACE.

Then in your BUILD file, simply rewrite d_binary to d_image with the following import:

load("@io_bazel_rules_docker//d:image.bzl", "d_image")

d_image(
    name = "d_image",
    srcs = ["main.d"],
)

If you need to modify somehow the container produced by d_image (e.g., env, symlink), see note above in Language Rules Overview about how to do this and see go_image (custom base) example.

NOTE: all application image rules support the args string_list attribute. If specified, they will be appended directly after the container ENTRYPOINT binary name.

container_bundle

container_bundle(
    name = "bundle",
    images = {
        # A set of images to bundle up into a single tarball.
        "gcr.io/foo/bar:bazz": ":app",
        "gcr.io/foo/bar:blah": "//my:sidecar",
        "gcr.io/foo/bar:booo": "@your//random:image",
    }
)

container_pull

In WORKSPACE:

container_pull(
    name = "base",
    registry = "gcr.io",
    repository = "my-project/my-base",
    # 'tag' is also supported, but digest is encouraged for reproducibility.
    digest = "sha256:deadbeef",
)

This can then be referenced in BUILD files as @base//image.

To get the correct digest one can run docker manifest inspect gcr.io/my-project/my-base:tag once experimental docker cli features are enabled.

See here for an example of how to use container_pull with custom docker authentication credentials.

container_push

This target pushes on bazel run :push_foo:

container_push(
   name = "push_foo",
   image = ":foo",
   format = "Docker",
   registry = "gcr.io",
   repository = "my-project/my-image",
   tag = "dev",
)

We also support the docker_push (from docker/docker.bzl) and oci_push (from oci/oci.bzl) aliases, which bake in the format = "..." attribute.

See here for an example of how to use container_push with custom docker authentication credentials.

container_push (Custom client configuration)

If you wish to use container_push using custom docker authentication credentials, in WORKSPACE:

# Download the rules_docker repository
http_archive(
    name = "io_bazel_rules_docker",
    ...
)

# Load the macro that allows you to customize the docker toolchain configuration.
load("@io_bazel_rules_docker//toolchains/docker:toolchain.bzl",
    docker_toolchain_configure="toolchain_configure"
)

docker_toolchain_configure(
  name = "docker_config",
  # Replace this with a Bazel label to the config.json file. Note absolute or relative
  # paths are not supported. Docker allows you to specify custom authentication credentials
  # in the client configuration JSON file.
  # See https://docs.docker.com/engine/reference/commandline/cli/#configuration-files
  # for more details.
  client_config="@//path/to/docker:config.json",
)

In BUILD file:

load("@io_bazel_rules_docker//container:container.bzl", "container_push")

container_push(
   name = "push_foo",
   image = ":foo",
   format = "Docker",
   registry = "gcr.io",
   repository = "my-project/my-image",
   tag = "dev",
)

container_pull (DockerHub)

In WORKSPACE:

container_pull(
    name = "official_ubuntu",
    registry = "index.docker.io",
    repository = "library/ubuntu",
    tag = "14.04",
)

This can then be referenced in BUILD files as @official_ubuntu//image.

container_pull (Quay.io)

In WORKSPACE:

container_pull(
    name = "etcd",
    registry = "quay.io",
    repository = "coreos/etcd",
    tag = "latest",
)

This can then be referenced in BUILD files as @etcd//image.

container_pull (Bintray.io)

In WORKSPACE:

container_pull(
    name = "artifactory",
    registry = "docker.bintray.io",
    repository = "jfrog/artifactory-pro",
)

This can then be referenced in BUILD files as @artifactory//image.

container_pull (Gitlab)

In WORKSPACE:

container_pull(
    name = "gitlab",
    registry = "registry.gitlab.com",
    repository = "username/project/image",
    tag = "tag",
)

This can then be referenced in BUILD files as @gitlab//image.

container_pull (Custom client configuration)

If you specified a docker client directory using the client_config attribute to the docker toolchain configuration described here, you can use a container_pull that uses the authentication credentials from the specified docker client directory as follows:

In WORKSPACE:

load("@io_bazel_rules_docker//toolchains/docker:toolchain.bzl",
    docker_toolchain_configure="toolchain_configure"
)

# Configure the docker toolchain.
docker_toolchain_configure(
  name = "docker_config",
  # Bazel label to a custom docker client config.json with
  # authentication credentials for registry.gitlab.com (used in this example).
  client_config="@//path/to/docker/client:config.json",
)

# Load the custom version of container_pull created by the docker toolchain
# configuration.
load("@docker_config//:pull.bzl", authenticated_container_pull="container_pull")

authenticated_container_pull(
    name = "gitlab",
    registry = "registry.gitlab.com",
    repository = "username/project/image",
    tag = "tag",
)

This can then be referenced in BUILD files as @gitlab//image.

NOTE: This should only be used if a custom client_config was set. If you want to use the DOCKER_CONFIG env variable or the default home directory use the standard container_pull rule.

NOTE: This will only work on systems with Python >2.7.6

Python tools

Starting with Bazel 0.25.0 it's possible to configure python toolchains for rules_docker.

To use these features you need to enable the flags in the .bazelrc file at the root of this project.

Use of these features require a python toolchain to be registered. //py_images/image.bzl:deps and //py3_images/image.bzl:deps register a default python toolchain (//toolchains:container_py_toolchain) that defines the path to python tools inside the default container used for these rules.

Known issues

If you are using a custom base for py_image or py3_image builds that has python tools installed in a different location to those defined in //toolchains:container_py_toolchain, you will need to create a toolchain that points to these paths and register it before the call to py*_images/image.bzl:deps in your WORKSPACE.

Use of python toolchain features, currently, only supports picking one version of python for execution of host tools. rules_docker heavily depends on execution of python host tools that are only compatible with python 2. Flags in the recommended .bazelrc file force all host tools to use python 2. If your project requires using host tools that are only compatible with python 3 you will not be able to use these features at the moment. We expect this issue to be resolved before use of python toolchain features becomes the default.

Updating the distroless base images.

The digest references to the distroless base images must be updated over time to pick up bug fixes and security patches. To facilitate this, the files containing the digest references are generated by tools/update_deps.py. To update all of the dependencies, please run (from the root of the repository):

./update_deps.sh

Image references should not be updated individually because these images have shared layers and letting them diverge could result in sub-optimal push and pull performance.

container_pull

MOVED: See docs/container.md

container_push

MOVED: See docs/container.md

container_layer

MOVED: See docs/container.md

container_image

MOVED: See docs/container.md

container_bundle

MOVED: See docs/container.md

container_import

MOVED: See docs/container.md

container_load

MOVED: See docs/container.md

Adopters

Here's a (non-exhaustive) list of companies that use rules_docker in production. Don't see yours? You can add it in a PR!

rules_docker's People

Contributors

alex1545 avatar alexeagle avatar capstan avatar cgdolan avatar clintharrison avatar dannysullivan avatar dekkagaijin avatar drigz avatar erain avatar globegitter avatar gravypod avatar hwright avatar ixdy avatar jonjohnsonjr avatar kriscfoster avatar laurentlb avatar linzhp avatar mattmoor avatar nlopezgi avatar pawelz avatar pcj avatar renovate-bot avatar scele avatar sluongng avatar smukherj1 avatar tejal29 avatar uebelandre avatar xiaohegong avatar xingao267 avatar xwinxu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rules_docker's Issues

error getting credentials

Hi, total newbie error here I am sure, but when trying a simple build I get an credentials error:

ERROR: /Users/sebgoa/Desktop/foobar/wordpress/BUILD:3:1: no such package '@bitnami_minideb//image': Pull command failed: Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/__main__.py", line 103, in <module>
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/__main__.py", line 90, in main
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/containerregistry/client/v2_2/docker_image_.py", line 256, in __enter__
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/containerregistry/client/v2_2/docker_http_.py", line 182, in __init__
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/containerregistry/client/v2_2/docker_http_.py", line 244, in _Refresh
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/containerregistry/client/docker_creds_.py", line 65, in Get
  File "/private/var/tmp/_bazel_sebgoa/d4b7150d10cf6c79d4bea4b85c7dc9d0/external/puller/file/puller.par/containerregistry/client/docker_creds_.py", line 155, in suffix
Exception: Error fetching credential for osxkeychain, exit status: 1
credentials not found in native keychain

and here is the BUILD:

load("@io_bazel_rules_docker//docker:docker.bzl", "docker_build")

docker_build(
    name = "barfoo",
    # References docker_pull from WORKSPACE (above)
    base = "@bitnami_minideb//image:image.tar",
    files = [":foobar/foobar.py"],
    cmd = ["foobar.py"]
)

even though I can docker pull.

So how do I set the creds for the BUILD to work ?

thanks

Kubernetes rules

I am opening this issue to track discussions around what shape rules_k8s might take, and to enumerate the kinds of scenarios folks would like to see rules_k8s cover.

Top-level docker_build targets are broken again

In the switch to rules_docker I broke top-level docker_build targets because the name we use isn't an acceptable name to the containerregistry.client.docker_name module.

Here's the stack trace:

$ bazel build :image
INFO: Found 1 target...
ERROR: /home/mattmoor/java-docs-samples/flexible/helloworld/BUILD:16:1: null failed: Process exited with status 1 [sandboxed].
Traceback (most recent call last):
  File "/home/mattmoor/.cache/bazel/_bazel_mattmoor/d76411ba60a897ec070f41fe6c460c8f/bazel-sandbox/c3d33b99-a06b-4472-a6a8-c051f811fdf6-0/execroot/helloworld/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image.runfiles/helloworld/../io_bazel_rules_docker/docker/create_image.py", line 198, in <module>
    main()
  File "/home/mattmoor/.cache/bazel/_bazel_mattmoor/d76411ba60a897ec070f41fe6c460c8f/bazel-sandbox/c3d33b99-a06b-4472-a6a8-c051f811fdf6-0/execroot/helloworld/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image.runfiles/helloworld/../io_bazel_rules_docker/docker/create_image.py", line 195, in main
    args.base, args.metadata, args.name, args.repository)
  File "/home/mattmoor/.cache/bazel/_bazel_mattmoor/d76411ba60a897ec070f41fe6c460c8f/bazel-sandbox/c3d33b99-a06b-4472-a6a8-c051f811fdf6-0/execroot/helloworld/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image.runfiles/helloworld/../io_bazel_rules_docker/docker/create_image.py", line 128, in create_image
    repository=repository, tag=name))
  File "/home/mattmoor/.cache/bazel/_bazel_mattmoor/d76411ba60a897ec070f41fe6c460c8f/bazel-sandbox/c3d33b99-a06b-4472-a6a8-c051f811fdf6-0/execroot/helloworld/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image.runfiles/containerregistry/client/docker_name_.py", line 148, in __init__
    super(Tag, self).__init__(parts[0])
  File "/home/mattmoor/.cache/bazel/_bazel_mattmoor/d76411ba60a897ec070f41fe6c460c8f/bazel-sandbox/c3d33b99-a06b-4472-a6a8-c051f811fdf6-0/execroot/helloworld/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image.runfiles/containerregistry/client/docker_name_.py", line 114, in __init__
    raise self._validation_exception(name)
containerregistry.client.docker_name_.BadNameException: Docker image name must be fully qualified (e.g.registry/repository:tag) saw: bazel

Alpine: Can't RUN `apk add ca-certificates`

I'm trying to convert my Dockerfile to bazel. Here is the Dockerfile:

FROM alpine:3.5
RUN apk add --no-cache ca-certificates && update-ca-certificates
COPY my-binary /
ENTRYPOINT ["/my-binary"]

my-binary connects to some HTTPS websites.

Right now I have:

# in WORKSPACE
docker_pull(
   name = "alpine",
   registry = "index.docker.io",
   repository = "library/alpine",
   tag = "3.5",
)

# in BUILD
docker_build(
    name = "my-binary-docker",
    base = "@alpine//image:image.tar",
    files = [":my-binary"],
)

I'm not sure how to replace the RUN part of the file.

docker_repositories() fails if user's workspace already contains "subpar"

We use subpar for packaging Python. When trying to introduce Docker support using WORKSPACE file (following the example in README.md), I get the following:

	File "/home/dmitryb/.cache/bazel/_bazel_dmitryb/8e618220280fa417619d9462a0a41d8d/external/io_bazel_rules_docker/docker/docker.bzl", line 128, in docker_repositories
		native.git_repository(name = "subpar", remote = "https:/...", ...")
Cannot redefine repository after any load statement in the WORKSPACE file (for repository 'subpar').
ERROR: Error evaluating WORKSPACE file.
ERROR: error loading package 'external': Package 'external' contains errors.

Seems like you're loading subpar as a part of docker_repositories(), and it's conflicting with the existing subpar target we already have.

Maybe namespacing it in some way (e.g. rules_docker_subpar) could prevent this?

docker_bundle always up-to-date (nothing to build)

Playing around trying to see how this can be used for a general go project. Building the binary via go_binary and image via docker_build works, but docker_bundle always says it's up-to-date, when no binary bundle (tarball I'm expecting is being produced.

Output is:

$ bazel build :docker

INFO: Found 1 target...
Target //:docker up-to-date (nothing to build)
INFO: Elapsed time: 0.837s, Critical Path: 0.64s

Here's my BUILD file:

go_binary(
    name = "dummy-web",
    library = ":go_default_library",
)

docker_build(
    name = "docker-internal",
    base = "@distroless_base//image:image.tar",
    entrypoint = ["/dummy-web"],
    files = [":dummy-web"],
    visibility = ["//visibility:private"],
)

docker_bundle(
    name = "docker",
    images = {
        "dummy/web:latest": ":docker-internal",
    },
    stamp = True,
)

I assume i'm doing something wrong but not sure what (I'm a bazel n00b I'm afraid).

docker_pull fails on syntax error

Hi,

I'm using ArchLinux and I get an error when adding that to my workspace:

docker_pull(
    name = "busybox",
    registry = "index.docker.io",
    repository = "library/busybox",
    tag = "1.26.2-musl"
)

the error is:

    Pull command failed: Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/sphax/.cache/bazel/_bazel_sphax/420d00f9ffa546a452fc5bdf768b31b7/external/puller/file/puller.par/__main__.py", line 26, in <module>
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 646, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 616, in _load_backward_compatible
  File "/home/sphax/.cache/bazel/_bazel_sphax/420d00f9ffa546a452fc5bdf768b31b7/external/puller/file/puller.par/containerregistry/client/__init__.py", line 23, in <module>
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 646, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 616, in _load_backward_compatible
  File "/home/sphax/.cache/bazel/_bazel_sphax/420d00f9ffa546a452fc5bdf768b31b7/external/puller/file/puller.par/containerregistry/client/docker_creds_.py", line 26, in <module>
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 946, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 885, in _find_spec
  File "<frozen importlib._bootstrap_external>", line 1157, in find_spec
  File "<frozen importlib._bootstrap_external>", line 1131, in _get_spec
  File "<frozen importlib._bootstrap_external>", line 1112, in _legacy_get_spec
  File "<frozen importlib._bootstrap>", line 427, in spec_from_loader
  File "<frozen importlib._bootstrap_external>", line 544, in spec_from_file_location
  File "/home/sphax/.cache/bazel/_bazel_sphax/420d00f9ffa546a452fc5bdf768b31b7/external/puller/file/puller.par/httplib2/__init__.py", line 942
    print "connect: (%s, %s) ************" % (self.host, self.port)
                                         ^
SyntaxError: invalid syntax

By default Arch uses Python 3, looks like this is the problem ?

Is there a way to tell bazel to use python 2 ? I tried to run bazel with --python2_path=/usr/bin/python2 when it doesn't work.

docker_push incompatible with quay.io (manifest schema version not supported?)

I'm trying to push an image to quay.io with docker_push, and get the following error:

$ bazel run //python2.7:push_python27_cpp 
INFO: Analysed target //python2.7:push_python27_cpp (0 packages loaded).
INFO: Found 1 target...
Target //python2.7:push_python27_cpp up-to-date:
  bazel-bin/python2.7/push_python27_cpp
INFO: Elapsed time: 0.167s, Critical Path: 0.01s
INFO: Build completed successfully, 1 total action

INFO: Running command line: bazel-bin/python2.7/push_python27_cpp
+ ../pusher/file/pusher.par --name=quay.io/postmates/distroless_python27_cpp:dev --config=python2.7/python27_cpp.config --digest=base/with_tmp-layer.tar.gz.sha256 --digest=base/base-layer.tar.gz.sha256 --digest=python2.7/python27-layer.tar.gz.sha256 --digest=python2.7/python27_cpp-layer.tar.gz.sha256 --layer=base/with_tmp-layer.tar.gz --layer=base/base-layer.tar.gz --layer=python2.7/python27-layer.tar.gz --layer=python2.7/python27_cpp-layer.tar.gz
ERROR:root:Error during upload of: quay.io/postmates/distroless_python27_cpp:dev
Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "../pusher/file/pusher.par/__main__.py", line 129, in <module>
  File "../pusher/file/pusher.par/__main__.py", line 124, in main
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 300, in upload
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 228, in _put_manifest
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_http_.py", line 340, in Request
containerregistry.client.v2_2.docker_http_.V2DiagnosticException: response: {'status': '415', 'content-length': '131', 'server': 'nginx/1.13.3', 'connection': 'keep-alive', 'date': 'Wed, 02 Aug 2017 19:14:01 GMT', 'content-type': 'application/json'}
manifest invalid: {u'message': u'manifest schema version not supported'}

Pushing to private registry throws an exception

Hey,

First of all thanks for working on bazel and docker support. I'm new to bazel. I try to figure out whether it makes sense for me to use bazel. At the moment I try building docker images and pushing them to my registry.

I have my own docker registry running, but if I try to push using docker_push an error is thrown:

Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "../pusher/file/pusher.par/__main__.py", line 129, in <module>
  File "../pusher/file/pusher.par/__main__.py", line 121, in main
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 71, in __init__
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_http_.py", line 177, in __init__
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_http_.py", line 215, in _Ping
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_http_.py", line 128, in _CheckState
containerregistry.client.v2_2.docker_http_.BadStateException: Unexpected "www-authenticate" header: Basic realm="Registry Realm"

My docker command for running the registry is basically:

docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v `pwd`/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  -v `pwd`/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2

My BUILD file looks like this:

load("@io_bazel_rules_docker//docker:docker.bzl", "docker_build", "docker_push")

docker_build(
    name="db1",
    files=["file.txt", "//project/setup:setup"],
    base="@nginx-alpine//image",
)

docker_push(
    name="push-db1",
    image=":db1",
    registry="registry.example.com",
    repository="project/db1",
    tag="latest",
)

My ~/.docker/config.jsonfile:

cat ~/.docker/config.json
{
	"auths": {
		"https://registry.gitlab.com": {},
		"registry.example.com": {},
		"registry.gitlab.com": {}
	},
	"credsStore": "osxkeychain"
}

Running bazel build works fine, but I don't know how to provide the credentials.

Can someone guide me how to provide the credentials?

Thanks!
Tarek

pushall emits a warning

Using pushall to push a bundle always emits a warning:

docker/contrib/push-all.bzl:39:7: Pushing an image based on a tarball can be very expensive.  If the image is the output of a docker_build, consider dropping the '.tar' extension. If the image is checked in, consider using docker_import instead.

Any way around this?

Remove requirement on GNU tar

A patch in #87 explicitly made GNU tar a requirement.

The root cause of the issue that prompted the change is tar usage within incremental_load.sh.tpl. tar --create --absolute-names --dereference ... causes errors when the BSD variant is used (default on Macs).

It would be good to remove the prerequisite on GNU tar within the script so other implementations (especially BSD) could be used without users having to do anything.

Implementing #72 will most likely supersede this.

files added from repository rule have impossible paths

If I add the following to docker/testdata/BUILD:

docker_build(
    name = "data_path_image_external",
    files = ["@com_google_guava_guava//jar"],
    mode = "0644",
    data_path = "/",
)

It produces an image with:

$ tar tvf ../../bazel-bin/docker/testdata/data_path_image_external-layer.tar
drwxr-xr-x 0/0               0 1970-01-01 00:00 ./
tar: Removing leading `./..' from member names
drwxr-xr-x 0/0               0 1970-01-01 00:00 ./../
tar: Removing leading `./../' from member names
drwxr-xr-x 0/0               0 1970-01-01 00:00 ./../com_google_guava_guava/
drwxr-xr-x 0/0               0 1970-01-01 00:00 ./../com_google_guava_guava/jar/
-rw-r--r-- 0/0         2256213 1970-01-01 00:00 ./../com_google_guava_guava/jar/guava-18.0.jar

docker_import may result in layer mismatch

Resulting in:

invalid manifest, layers length mismatch: expected 6, got 4

The bug is here:

  TOTAL_DIFF_IDS=($(cat "${name}" | python -mjson.tool | \
      grep sha256 | cut -d'"' -f 2 | cut -d':' -f 2))

Essentially, this doesn't filter things enough. The config may contain lines like:

        "Image": "sha256:3fdb6bcbf1c1e852e13c0defe66743162cd07bee677bdbdd82db7f3f395349e4",

Which results in the manifest.json containing additional entries like "Image.tar".

The fix is to expand the filter to something like: grep -E '^ +"sha256:'

Docker disallows use of 64-byte hexadecimal strings for repository name

Minimal repo: https://gist.github.com/jschaf/5fbdc65730fe9cdf7dcf5ddd9c95e0da

bazel run //:hello

The command errors with:

INFO: Found 1 target...
Target //:java up-to-date:
  bazel-bin/java-layer.tar
INFO: Elapsed time: 36.408s, Critical Path: 0.60s

INFO: Running command line: bazel-bin/java
Loading 24c4a0933bbd2f6c65ed283d84502fed4d22c77bacd109353929fea482da6025...
Loaded image ID: sha256:24c4a0933bbd2f6c65ed283d84502fed4d22c77bacd109353929fea482da6025
Tagging 24c4a0933bbd2f6c65ed283d84502fed4d22c77bacd109353929fea482da6025 as bazel/:java
Error parsing reference: "24c4a0933bbd2f6c65ed283d84502fed4d22c77bacd109353929fea482da6025" is not a valid repository/tag: invalid repository name (24c4a0933bbd2f6c65ed283d84502fed4d22c77bacd109353929fea482da6025), cannot specify 64-byte hexadecimal strings

Here's the upstream issue, Docker #20972. The relevant quote is:

In general, we don't want to allow unprefixed 64-character hexadecimal image references. The concern is that a tag like 3240943c9ea3f72db51bea0a2428e83f3c5fa1312e19af017d026f9bcf70f84b could cause ambiguity when there is a content-addressable image ID with a matching digest. The safest way to avoid tags like this from being created or used is to reject references like this at parsing time. Admittedly, rmi behaves a bit differently here. This is not a big concern because rmi can't be used to create an ambiguous tag.

Is there a work around or fix available?

docker_build does not work well with py_binary

Say I have a python rule:

py_binary(
    name = 'main',
    ...
)

And I make a docker build rule that looks like this:

docker_build(
    files = ['//path/to/bin:main'],
    ...
)

If I do a bazel run for this rule and then inspect the contents of the image, i see that the main executable has been copied over but not the directory main.runfiles or the manifest main.runfile_manifest. Without these files the python executable will not work. Am I doing something wrong?

add filter / exclude to docker_build

At the moment, if you install a deb in debian_build, all content from the deb is extracted.
It would be nice if some filter / exclude option was added to e.g filer /usr/share/man , /usr/share/doc

Document the more-efficient on-disk format used by rules_docker

This is a work in progress on top of #70 building tighter integration between docker_pull, docker_push and the new intermediate form of docker_build in the diffbase PR.

For users that want to build and transport Docker images without running a Linux-only daemon as root, the Bazel docker rules and pusher.par are currently the only game in town. Rather than treating this new image layout as an opaque implementation detail of docker_push, consider naming it and documenting its structure.

Then you'd have the additional advantage over docker save and docker push in that people could figure out how to integrate other tooling into the pipeline without having to crack open the Docker CLI source code.

-- from @jmillikin-stripe on #71

digest or user input as docker_push tag

So, I'm trying to figure out how to avoid needing docker in my CI in order to make deploys to kubernetes. A docker_push plus some locally kept templated k8s deployment YAMLs or just kubectl set image seems doable, but the default deployment strategies won't work if that tag is always latest (plus the k8s folks recommend against that for pretty good reasons).

My question: Is there a way to specify the docker image's tag in docker_push such that it uses the SHA256 digest of the image?

I guess this is maybe two questions: is there a way to specify what tag = to build with from user input or is there a way to get to the digest from skylark code that specifies the tag attribute?

(As a little side thing here, using the digest as the tag has the nice benefit of making k8s do a rolling restart only occur if there's been a change to the docker image since the last deploy, which is handy!)

Unable to pull from index.docker.io

docker_pull(
  name = "java_base",
  registry = "index.docker.io",
  repository = "openjdk",
  tag = "8"
)
containerregistry.client.v2_2.docker_http_.V2DiagnosticException: response: {'status': '401', 'content-length': '150', 'strict-transport-security': 'max-age=31536000', 'docker-distribution-api-version': 'registry/2.0', 'date': 'Sat, 13 May 2017 17:13:17 GMT', 'content-type': 'application/json; charset=utf-8', 'www-authenticate': 'Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:openjdk:pull",error="insufficient_scope"'}
authentication required: [{u'Action': u'pull', u'Type': u'repository', u'Class': u'', u'Name': u'openjdk'}]

Why is authentication required to do the same as docker pull openjdk:8? Is there a workaround?

bazel run docker_build doesn't work when using stamps

cc @ixdy

repro

$ bazel run //build:kube-controller-manager                                                                                                                                                                                                                                                           
INFO: Found 1 target...
Target //build:kube-controller-manager up-to-date (nothing to build)
INFO: Elapsed time: 7.461s, Critical Path: 5.67s

INFO: Running command line: bazel-bin/build/kube-controller-manager
Loading d10f0ce649a0386cfc6df629ba86375210548a6d4cf62ca52e722213f4d95eda...
Loaded image: bazel/build:busybox
Loading 9bd778a641e0bbd2a59d3a0d11cfa670aeb0b73800db6321491ada6022f86519...
Loaded image: bazel/build:kube-controller-manager-internal
Tagging 9bd778a641e0bbd2a59d3a0d11cfa670aeb0b73800db6321491ada6022f86519 as gcr.io/google_containers/kube-controller-manager:{STABLE_DOCKER_TAG}
Error parsing reference: "gcr.io/google_containers/kube-controller-manager:{STABLE_DOCKER_TAG}" is not a valid repository/tag

docker_push not working

Build rules:

go_binary(
    name = "greeter_http_server",
    srcs = ["greeter_http.go"],
    deps = [":helloworld_proto_go"] + GRPC_GATEWAY_DEPS,
)

docker_build(
    name = "greeter_http_server_docker",
    base = "@joeshaw_busybox_nonroot//image:image.tar",
    cmd = ["./greeter_http_server"],
    files = [":greeter_http_server"],
    ports = ["8080"],
    repository = "registry.gitlab.com/<blah>",
    symlinks = {
        "/usr/bin/greeter_http_server": "greeter_http_server",
    },
)

docker_push(
    name = "greeter_http_server_docker_push",
    image = ":greeter_http_server_docker",
    registry = "registry.gitlab.com",
    repository = "<blah>/samples/helloworld",
    tag = "dev",
)

Error:

$ bazeldev run samples/helloworld:greeter_http_server_docker_push
INFO: Found 1 target...
Target //samples/helloworld:greeter_http_server_docker_push up-to-date:
  bazel-bin/samples/helloworld/greeter_http_server_docker_push
INFO: Elapsed time: 0.544s, Critical Path: 0.29s

INFO: Running command line: bazel-bin/samples/helloworld/greeter_http_server_docker_push
+ ../pusher/file/pusher.par --name=registry.gitlab.com/<blah>/samples/helloworld:dev --tarball=samples/helloworld/greeter_http_server_docker.tar
ERROR:root:Error during upload of: registry.gitlab.com/<blah>/samples/helloworld:dev
Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "../pusher/file/pusher.par/__main__.py", line 71, in <module>
  File "../pusher/file/pusher.par/__main__.py", line 66, in main
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 294, in upload
  File "../pusher/file/pusher.par/concurrent/futures/_base.py", line 398, in result
  File "../pusher/file/pusher.par/concurrent/futures/thread.py", line 55, in run
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 264, in _upload_one
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 186, in _put_blob
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_session_.py", line 125, in _monolithic_upload
  File "../pusher/file/pusher.par/containerregistry/client/v2_2/docker_http_.py", line 333, in Request
containerregistry.client.v2_2.docker_http_.V2DiagnosticException: response: {'status': '202', 'content-length': '0', 'content-security-policy': "object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' piwik.gitlab.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/; style-src 'self' 'unsafe-inline'; img-src * data: blob:; frame-src 'self' https://www.google.com/recaptcha/; frame-ancestors 'none'; connect-src 'self' wss://gitlab.com; report-uri https://sentry-infra.gitlap.com/api/3/csp-report/?sentry_key=a664fdde83424b43a991f25fa7c78987", 'x-content-type-options': 'nosniff', 'docker-upload-uuid': '9e142cbb-38be-4023-a995-3973871bb035', 'server': 'nginx', 'range': '0-0', 'docker-distribution-api-version': 'registry/2.0', 'location': 'https://registry.gitlab.com/v2/<blah>/samples/helloworld/blobs/uploads/9e142cbb-38be-4023-a995-3973871bb035?_state=e7GilJ0V9PBDIMONe0vaApbNxhosgpwZNLyj1rpjph17Ik5hbWUiOiJjaGFpdGFueWE5MTg2L3NyZWxsaWszL3NhbXBsZXMvaGVsbG93b3JsZCIsIlVVSUQiOiI5ZTE0MmNiYi0zOGJlLTQwMjMtYTk5NS0zOTczODcxYmIwMzUiLCJPZmZzZXQiOjAsIlN0YXJ0ZWRBdCI6IjIwMTctMDUtMDFUMjM6MDI6MjEuMTkxMzE3MTE1WiJ9', 'date': 'Mon, 01 May 2017 23:02:21 GMT', 'content-type': 'text/plain; charset=utf-8'}
: None
ERROR: Non-zero return code '1' from command: Process exited with status 1.

Env details:

$ docker -v
Docker version 17.05.0-ce-rc2, build c57fdb2a14cfba584686ddad909e3006284d10aa

$ sudo cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=17.04
DISTRIB_CODENAME=zesty
DISTRIB_DESCRIPTION="Ubuntu 17.04"
NAME="Ubuntu"
VERSION="17.04 (Zesty Zapus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 17.04"
VERSION_ID="17.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=zesty
UBUNTU_CODENAME=zesty

Please add simple helloworld example for bazel Docker Rules

Please update the documentation for bazel docker rules with a concrete, easy to follow live example.

I'm familiar with traditional docker-based build and as a (very) new user of bazel, I'd like to see where i can use bazel.

It'd help if we update our docs with a 'concrete' example: eg. suggest a full end to end example that runs alpine with python and then simply echo python -c 'print "hello world"' or some such; (something i can run off the bat)

Stamp for docker_push?

In my docker/BUILD file I have something like this to create docker images. Currently this requires bazel clean between builds for these services because I haven't figured out how to get the stamps to update every run (which is besides the point, there must be a way).

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

load("@io_bazel_rules_docker//docker:docker.bzl", "docker_bundle", "docker_push")

DOCKER_BUILDS = {
    "assets":       "//assets/assets:docker", # etc...
}

[docker_bundle(
    name = binary,
    images = {"gcr.io/{GCLOUD_PROJECT_ID}/%s:{BRANCH_NAME}-{BUILD_NUMBER}" % binary: docker_image},
    stamp = True
 ) for binary, docker_image in DOCKER_BUILDS.items()]

My desire is to define matching docker_push targets:

[docker_push(
    name = "push_" + binary,
    image = ":" + binary,
    registry = "gcr.io",
    repository = "{GCLOUD_PROJECT_ID}/%s" % binary,
    tag = "{BRANCH_NAME}-{BUILD_NUMBER}",
    stamp = true,
 ) for binary in DOCKER_BUILDS.keys()]

However this doesn't appear to be supported. I assume there is a reason why that is escaping me. Or maybe I should just be doing this in an external tool.

Creating empty, mode 0777 /tmp directory

Looking in the docs it appears that it would be possible to make a file in a directory called "/tmp" but I can't figure out how to make a /tmp dir with mode 0777. Is that possible?

Unable to pull from local docker registry

docker_pull does not work with docker registry without authentication. The error message is "external/puller/file/puller.par/containerregistry/client/v2_2/docker_http_.py", line 128, in CheckState, containerregistry.client.v2_2.docker_http_.BadStateException: Unexpected status: 200".

https://github.com/docker/docker.github.io/blob/master/registry/deploying.md

The docker registry spec states "If a 200 OK response is returned, the registry implements the V2(.1) registry API and the client may proceed safely with other V2 operations." However, containerregistry always expects 401 status code.

https://github.com/docker/distribution/blob/master/docs/spec/api.md#api-version-check
https://github.com/google/containerregistry/blob/master/client/v2_2/docker_http_.py#L201

expected value of type 'string' for attribute 'base' in 'docker_build_' rule, but got ["@java_base//image:image.tar"] (list).

In the readme, this given example throws an error expected value of type 'string' for attribute 'base' in 'docker_build_' rule, but got ["@java_base//image:image.tar"] (list).

docker_build(
    name = "app",
    # References docker_pull from WORKSPACE (above)
    base = ["@java_base//image:image.tar"],
    files = ["//java/com/example/app:Hello_deploy.jar"],
    cmd = ["Hello_deploy.jar"]
)

Make testing/e2e.sh a bazel test...

So we can run it on Bazel.

We have docker test in Bazel, and we can depends on the bazel installer to get bazel inside the test so it should be possible.

Docker image tarballs have wrong created time when imported to Docker

$ docker images|grep dummy

dummy/web                                                  latest                    df93a33aa16b        292 years ago       21.1MB

I also noticed that all files in the tarball have a created date of 1970-01-01 01:00:

$ tar tvf bazel-bin/docker.tar

-rw-r--r-- 0/0             606 1970-01-01 01:00 df93a33aa16b04e027f600b2f429e80a8b6a8896d035910ec5b90109269d3326.json
-rw-r--r-- 0/0               3 1970-01-01 01:00 9f8383f973c5c7dece737d92e6587a0f37002b20287303512f260d6a506bf4f4/VERSION
-rw-r--r-- 0/0         9482240 1970-01-01 01:00 9f8383f973c5c7dece737d92e6587a0f37002b20287303512f260d6a506bf4f4/layer.tar
-rw-r--r-- 0/0             349 1970-01-01 01:00 9f8383f973c5c7dece737d92e6587a0f37002b20287303512f260d6a506bf4f4/json
-rw-r--r-- 0/0               3 1970-01-01 01:00 fb8b0e2a7f9d34c6bd92e1700b942fe81e3603d021fc442470cdd8227d3dbc7a/VERSION
-rw-r--r-- 0/0        11950080 1970-01-01 01:00 fb8b0e2a7f9d34c6bd92e1700b942fe81e3603d021fc442470cdd8227d3dbc7a/layer.tar
-rw-r--r-- 0/0             241 1970-01-01 01:00 fb8b0e2a7f9d34c6bd92e1700b942fe81e3603d021fc442470cdd8227d3dbc7a/json
-rw-r--r-- 0/0               3 1970-01-01 01:00 07dd64f81c937fe7a80aabfb2b5376e80746bed42e8a89c74bf2c579b553dd50/VERSION
-rw-r--r-- 0/0           10240 1970-01-01 01:00 07dd64f81c937fe7a80aabfb2b5376e80746bed42e8a89c74bf2c579b553dd50/layer.tar
-rw-r--r-- 0/0             178 1970-01-01 01:00 07dd64f81c937fe7a80aabfb2b5376e80746bed42e8a89c74bf2c579b553dd50/json
-rw-r--r-- 0/0              95 1970-01-01 01:00 repositories
-rw-r--r-- 0/0             367 1970-01-01 01:00 manifest.json

Allow Ignoring of pre-loaded packages.

Via the docker_repositories() initialization command it would be great if we had a way to re-use existing dependencies.

Let's say for example I was attempting to build something in the tensorflow/tensorflow tf_workspace, that we have loaded up. It turns out they have already imported six:

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/workspace.bzl#L302

native.bind(
    name = "six",
    actual = "@six_archive//:six",
)

Without being able to override in some manner we are unable to use the docker_build rules in the same workspace. pubref/rules_protobuf an interesting way to handle these sorts of dependencies:
https://github.com/pubref/rules_protobuf#overriding-or-excluding-workspace-dependencies

go_proto_repositories(
  excludes = [
    "com_github_golang_glog",
  ]
)

Which then uses some require logic under the hood to load / not load the repository functions.

In interim I suppose it's possible to manually include the dependencies other than the ones we have already defined and go from there. This seems like something that might get solved as we move towards: bazelbuild/bazel#1943

docker_build error: AttributeError: 'module' object has no attribute 'ExtractValue'

docker_build rule is failing locally for me. Any idea what could be causing the following error:

INFO: Found 1 target...
ERROR: /home/jdyson/projects/bazel-golang-docker-example/BUILD:20:1: null failed: Process exited with status 1 [sandboxed].
Traceback (most recent call last):
  File "/home/jdyson/.cache/bazel/_bazel_jdyson/0016da4edad2c31f0ea83fd2b70559a0/bazel-sandbox/5912333423796671488/execroot/bazel-golang-docker-example/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image_config.runfiles/bazel_golang_docker_example/../io_bazel_rules_docker/docker/create_image_config.py", line 107, in <module>
    main()
  File "/home/jdyson/.cache/bazel/_bazel_jdyson/0016da4edad2c31f0ea83fd2b70559a0/bazel-sandbox/5912333423796671488/execroot/bazel-golang-docker-example/bazel-out/host/bin/external/io_bazel_rules_docker/docker/create_image_config.runfiles/bazel_golang_docker_example/../io_bazel_rules_docker/docker/create_image_config.py", line 85, in main
    layers.append(utils.ExtractValue(layer))
AttributeError: 'module' object has no attribute 'ExtractValue'
Use --strategy=ImageConfig=standalone to disable sandboxing for the failing actions.
Target //:go_example failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 4.010s, Critical Path: 1.77s

Triage quoting

On #98 Doug pointed out that we likely have various quoting problems passing strings as values to utility binaries.

This tracks triaging and fixing them.

default repository for docker_build

It'd be nice to have a way to change the default repository for my docker_build somewhere in WORKSPACE or a top-level BUILD.bazel or similar. I always forget to change it to my private gcr.io docker repo unless I copy and paste the docker_build from elsewhere.

Add stamping documentation

We definitely need this for docker_push, but may as well for docker_bundle.

We should have a section specifically dedicated to stamping in the README.md.

bazel explodes on multiple docker_build rules in same package with different external base images

Simple example given in ixdy@8125a4c.

I have two docker_build rules in the same BUILD file, each one depending on an different external image (pulled in through docker_pull in my WORKSPACE).

When I try to build both, bazel explodes, I guess because they are both trying to create the same artifact, image.tar.id:

$ bazel build foo.tar bar.tar
.
ERROR: file 'image.tar.id' is generated by these conflicting actions:
Label: //:foo, //:bar
RuleClass: docker_build_ rule
Configuration: 32a994dd81b79c0621b68fa6003f0e25
Mnemonic: ExtractID
Action key: c0d8c6c6b75540d6052f398dcbf6fc31, fdc7414328621a989a7e2ce8c931afc8
Progress message: ExtractID image.tar.id
PrimaryInput: File:[/usr/local/google/home/jgrafton/.cache/bazel/_bazel_jgrafton/1c344542258c3021719db9a8e772b13f[source]]external/official_python/image/image.tar, File:[/usr/local/google/home/jgrafton/.cache/baz
el/_bazel_jgrafton/1c344542258c3021719db9a8e772b13f[source]]external/official_busybox/image/image.tar
PrimaryOutput: File:[[/usr/local/google/home/jgrafton/.cache/bazel/_bazel_jgrafton/1c344542258c3021719db9a8e772b13f/execroot/rules_docker]bazel-out/local-fastbuild/bin]image.tar.id
.
ERROR: Analysis of target '//:foo' failed; build aborted.
INFO: Elapsed time: 35.226s

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.