Organize LTLs and yamls to layer folder structure. (#76)

This PR includes the following changes:

* Organize LTLs and yamls to layer folder structure.

* Also print out detailed test log in ci.

* Update rules_docker pin which fixes the naming conflicts of input image to container_tests (https://github.com/bazelbuild/rules_docker/pull/428). The naming conflicts cause the flakiness of container_tests in our repo, i.e. rbe-ubuntu16_04's contain_test can accidentally use the toolchain tar built for rbe-debian8.

diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index eb4e83b..620a95d 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -4,39 +4,39 @@
     test_targets:
     - "//test/configs:debian-jessie-autoconfig_test"
     - "//test/configs:debian-jessie-bazel-head-autoconfig_test"
-    - "//test/configs:debian-jessie-custom-bazel-version-autoconfig_test"
     - "//test/configs:debian-jessie-custom-bazel-rc-version-autoconfig_test"
     - "//test/configs:ubuntu-xenial-autoconfig_test"
     - "//test/configs:ubuntu-xenial-bazel-head-autoconfig_test"
-    - "//test/configs:ubuntu-xenial-custom-bazel-version-autoconfig_test"
     - "//test/configs:ubuntu-xenial-custom-bazel-rc-version-autoconfig_test"
     - "//test/configs:debian8_clang_autoconfig_test"
     - "//configs/debian8_clang:debian8-clang-0.3.0-bazel_0.13.0-autoconfig_test"
     - "//configs/debian8_clang:msan-debian8-clang-0.3.0-bazel_0.13.0-autoconfig_test"
     - "//configs/ubuntu16_04_clang:ubuntu16_04-clang-0.3.0-bazel_0.13.0-autoconfig_test"
     - "//configs/ubuntu16_04_clang:msan-ubuntu16_04-clang-0.3.0-bazel_0.13.0-autoconfig_test"
-    - "//container/rbe-debian8:toolchain-test"
-    - "//container/rbe-ubuntu16_04:toolchain-test"
+    - "//container/debian8/builders/rbe-debian8:toolchain-test"
+    - "//container/ubuntu16_04/builders/rbe-ubuntu16_04:toolchain-test"
     - "//container/experimental/rbe-debian9:toolchain-test"
     - "//container/ubuntu16_04/builders/bazel:bazel-test"
     - "//container/ubuntu16_04/builders/bazel:bazel_docker-test"
+    test_flags:
+    - "--test_output=all"
   ubuntu1604:
     test_targets:
     - "//test/configs:debian-jessie-autoconfig_test"
     - "//test/configs:debian-jessie-bazel-head-autoconfig_test"
-    - "//test/configs:debian-jessie-custom-bazel-version-autoconfig_test"
     - "//test/configs:debian-jessie-custom-bazel-rc-version-autoconfig_test"
     - "//test/configs:ubuntu-xenial-autoconfig_test"
     - "//test/configs:ubuntu-xenial-bazel-head-autoconfig_test"
-    - "//test/configs:ubuntu-xenial-custom-bazel-version-autoconfig_test"
     - "//test/configs:ubuntu-xenial-custom-bazel-rc-version-autoconfig_test"
     - "//test/configs:debian8_clang_autoconfig_test"
     - "//configs/debian8_clang:debian8-clang-0.3.0-bazel_0.13.0-autoconfig_test"
     - "//configs/debian8_clang:msan-debian8-clang-0.3.0-bazel_0.13.0-autoconfig_test"
     - "//configs/ubuntu16_04_clang:ubuntu16_04-clang-0.3.0-bazel_0.13.0-autoconfig_test"
     - "//configs/ubuntu16_04_clang:msan-ubuntu16_04-clang-0.3.0-bazel_0.13.0-autoconfig_test"
-    - "//container/rbe-debian8:toolchain-test"
-    - "//container/rbe-ubuntu16_04:toolchain-test"
+    - "//container/debian8/builders/rbe-debian8:toolchain-test"
+    - "//container/ubuntu16_04/builders/rbe-ubuntu16_04:toolchain-test"
     - "//container/experimental/rbe-debian9:toolchain-test"
     - "//container/ubuntu16_04/builders/bazel:bazel-test"
     - "//container/ubuntu16_04/builders/bazel:bazel_docker-test"
+    test_flags:
+    - "--test_output=all"
diff --git a/WORKSPACE b/WORKSPACE
index ca05153..5240766 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -23,9 +23,9 @@
 # https://docs.bazel.build/versions/master/be/workspace.html#git_repository
 http_archive(
     name = "io_bazel_rules_docker",
-    sha256 = "33ef2a5d3992bc44494b84f932cd114d1fc44c377a76e033adcf09a5d258dbb7",
-    strip_prefix = "rules_docker-b1ea0f972422e246fb6f39d9a21ec435d78a80de",
-    urls = ["https://github.com/bazelbuild/rules_docker/archive/b1ea0f972422e246fb6f39d9a21ec435d78a80de.tar.gz"],
+    sha256 = "b0e6a7fb7a505de72c055ce4e9af4ef18417fe99f226af3afb6bfe3be7fe23ad",
+    strip_prefix = "rules_docker-993d320b7ad1376cbf5a1c5b7080d82a76e286a2",
+    urls = ["https://github.com/bazelbuild/rules_docker/archive/993d320b7ad1376cbf5a1c5b7080d82a76e286a2.tar.gz"],
 )
 
 load(
diff --git a/container/build.sh b/container/build.sh
index 3ea6ac2..f45d05f 100755
--- a/container/build.sh
+++ b/container/build.sh
@@ -19,9 +19,9 @@
 
 # Map to store all supported container type and the package of target to build it.
 declare -A TYPE_PACKAGE_MAP=(
-  ["rbe-debian8"]="container/rbe-debian8"
+  ["rbe-debian8"]="container/debian8/builders/rbe-debian8"
   ["rbe-debian9"]="container/experimental/rbe-debian9"
-  ["rbe-ubuntu16_04"]="container/rbe-ubuntu16_04"
+  ["rbe-ubuntu16_04"]="container/ubuntu16_04/builders/rbe-ubuntu16_04"
   ["ubuntu16_04-bazel"]="container/ubuntu16_04/builders/bazel"
   ["ubuntu16_04-bazel-docker"]="container/ubuntu16_04/builders/bazel"
 )
diff --git a/container/common/BUILD b/container/common/BUILD
new file mode 100644
index 0000000..8ece167
--- /dev/null
+++ b/container/common/BUILD
@@ -0,0 +1,19 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+exports_files(glob(["*.yaml"]))
diff --git a/container/common/clang.yaml b/container/common/clang.yaml
new file mode 100644
index 0000000..051f6cc
--- /dev/null
+++ b/container/common/clang.yaml
@@ -0,0 +1,76 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+commandTests:
+- name: 'cc-envvar'
+  command: ['sh', '-c', 'echo $CC']
+  expectedOutput: ['/usr/local/bin/clang']
+- name: 'clang-version'
+  command: ['bash', '-c', 'clang --version']
+  expectedOutput: ['clang version 7.0.0.*']
+
+fileExistenceTests:
+- name: 'Clang'
+  isDirectory: false
+  path: '/usr/local/bin/clang'
+  shouldExist: true
+- name: 'libcxx-header'
+  isDirectory: true
+  path: '/usr/local/include/c++/v1'
+  shouldExist: true
+- name: 'libcxx-lib'
+  isDirectory: false
+  path: '/usr/local/lib/libc++.a'
+  shouldExist: true
+- name: 'llvm-symbolizer'
+  isDirectory: false
+  path: '/usr/local/bin/llvm-symbolizer'
+  shouldExist: true
+- name: 'sanitizer'
+  isDirectory: true
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer'
+  shouldExist: true
+- name: 'sanitizer-allocator'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/allocator_interface.h'
+  shouldExist: true
+- name: 'sanitizer-asan'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/asan_interface.h'
+  shouldExist: true
+- name: 'sanitizer-common_defs'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/common_interface_defs.h'
+  shouldExist: true
+- name: 'sanitizer-coverage'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/coverage_interface.h'
+  shouldExist: true
+- name: 'sanitizer-dfsan'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/dfsan_interface.h'
+  shouldExist: true
+- name: 'sanitizer-esan'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/esan_interface.h'
+  shouldExist: true
+- name: 'sanitizer-linux_syscall_hooks'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/linux_syscall_hooks.h'
+  shouldExist: true
+- name: 'sanitizer-lsan'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/lsan_interface.h'
+  shouldExist: true
+- name: 'sanitizer-msan'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/msan_interface.h'
+  shouldExist: true
+- name: 'sanitizer-tsan_atomic'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface_atomic.h'
+  shouldExist: true
+- name: 'sanitizer-tsan'
+  isDirectory: false
+  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface.h'
+  shouldExist: true
diff --git a/container/common/go.yaml b/container/common/go.yaml
new file mode 100644
index 0000000..34806da
--- /dev/null
+++ b/container/common/go.yaml
@@ -0,0 +1,16 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+commandTests:
+- name: 'gopath-envvar'
+  command: ['sh', '-c', 'echo $GOPATH']
+  expectedOutput: ['/go']
+- name: 'go-version'
+  command: ['bash', '-c', 'go version']
+  expectedOutput: ['go version go1.10 linux/amd64']
+
+fileExistenceTests:
+- name: 'Golang'
+  isDirectory: false
+  path: '/usr/local/go/bin/go'
+  shouldExist: true
diff --git a/container/common/java.yaml b/container/common/java.yaml
new file mode 100644
index 0000000..bf2c8ff
--- /dev/null
+++ b/container/common/java.yaml
@@ -0,0 +1,16 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+commandTests:
+- name: 'javahome-envvar'
+  command: ['sh', '-c', 'echo $JAVA_HOME']
+  expectedOutput: ['/usr/lib/jvm/java-8-openjdk-amd64']
+- name: 'java-version'
+  command: ['bash', '-c', 'java -version 2>&1']
+  expectedOutput: ['openjdk version \"1.8.*']
+
+fileExistenceTests:
+- name: 'OpenJDK'
+  isDirectory: true
+  path: '/usr/lib/jvm/java-8-openjdk-amd64'
+  shouldExist: true
diff --git a/container/common/python2.yaml b/container/common/python2.yaml
new file mode 100644
index 0000000..d0cbbfa
--- /dev/null
+++ b/container/common/python2.yaml
@@ -0,0 +1,13 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+commandTests:
+- name: 'python2-version'
+  command: ['bash', '-c', 'python -V 2>&1']
+  expectedOutput: ['Python 2.7.*']
+
+fileExistenceTests:
+- name: 'Python2'
+  isDirectory: false
+  path: '/usr/bin/python2.7'
+  shouldExist: true
diff --git a/container/common/rbe-base.yaml b/container/common/rbe-base.yaml
new file mode 100644
index 0000000..91091c8
--- /dev/null
+++ b/container/common/rbe-base.yaml
@@ -0,0 +1,40 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+commandTests:
+- name: 'check-locale'
+  command: ['sh', '-c', 'echo $LC_ALL']
+  expectedOutput: ['C.UTF-8']
+- name: 'check-ed'
+  command: ['bash', '-c', 'ed --version']
+  expectedOutput: ['GNU [eE]d .*']
+- name: 'check-file'
+  command: ['bash', '-c', 'file --version']
+  expectedOutput: ['file-.*']
+- name: 'check-git'
+  command: ['bash', '-c', 'git --version']
+  expectedOutput: ['git version .*']
+- name: 'check-less'
+  command: ['bash', '-c', 'less --version']
+  expectedOutput: ['less .*']
+- name: 'check-netcat'
+  command: ['bash', '-c', 'nc -h 2>&1']
+  expectedOutput: ['\[v.*']
+- name: 'check-openssl'
+  command: ['bash', '-c', 'openssl version']
+  expectedOutput: ['OpenSSL .*']
+- name: 'check-patch'
+  command: ['bash', '-c', 'patch --version']
+  expectedOutput: ['GNU patch .*']
+- name: 'check-wget'
+  command: ['bash', '-c', 'wget --version']
+  expectedOutput: ['GNU Wget.* built on linux-gnu.*']
+- name: 'check-zip'
+  command: ['bash', '-c', 'zip --version']
+  expectedOutput: ['.*This is Zip.*']
+
+fileExistenceTests:
+- name: 'Root'
+  isDirectory: true
+  path: '/'
+  shouldExist: true
diff --git a/container/debian8/BUILD b/container/debian8/BUILD
new file mode 100644
index 0000000..8ece167
--- /dev/null
+++ b/container/debian8/BUILD
@@ -0,0 +1,19 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+exports_files(glob(["*.yaml"]))
diff --git a/container/debian8/builders/rbe-debian8/BUILD b/container/debian8/builders/rbe-debian8/BUILD
new file mode 100644
index 0000000..a0c9d32
--- /dev/null
+++ b/container/debian8/builders/rbe-debian8/BUILD
@@ -0,0 +1,84 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+    "toolchain_container",
+)
+load("@io_bazel_rules_docker//contrib:test.bzl", "container_test")
+
+language_tool_layer(
+    name = "base-ltl",
+    base = "@debian8//image",
+    packages = [
+        "binutils",
+        "ca-certificates",
+        "curl",
+        "ed",
+        "file",
+        "git",
+        "less",
+        "netcat",
+        "openssh-client",
+        "patch",
+        "unzip",
+        "wget",
+        "zip",
+    ],
+)
+
+toolchain_container(
+    name = "toolchain",
+    base = "@debian8//image",
+    cmd = [
+        "/bin/sh",
+        "-c",
+        "/bin/bash",
+    ],
+    env = {
+        # PATH envvar is a special case, and currently only the one in the
+        # topmost layer is set. So that we override it here to include all.
+        "PATH": "$PATH:/opt/python3.6/bin:/usr/local/go/bin",
+        "LANG": "C.UTF-8",
+        "LANGUAGE": "C.UTF-8",
+        "LC_ALL": "C.UTF-8",
+    },
+    language_layers = [
+        "base-ltl",
+        "//container/debian8/layers/clang:clang-ltl",
+        "//container/debian8/layers/go:go-ltl",
+        "//container/debian8/layers/java:java-ltl",
+        "//container/debian8/layers/python:python-ltl",
+    ],
+)
+
+container_test(
+    name = "toolchain-test",
+    configs = [
+        ":rbe-debian8.yaml",
+        "//container/common:clang.yaml",
+        "//container/common:go.yaml",
+        "//container/common:java.yaml",
+        "//container/common:python2.yaml",
+        "//container/common:rbe-base.yaml",
+        "//container/debian8:debian8.yaml",
+    ],
+    image = ":toolchain",
+    verbose = True,
+)
diff --git a/container/debian8/builders/rbe-debian8/rbe-debian8.yaml b/container/debian8/builders/rbe-debian8/rbe-debian8.yaml
new file mode 100644
index 0000000..77c7238
--- /dev/null
+++ b/container/debian8/builders/rbe-debian8/rbe-debian8.yaml
@@ -0,0 +1,22 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+fileExistenceTests:
+- name: 'Python3'
+  isDirectory: false
+  path: '/opt/python3.6/bin/python3'
+  shouldExist: true
+
+# Common tests
+commandTests:
+- name: 'path-envvar'
+  command: ['sh', '-c', 'echo $PATH']
+  expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/python3.6/bin:/usr/local/go/bin']
+- name: 'python3-version'
+  command: ['bash', '-c', 'python3 -V']
+  expectedOutput: ['Python 3.6.*']
+# This is failing in Debian9 base. Once resolved, move this test to
+# container/common/rbe-base.yaml.
+- name: 'check-curl'
+  command: ['bash', '-c', 'curl --version']
+  expectedOutput: ['curl .* \(x86_64-pc-linux-gnu\).*']
diff --git a/container/debian8/debian8.yaml b/container/debian8/debian8.yaml
new file mode 100644
index 0000000..1a84140
--- /dev/null
+++ b/container/debian8/debian8.yaml
@@ -0,0 +1,8 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+# Distro-specific tests
+commandTests:
+- name: 'os-version'
+  command: ['sh', '-c', 'cat /etc/issue.net']
+  expectedOutput: ['Debian GNU/Linux 8']
diff --git a/container/debian8/layers/clang/BUILD b/container/debian8/layers/clang/BUILD
new file mode 100644
index 0000000..d58d051
--- /dev/null
+++ b/container/debian8/layers/clang/BUILD
@@ -0,0 +1,39 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+language_tool_layer(
+    name = "clang-ltl",
+    base = "@debian8//image",
+    env = {
+        "CC": "/usr/local/bin/clang",
+        "ASAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
+        "MSAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
+    },
+    packages = [
+        "libstdc++-4.9-dev",
+    ],
+    tars = [
+        "//third_party/clang:debian8_tar",
+        "//third_party/libcxx:debian8_tar",
+    ],
+)
diff --git a/container/debian8/layers/go/BUILD b/container/debian8/layers/go/BUILD
new file mode 100644
index 0000000..b731324
--- /dev/null
+++ b/container/debian8/layers/go/BUILD
@@ -0,0 +1,32 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+language_tool_layer(
+    name = "go-ltl",
+    base = "@debian8//image",
+    env = {
+        "GOPATH": "/go",
+        "PATH": "$PATH:/usr/local/go/bin",
+    },
+    tars = ["//third_party/golang:tar"],
+)
diff --git a/container/debian8/layers/java/BUILD b/container/debian8/layers/java/BUILD
new file mode 100644
index 0000000..f564a16
--- /dev/null
+++ b/container/debian8/layers/java/BUILD
@@ -0,0 +1,49 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+JAVA_CLEANUP_COMMANDS = (
+    "rm -rf " +
+    "/etc/ssl/certs/java/cacerts " +
+    "/tmp/hsperfdata_root/* " +
+    "/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/classes.jsa"
+)
+
+language_tool_layer(
+    name = "java-ltl",
+    additional_repos = [
+        "deb http://deb.debian.org/debian jessie-backports main",
+    ],
+    base = "@debian8//image",
+    env = {
+        "JAVA_HOME": "/usr/lib/jvm/java-8-openjdk-amd64",
+    },
+    installation_cleanup_commands = JAVA_CLEANUP_COMMANDS,
+    packages = [
+        "ca-certificates-java=20161107'*'",
+        "openjdk-8-jdk-headless",
+        "openjdk-8-jre-headless",
+    ],
+    symlinks = {
+        "/usr/bin/java": "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java",
+    },
+)
diff --git a/container/debian8/layers/python/BUILD b/container/debian8/layers/python/BUILD
new file mode 100644
index 0000000..a4e5be7
--- /dev/null
+++ b/container/debian8/layers/python/BUILD
@@ -0,0 +1,48 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+PYTHON_CLEANUP_COMMANDS = (
+    "find /usr/lib/python* -name __pycache__ -exec rm -rf {} +"
+)
+
+language_tool_layer(
+    name = "python-ltl",
+    base = "@debian8//image",
+    env = {
+        "PATH": "$PATH:/opt/python3.6/bin",
+    },
+    installation_cleanup_commands = PYTHON_CLEANUP_COMMANDS,
+    packages = [
+        "python-dev",
+        "python-setuptools",
+        "python3-dev",
+    ],
+    symlinks = {
+        "/usr/bin/python": "/usr/bin/python2.7",
+        "/usr/bin/python3": "/opt/python3.6/bin/python3.6",
+        "/opt/python3.6/bin/python3": "/opt/python3.6/bin/python3.6",
+        "/opt/python3.6/bin/pip3": "/opt/python3.6/bin/pip3.6",
+        "/opt/python3.6/bin/easy_install3": "/opt/python3.6/bin/easy_install-3.6",
+    },
+    tars = ["//third_party/python:debian8_tar"],
+)
diff --git a/container/experimental/rbe-debian8/BUILD b/container/experimental/rbe-debian8/BUILD
index a40b912..635cacb 100644
--- a/container/experimental/rbe-debian8/BUILD
+++ b/container/experimental/rbe-debian8/BUILD
@@ -125,7 +125,15 @@
 
 container_test(
     name = "toolchain-test",
-    configs = ["//container/rbe-debian8:rbe-debian8.yaml"],
+    configs = [
+        "//container/common:clang.yaml",
+        "//container/common:go.yaml",
+        "//container/common:java.yaml",
+        "//container/common:python2.yaml",
+        "//container/common:rbe-base.yaml",
+        "//container/debian8:debian8.yaml",
+        "//container/debian8/builders/rbe-debian8:rbe-debian8.yaml",
+    ],
     image = ":toolchain",
     verbose = True,
 )
diff --git a/container/experimental/rbe-debian9/BUILD b/container/experimental/rbe-debian9/BUILD
index 0eaccb6..03e03d6 100644
--- a/container/experimental/rbe-debian9/BUILD
+++ b/container/experimental/rbe-debian9/BUILD
@@ -153,6 +153,11 @@
     name = "toolchain-test",
     configs = [
         ":rbe-debian9.yaml",
+        "//container/common:clang.yaml",
+        "//container/common:go.yaml",
+        "//container/common:java.yaml",
+        "//container/common:python2.yaml",
+        "//container/common:rbe-base.yaml",
     ],
     image = ":toolchain",
     verbose = True,
diff --git a/container/experimental/rbe-debian9/rbe-debian9.yaml b/container/experimental/rbe-debian9/rbe-debian9.yaml
index 291e8fc..ed66825 100644
--- a/container/experimental/rbe-debian9/rbe-debian9.yaml
+++ b/container/experimental/rbe-debian9/rbe-debian9.yaml
@@ -1,7 +1,6 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
 schemaVersion: "1.0.0"
 
-# TODO: split out the common tests once resolve the CI issues
-
 # Distro-specific tests
 commandTests:
 - name: 'os-version'
@@ -18,143 +17,6 @@
 - name: 'path-envvar'
   command: ['sh', '-c', 'echo $PATH']
   expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin']
-- name: 'check-locale'
-  command: ['sh', '-c', 'echo $LC_ALL']
-  expectedOutput: ['C.UTF-8']
-- name: 'cc-envvar'
-  command: ['sh', '-c', 'echo $CC']
-  expectedOutput: ['/usr/local/bin/clang']
-- name: 'javahome-envvar'
-  command: ['sh', '-c', 'echo $JAVA_HOME']
-  expectedOutput: ['/usr/lib/jvm/java-8-openjdk-amd64']
-- name: 'gopath-envvar'
-  command: ['sh', '-c', 'echo $GOPATH']
-  expectedOutput: ['/go']
-- name: 'clang-version'
-  command: ['bash', '-c', 'clang --version']
-  expectedOutput: ['clang version 7.0.0.*']
-- name: 'java-version'
-  command: ['bash', '-c', 'java -version 2>&1']
-  expectedOutput: ['openjdk version \"1.8.*']
-- name: 'python2-version'
-  command: ['bash', '-c', 'python -V 2>&1']
-  expectedOutput: ['Python 2.7.*']
 - name: 'python3-version'
   command: ['bash', '-c', 'python3 -V']
   expectedOutput: ['Python 3.6.*']
-- name: 'go-version'
-  command: ['bash', '-c', 'go version']
-  expectedOutput: ['go version go1.10 linux/amd64']
-# This test is failing. Disable if for now as debian9 is not released.
-#- name: 'check-curl'
-#  command: ['bash', '-c', 'curl --version']
-#  expectedOutput: ['curl .* \(x86_64-pc-linux-gnu\).*']
-- name: 'check-ed'
-  command: ['bash', '-c', 'ed --version']
-  expectedOutput: ['GNU [eE]d .*']
-- name: 'check-file'
-  command: ['bash', '-c', 'file --version']
-  expectedOutput: ['file-.*']
-- name: 'check-git'
-  command: ['bash', '-c', 'git --version']
-  expectedOutput: ['git version .*']
-- name: 'check-less'
-  command: ['bash', '-c', 'less --version']
-  expectedOutput: ['less .*']
-- name: 'check-netcat'
-  command: ['bash', '-c', 'nc -h 2>&1']
-  expectedOutput: ['\[v.*']
-- name: 'check-openssl'
-  command: ['bash', '-c', 'openssl version']
-  expectedOutput: ['OpenSSL .*']
-- name: 'check-patch'
-  command: ['bash', '-c', 'patch --version']
-  expectedOutput: ['GNU patch .*']
-- name: 'check-wget'
-  command: ['bash', '-c', 'wget --version']
-  expectedOutput: ['GNU Wget.* built on linux-gnu.*']
-- name: 'check-zip'
-  command: ['bash', '-c', 'zip --version']
-  expectedOutput: ['.*This is Zip.*']
-
-fileExistenceTests:
-- name: 'Root'
-  isDirectory: true
-  path: '/'
-  shouldExist: true
-- name: 'Clang'
-  isDirectory: false
-  path: '/usr/local/bin/clang'
-  shouldExist: true
-- name: 'libcxx-header'
-  isDirectory: true
-  path: '/usr/local/include/c++/v1'
-  shouldExist: true
-- name: 'libcxx-lib'
-  isDirectory: false
-  path: '/usr/local/lib/libc++.a'
-  shouldExist: true
-- name: 'OpenJDK'
-  isDirectory: true
-  path: '/usr/lib/jvm/java-8-openjdk-amd64'
-  shouldExist: true
-- name: 'Python2'
-  isDirectory: false
-  path: '/usr/bin/python2.7'
-  shouldExist: true
-- name: 'Golang'
-  isDirectory: false
-  path: '/usr/local/go/bin/go'
-  shouldExist: true
-- name: 'llvm-symbolizer'
-  isDirectory: false
-  path: '/usr/local/bin/llvm-symbolizer'
-  shouldExist: true
-- name: 'sanitizer'
-  isDirectory: true
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer'
-  shouldExist: true
-- name: 'sanitizer-allocator'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/allocator_interface.h'
-  shouldExist: true
-- name: 'sanitizer-asan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/asan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-common_defs'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/common_interface_defs.h'
-  shouldExist: true
-- name: 'sanitizer-coverage'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/coverage_interface.h'
-  shouldExist: true
-- name: 'sanitizer-dfsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/dfsan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-esan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/esan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-linux_syscall_hooks'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/linux_syscall_hooks.h'
-  shouldExist: true
-- name: 'sanitizer-lsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/lsan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-msan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/msan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-tsan_atomic'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface_atomic.h'
-  shouldExist: true
-- name: 'sanitizer-tsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface.h'
-  shouldExist: true
diff --git a/container/rbe-debian8/BUILD b/container/rbe-debian8/BUILD
deleted file mode 100644
index 1be1892..0000000
--- a/container/rbe-debian8/BUILD
+++ /dev/null
@@ -1,158 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-licenses(["notice"])  # Apache 2.0
-
-package(default_visibility = ["//visibility:public"])
-
-load(
-    "//container/rules:docker_toolchains.bzl",
-    "language_tool_layer",
-    "toolchain_container",
-)
-load("@io_bazel_rules_docker//contrib:test.bzl", "container_test")
-
-JAVA_CLEANUP_COMMANDS = (
-    "rm -rf " +
-    "/etc/ssl/certs/java/cacerts " +
-    "/tmp/hsperfdata_root/* " +
-    "/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/classes.jsa"
-)
-
-PYTHON_CLEANUP_COMMANDS = (
-    "find /usr/lib/python* -name __pycache__ -exec rm -rf {} +"
-)
-
-toolchain_container(
-    name = "toolchain",
-    base = "@debian8//image",
-    cmd = [
-        "/bin/sh",
-        "-c",
-        "/bin/bash",
-    ],
-    env = {
-        # PATH envvar is a special case, and currently only the one in the
-        # topmost layer is set. So that we override it here to include all.
-        "PATH": "$PATH:/opt/python3.6/bin:/usr/local/go/bin",
-        "LANG": "C.UTF-8",
-        "LANGUAGE": "C.UTF-8",
-        "LC_ALL": "C.UTF-8",
-    },
-    language_layers = [
-        "base-ltl",
-        "clang-ltl",
-        "go-ltl",
-        "java-ltl",
-        "python-ltl",
-    ],
-)
-
-language_tool_layer(
-    name = "base-ltl",
-    base = "@debian8//image",
-    packages = [
-        "binutils",
-        "ca-certificates",
-        "curl",
-        "ed",
-        "file",
-        "git",
-        "less",
-        "netcat",
-        "openssh-client",
-        "patch",
-        "unzip",
-        "wget",
-        "zip",
-    ],
-)
-
-language_tool_layer(
-    name = "clang-ltl",
-    base = "@debian8//image",
-    env = {
-        "CC": "/usr/local/bin/clang",
-        "ASAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
-        "MSAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
-    },
-    packages = [
-        "libstdc++-4.9-dev",
-    ],
-    tars = [
-        "//third_party/clang:debian8_tar",
-        "//third_party/libcxx:debian8_tar",
-    ],
-)
-
-language_tool_layer(
-    name = "go-ltl",
-    base = "@debian8//image",
-    env = {
-        "GOPATH": "/go",
-        "PATH": "$PATH:/usr/local/go/bin",
-    },
-    tars = ["//third_party/golang:tar"],
-)
-
-language_tool_layer(
-    name = "java-ltl",
-    additional_repos = [
-        "deb http://deb.debian.org/debian jessie-backports main",
-    ],
-    base = "@debian8//image",
-    env = {
-        "JAVA_HOME": "/usr/lib/jvm/java-8-openjdk-amd64",
-    },
-    installation_cleanup_commands = JAVA_CLEANUP_COMMANDS,
-    packages = [
-        "ca-certificates-java=20161107'*'",
-        "openjdk-8-jdk-headless",
-        "openjdk-8-jre-headless",
-    ],
-    symlinks = {
-        "/usr/bin/java": "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java",
-    },
-)
-
-language_tool_layer(
-    name = "python-ltl",
-    base = "@debian8//image",
-    env = {
-        "PATH": "$PATH:/opt/python3.6/bin",
-    },
-    installation_cleanup_commands = PYTHON_CLEANUP_COMMANDS,
-    packages = [
-        "python-dev",
-        "python-setuptools",
-        "python3-dev",
-    ],
-    symlinks = {
-        "/usr/bin/python": "/usr/bin/python2.7",
-        "/usr/bin/python3": "/opt/python3.6/bin/python3.6",
-        "/opt/python3.6/bin/python3": "/opt/python3.6/bin/python3.6",
-        "/opt/python3.6/bin/pip3": "/opt/python3.6/bin/pip3.6",
-        "/opt/python3.6/bin/easy_install3": "/opt/python3.6/bin/easy_install-3.6",
-    },
-    tars = ["//third_party/python:debian8_tar"],
-)
-
-container_test(
-    name = "toolchain-test",
-    configs = [
-        ":rbe-debian8.yaml",
-    ],
-    image = ":toolchain",
-    verbose = True,
-)
diff --git a/container/rbe-debian8/rbe-debian8.yaml b/container/rbe-debian8/rbe-debian8.yaml
deleted file mode 100644
index 7412c29..0000000
--- a/container/rbe-debian8/rbe-debian8.yaml
+++ /dev/null
@@ -1,159 +0,0 @@
-schemaVersion: "1.0.0"
-
-# TODO: split out the common tests once resolve the CI issues
-
-# Distro-specific tests
-commandTests:
-- name: 'os-version'
-  command: ['sh', '-c', 'cat /etc/issue.net']
-  expectedOutput: ['Debian GNU/Linux 8']
-fileExistenceTests:
-- name: 'Python3'
-  isDirectory: false
-  path: '/opt/python3.6/bin/python3'
-  shouldExist: true
-
-# Common tests
-commandTests:
-- name: 'path-envvar'
-  command: ['sh', '-c', 'echo $PATH']
-  expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/python3.6/bin:/usr/local/go/bin']
-- name: 'check-locale'
-  command: ['sh', '-c', 'echo $LC_ALL']
-  expectedOutput: ['C.UTF-8']
-- name: 'cc-envvar'
-  command: ['sh', '-c', 'echo $CC']
-  expectedOutput: ['/usr/local/bin/clang']
-- name: 'javahome-envvar'
-  command: ['sh', '-c', 'echo $JAVA_HOME']
-  expectedOutput: ['/usr/lib/jvm/java-8-openjdk-amd64']
-- name: 'gopath-envvar'
-  command: ['sh', '-c', 'echo $GOPATH']
-  expectedOutput: ['/go']
-- name: 'clang-version'
-  command: ['bash', '-c', 'clang --version']
-  expectedOutput: ['clang version 7.0.0.*']
-- name: 'java-version'
-  command: ['bash', '-c', 'java -version 2>&1']
-  expectedOutput: ['openjdk version \"1.8.*']
-- name: 'python2-version'
-  command: ['bash', '-c', 'python -V 2>&1']
-  expectedOutput: ['Python 2.7.*']
-- name: 'python3-version'
-  command: ['bash', '-c', 'python3 -V']
-  expectedOutput: ['Python 3.6.*']
-- name: 'go-version'
-  command: ['bash', '-c', 'go version']
-  expectedOutput: ['go version go1.10 linux/amd64']
-- name: 'check-curl'
-  command: ['bash', '-c', 'curl --version']
-  expectedOutput: ['curl .* \(x86_64-pc-linux-gnu\).*']
-- name: 'check-ed'
-  command: ['bash', '-c', 'ed --version']
-  expectedOutput: ['GNU [eE]d .*']
-- name: 'check-file'
-  command: ['bash', '-c', 'file --version']
-  expectedOutput: ['file-.*']
-- name: 'check-git'
-  command: ['bash', '-c', 'git --version']
-  expectedOutput: ['git version .*']
-- name: 'check-less'
-  command: ['bash', '-c', 'less --version']
-  expectedOutput: ['less .*']
-- name: 'check-netcat'
-  command: ['bash', '-c', 'nc -h 2>&1']
-  expectedOutput: ['\[v.*']
-- name: 'check-openssl'
-  command: ['bash', '-c', 'openssl version']
-  expectedOutput: ['OpenSSL .*']
-- name: 'check-patch'
-  command: ['bash', '-c', 'patch --version']
-  expectedOutput: ['GNU patch .*']
-- name: 'check-wget'
-  command: ['bash', '-c', 'wget --version']
-  expectedOutput: ['GNU Wget.* built on linux-gnu.*']
-- name: 'check-zip'
-  command: ['bash', '-c', 'zip --version']
-  expectedOutput: ['.*This is Zip.*']
-
-fileExistenceTests:
-- name: 'Root'
-  isDirectory: true
-  path: '/'
-  shouldExist: true
-- name: 'Clang'
-  isDirectory: false
-  path: '/usr/local/bin/clang'
-  shouldExist: true
-- name: 'libcxx-header'
-  isDirectory: true
-  path: '/usr/local/include/c++/v1'
-  shouldExist: true
-- name: 'libcxx-lib'
-  isDirectory: false
-  path: '/usr/local/lib/libc++.a'
-  shouldExist: true
-- name: 'OpenJDK'
-  isDirectory: true
-  path: '/usr/lib/jvm/java-8-openjdk-amd64'
-  shouldExist: true
-- name: 'Python2'
-  isDirectory: false
-  path: '/usr/bin/python2.7'
-  shouldExist: true
-- name: 'Golang'
-  isDirectory: false
-  path: '/usr/local/go/bin/go'
-  shouldExist: true
-- name: 'llvm-symbolizer'
-  isDirectory: false
-  path: '/usr/local/bin/llvm-symbolizer'
-  shouldExist: true
-- name: 'sanitizer'
-  isDirectory: true
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer'
-  shouldExist: true
-- name: 'sanitizer-allocator'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/allocator_interface.h'
-  shouldExist: true
-- name: 'sanitizer-asan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/asan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-common_defs'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/common_interface_defs.h'
-  shouldExist: true
-- name: 'sanitizer-coverage'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/coverage_interface.h'
-  shouldExist: true
-- name: 'sanitizer-dfsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/dfsan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-esan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/esan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-linux_syscall_hooks'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/linux_syscall_hooks.h'
-  shouldExist: true
-- name: 'sanitizer-lsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/lsan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-msan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/msan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-tsan_atomic'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface_atomic.h'
-  shouldExist: true
-- name: 'sanitizer-tsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface.h'
-  shouldExist: true
diff --git a/container/rbe-ubuntu16_04/BUILD b/container/rbe-ubuntu16_04/BUILD
deleted file mode 100644
index fbdafba..0000000
--- a/container/rbe-ubuntu16_04/BUILD
+++ /dev/null
@@ -1,157 +0,0 @@
-# Copyright 2017 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-licenses(["notice"])  # Apache 2.0
-
-package(default_visibility = ["//visibility:public"])
-
-load(
-    "//container/rules:docker_toolchains.bzl",
-    "language_tool_layer",
-    "toolchain_container",
-)
-load("@io_bazel_rules_docker//contrib:test.bzl", "container_test")
-
-JAVA_CLEANUP_COMMANDS = (
-    "rm -rf " +
-    "/etc/ssl/certs/java/cacerts " +
-    "/tmp/hsperfdata_root/* " +
-    "/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/classes.jsa"
-)
-
-PYTHON_CLEANUP_COMMANDS = (
-    "find /usr/lib/python* -name __pycache__ -exec rm -rf {} +"
-)
-
-toolchain_container(
-    name = "toolchain",
-    base = "@ubuntu16_04//image",
-    cmd = [
-        "/bin/sh",
-        "-c",
-        "/bin/bash",
-    ],
-    env = {
-        # PATH envvar is a special case, and currently only the one in the
-        # topmost layer is set. So that we override it here to include all.
-        "PATH": "$PATH:/opt/python3.6/bin:/usr/local/go/bin",
-        "LANG": "C.UTF-8",
-        "LANGUAGE": "C.UTF-8",
-        "LC_ALL": "C.UTF-8",
-    },
-    language_layers = [
-        "base-ltl",
-        "clang-ltl",
-        "go-ltl",
-        "java-ltl",
-        "python-ltl",
-    ],
-)
-
-language_tool_layer(
-    name = "base-ltl",
-    base = "@ubuntu16_04//image",
-    packages = [
-        "binutils",
-        "ca-certificates",
-        "curl",
-        "ed",
-        "file",
-        "git",
-        "less",
-        "locales",
-        "locales-all",
-        "netcat",
-        "openssh-client",
-        "patch",
-        "unzip",
-        "wget",
-        "zip",
-    ],
-)
-
-language_tool_layer(
-    name = "clang-ltl",
-    base = "@ubuntu16_04//image",
-    env = {
-        "CC": "/usr/local/bin/clang",
-        "ASAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
-        "MSAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
-    },
-    packages = [
-        "libstdc++-4.9-dev",
-    ],
-    tars = [
-        "//third_party/clang:ubuntu16_04_tar",
-        "//third_party/libcxx:ubuntu16_04_tar",
-    ],
-)
-
-language_tool_layer(
-    name = "go-ltl",
-    base = "@ubuntu16_04//image",
-    env = {
-        "GOPATH": "/go",
-        "PATH": "$PATH:/usr/local/go/bin",
-    },
-    tars = ["//third_party/golang:tar"],
-)
-
-language_tool_layer(
-    name = "java-ltl",
-    base = "@ubuntu16_04//image",
-    env = {
-        "JAVA_HOME": "/usr/lib/jvm/java-8-openjdk-amd64",
-    },
-    installation_cleanup_commands = JAVA_CLEANUP_COMMANDS,
-    packages = [
-        "ca-certificates-java",
-        "openjdk-8-jdk-headless",
-        "openjdk-8-jre-headless",
-    ],
-    symlinks = {
-        "/usr/bin/java": "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java",
-    },
-)
-
-language_tool_layer(
-    name = "python-ltl",
-    base = "@ubuntu16_04//image",
-    env = {
-        "PATH": "$PATH:/opt/python3.6/bin",
-    },
-    installation_cleanup_commands = PYTHON_CLEANUP_COMMANDS,
-    packages = [
-        "python-dev",
-        "python-setuptools",
-        "python3-dev",
-    ],
-    symlinks = {
-        "/usr/bin/python": "/usr/bin/python2.7",
-        "/usr/bin/python3": "/opt/python3.6/bin/python3.6",
-        "/opt/python3.6/bin/python3": "/opt/python3.6/bin/python3.6",
-        "/opt/python3.6/bin/pip3": "/opt/python3.6/bin/pip3.6",
-        "/opt/python3.6/bin/easy_install3": "/opt/python3.6/bin/easy_install-3.6",
-    },
-    tars = ["//third_party/python:ubuntu16_04_tar"],
-)
-
-container_test(
-    name = "toolchain-test",
-    configs = [
-        ":rbe-ubuntu16_04.yaml",
-    ],
-    image = ":toolchain",
-    verbose = True,
-)
diff --git a/container/rbe-ubuntu16_04/rbe-ubuntu16_04.yaml b/container/rbe-ubuntu16_04/rbe-ubuntu16_04.yaml
deleted file mode 100644
index b8b9e0b..0000000
--- a/container/rbe-ubuntu16_04/rbe-ubuntu16_04.yaml
+++ /dev/null
@@ -1,159 +0,0 @@
-schemaVersion: "1.0.0"
-
-# TODO: split out the common tests once resolve the CI issues
-
-# Distro-specific tests
-commandTests:
-- name: 'os-version'
-  command: ['sh', '-c', 'cat /etc/issue.net']
-  expectedOutput: ['Ubuntu 16.04.3 LTS']
-fileExistenceTests:
-- name: 'Python3'
-  isDirectory: false
-  path: '/opt/python3.6/bin/python3'
-  shouldExist: true
-
-# Common tests
-commandTests:
-- name: 'path-envvar'
-  command: ['sh', '-c', 'echo $PATH']
-  expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/python3.6/bin:/usr/local/go/bin']
-- name: 'check-locale'
-  command: ['sh', '-c', 'echo $LC_ALL']
-  expectedOutput: ['C.UTF-8']
-- name: 'cc-envvar'
-  command: ['sh', '-c', 'echo $CC']
-  expectedOutput: ['/usr/local/bin/clang']
-- name: 'javahome-envvar'
-  command: ['sh', '-c', 'echo $JAVA_HOME']
-  expectedOutput: ['/usr/lib/jvm/java-8-openjdk-amd64']
-- name: 'gopath-envvar'
-  command: ['sh', '-c', 'echo $GOPATH']
-  expectedOutput: ['/go']
-- name: 'clang-version'
-  command: ['bash', '-c', 'clang --version']
-  expectedOutput: ['clang version 7.0.0.*']
-- name: 'java-version'
-  command: ['bash', '-c', 'java -version 2>&1']
-  expectedOutput: ['openjdk version \"1.8.*']
-- name: 'python2-version'
-  command: ['bash', '-c', 'python -V 2>&1']
-  expectedOutput: ['Python 2.7.*']
-- name: 'python3-version'
-  command: ['bash', '-c', 'python3 -V']
-  expectedOutput: ['Python 3.6.*']
-- name: 'go-version'
-  command: ['bash', '-c', 'go version']
-  expectedOutput: ['go version go1.10 linux/amd64']
-- name: 'check-curl'
-  command: ['bash', '-c', 'curl --version']
-  expectedOutput: ['curl .* \(x86_64-pc-linux-gnu\).*']
-- name: 'check-ed'
-  command: ['bash', '-c', 'ed --version']
-  expectedOutput: ['GNU [eE]d .*']
-- name: 'check-file'
-  command: ['bash', '-c', 'file --version']
-  expectedOutput: ['file-.*']
-- name: 'check-git'
-  command: ['bash', '-c', 'git --version']
-  expectedOutput: ['git version .*']
-- name: 'check-less'
-  command: ['bash', '-c', 'less --version']
-  expectedOutput: ['less .*']
-- name: 'check-netcat'
-  command: ['bash', '-c', 'nc -h 2>&1']
-  expectedOutput: ['\[v.*']
-- name: 'check-openssl'
-  command: ['bash', '-c', 'openssl version']
-  expectedOutput: ['OpenSSL .*']
-- name: 'check-patch'
-  command: ['bash', '-c', 'patch --version']
-  expectedOutput: ['GNU patch .*']
-- name: 'check-wget'
-  command: ['bash', '-c', 'wget --version']
-  expectedOutput: ['GNU Wget.* built on linux-gnu.*']
-- name: 'check-zip'
-  command: ['bash', '-c', 'zip --version']
-  expectedOutput: ['.*This is Zip.*']
-
-fileExistenceTests:
-- name: 'Root'
-  isDirectory: true
-  path: '/'
-  shouldExist: true
-- name: 'Clang'
-  isDirectory: false
-  path: '/usr/local/bin/clang'
-  shouldExist: true
-- name: 'libcxx-header'
-  isDirectory: true
-  path: '/usr/local/include/c++/v1'
-  shouldExist: true
-- name: 'libcxx-lib'
-  isDirectory: false
-  path: '/usr/local/lib/libc++.a'
-  shouldExist: true
-- name: 'OpenJDK'
-  isDirectory: true
-  path: '/usr/lib/jvm/java-8-openjdk-amd64'
-  shouldExist: true
-- name: 'Python2'
-  isDirectory: false
-  path: '/usr/bin/python2.7'
-  shouldExist: true
-- name: 'Golang'
-  isDirectory: false
-  path: '/usr/local/go/bin/go'
-  shouldExist: true
-- name: 'llvm-symbolizer'
-  isDirectory: false
-  path: '/usr/local/bin/llvm-symbolizer'
-  shouldExist: true
-- name: 'sanitizer'
-  isDirectory: true
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer'
-  shouldExist: true
-- name: 'sanitizer-allocator'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/allocator_interface.h'
-  shouldExist: true
-- name: 'sanitizer-asan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/asan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-common_defs'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/common_interface_defs.h'
-  shouldExist: true
-- name: 'sanitizer-coverage'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/coverage_interface.h'
-  shouldExist: true
-- name: 'sanitizer-dfsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/dfsan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-esan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/esan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-linux_syscall_hooks'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/linux_syscall_hooks.h'
-  shouldExist: true
-- name: 'sanitizer-lsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/lsan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-msan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/msan_interface.h'
-  shouldExist: true
-- name: 'sanitizer-tsan_atomic'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface_atomic.h'
-  shouldExist: true
-- name: 'sanitizer-tsan'
-  isDirectory: false
-  path: '/usr/local/lib/clang/7.0.0/include/sanitizer/tsan_interface.h'
-  shouldExist: true
diff --git a/container/ubuntu16_04/BUILD b/container/ubuntu16_04/BUILD
new file mode 100644
index 0000000..8ece167
--- /dev/null
+++ b/container/ubuntu16_04/BUILD
@@ -0,0 +1,19 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+exports_files(glob(["*.yaml"]))
diff --git a/container/ubuntu16_04/builders/bazel/BUILD b/container/ubuntu16_04/builders/bazel/BUILD
index 7d292b4..5981d30 100644
--- a/container/ubuntu16_04/builders/bazel/BUILD
+++ b/container/ubuntu16_04/builders/bazel/BUILD
@@ -32,8 +32,8 @@
     # reproduction.
     installation_cleanup_commands = "update-ca-certificates -f",
     language_layers = [
-        "//container/rbe-ubuntu16_04:java-ltl",
-        "//container/rbe-ubuntu16_04:python-ltl",
+        "//container/ubuntu16_04/layers/java:java-ltl",
+        "//container/ubuntu16_04/layers/python:python-ltl",
         "//container/ubuntu16_04/layers/bazel:bazel-tools",
         "//container/ubuntu16_04/layers/bazel:bazel-ltl",
         "//container/ubuntu16_04/layers/git:git-ltl",
@@ -52,6 +52,9 @@
     name = "bazel-test",
     configs = [
         ":container.yaml",
+        "//container/common:java.yaml",
+        "//container/common:python2.yaml",
+        "//container/ubuntu16_04:ubuntu16_04.yaml",
         "//container/ubuntu16_04/layers/bazel:bazel.yaml",
         "//container/ubuntu16_04/layers/git:git.yaml",
     ],
@@ -80,6 +83,9 @@
     name = "bazel_docker-test",
     configs = [
         ":container.yaml",
+        "//container/common:java.yaml",
+        "//container/common:python2.yaml",
+        "//container/ubuntu16_04:ubuntu16_04.yaml",
         "//container/ubuntu16_04/layers/bazel:bazel.yaml",
         "//container/ubuntu16_04/layers/docker-17.12.0:docker-17.12.0.yaml",
         "//container/ubuntu16_04/layers/git:git.yaml",
diff --git a/container/ubuntu16_04/builders/bazel/container.yaml b/container/ubuntu16_04/builders/bazel/container.yaml
index 66308b6..6100f3c 100644
--- a/container/ubuntu16_04/builders/bazel/container.yaml
+++ b/container/ubuntu16_04/builders/bazel/container.yaml
@@ -1,25 +1,11 @@
 # TODO(xingao) Update to 2.0.0 to enable metadataTest.
 schemaVersion: "1.0.0"
 
-# TODO: split out the common tests once resolve the CI issues
-
-# Distro-specific tests
-commandTests:
-- name: 'os-version'
-  command: ['sh', '-c', 'cat /etc/issue.net']
-  expectedOutput: ['Ubuntu 16.04.3 LTS']
-
 # Common tests
 commandTests:
 - name: 'path-envvar'
   command: ['sh', '-c', 'echo $PATH']
   expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin']
-- name: 'javahome-envvar'
-  command: ['sh', '-c', 'echo $JAVA_HOME']
-  expectedOutput: ['/usr/lib/jvm/java-8-openjdk-amd64']
-- name: 'java-version'
-  command: ['bash', '-c', 'java -version 2>&1']
-  expectedOutput: ['openjdk version \"1.8.*']
 - name: 'gcc-version'
   command: ['bash', '-c', 'gcc --version 2>&1']
   expectedOutput: ['gcc .*']
@@ -33,12 +19,6 @@
   command: ['bash', '-c', 'zip --version']
   expectedOutput: ['.*This is Zip.*']
 
-# File existence tests
-fileExistenceTests:
-- name: 'OpenJDK'
-  isDirectory: true
-  path: '/usr/lib/jvm/java-8-openjdk-amd64'
-  shouldExist: true
 
 # TODO(xingao) Test entry point once rules_docker is updated with latest
 # version of the structure_test
diff --git a/container/ubuntu16_04/builders/rbe-ubuntu16_04/BUILD b/container/ubuntu16_04/builders/rbe-ubuntu16_04/BUILD
new file mode 100644
index 0000000..29c6f6e
--- /dev/null
+++ b/container/ubuntu16_04/builders/rbe-ubuntu16_04/BUILD
@@ -0,0 +1,86 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+    "toolchain_container",
+)
+load("@io_bazel_rules_docker//contrib:test.bzl", "container_test")
+
+language_tool_layer(
+    name = "base-ltl",
+    base = "@ubuntu16_04//image",
+    packages = [
+        "binutils",
+        "ca-certificates",
+        "curl",
+        "ed",
+        "file",
+        "git",
+        "less",
+        "locales",
+        "locales-all",
+        "netcat",
+        "openssh-client",
+        "patch",
+        "unzip",
+        "wget",
+        "zip",
+    ],
+)
+
+toolchain_container(
+    name = "toolchain",
+    base = "@ubuntu16_04//image",
+    cmd = [
+        "/bin/sh",
+        "-c",
+        "/bin/bash",
+    ],
+    env = {
+        # PATH envvar is a special case, and currently only the one in the
+        # topmost layer is set. So that we override it here to include all.
+        "PATH": "$PATH:/opt/python3.6/bin:/usr/local/go/bin",
+        "LANG": "C.UTF-8",
+        "LANGUAGE": "C.UTF-8",
+        "LC_ALL": "C.UTF-8",
+    },
+    language_layers = [
+        "base-ltl",
+        "//container/ubuntu16_04/layers/clang:clang-ltl",
+        "//container/ubuntu16_04/layers/go:go-ltl",
+        "//container/ubuntu16_04/layers/java:java-ltl",
+        "//container/ubuntu16_04/layers/python:python-ltl",
+    ],
+)
+
+container_test(
+    name = "toolchain-test",
+    configs = [
+        ":rbe-ubuntu16_04.yaml",
+        "//container/common:clang.yaml",
+        "//container/common:go.yaml",
+        "//container/common:java.yaml",
+        "//container/common:python2.yaml",
+        "//container/common:rbe-base.yaml",
+        "//container/ubuntu16_04:ubuntu16_04.yaml",
+    ],
+    image = ":toolchain",
+    verbose = True,
+)
diff --git a/container/ubuntu16_04/builders/rbe-ubuntu16_04/rbe-ubuntu16_04.yaml b/container/ubuntu16_04/builders/rbe-ubuntu16_04/rbe-ubuntu16_04.yaml
new file mode 100644
index 0000000..77c7238
--- /dev/null
+++ b/container/ubuntu16_04/builders/rbe-ubuntu16_04/rbe-ubuntu16_04.yaml
@@ -0,0 +1,22 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+fileExistenceTests:
+- name: 'Python3'
+  isDirectory: false
+  path: '/opt/python3.6/bin/python3'
+  shouldExist: true
+
+# Common tests
+commandTests:
+- name: 'path-envvar'
+  command: ['sh', '-c', 'echo $PATH']
+  expectedOutput: ['/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/python3.6/bin:/usr/local/go/bin']
+- name: 'python3-version'
+  command: ['bash', '-c', 'python3 -V']
+  expectedOutput: ['Python 3.6.*']
+# This is failing in Debian9 base. Once resolved, move this test to
+# container/common/rbe-base.yaml.
+- name: 'check-curl'
+  command: ['bash', '-c', 'curl --version']
+  expectedOutput: ['curl .* \(x86_64-pc-linux-gnu\).*']
diff --git a/container/ubuntu16_04/layers/clang/BUILD b/container/ubuntu16_04/layers/clang/BUILD
new file mode 100644
index 0000000..819dc3a
--- /dev/null
+++ b/container/ubuntu16_04/layers/clang/BUILD
@@ -0,0 +1,39 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+language_tool_layer(
+    name = "clang-ltl",
+    base = "@ubuntu16_04//image",
+    env = {
+        "CC": "/usr/local/bin/clang",
+        "ASAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
+        "MSAN_SYMBOLIZER_PATH": "/usr/local/bin/llvm-symbolizer",
+    },
+    packages = [
+        "libstdc++-4.9-dev",
+    ],
+    tars = [
+        "//third_party/clang:ubuntu16_04_tar",
+        "//third_party/libcxx:ubuntu16_04_tar",
+    ],
+)
diff --git a/container/ubuntu16_04/layers/go/BUILD b/container/ubuntu16_04/layers/go/BUILD
new file mode 100644
index 0000000..fb5ce2e
--- /dev/null
+++ b/container/ubuntu16_04/layers/go/BUILD
@@ -0,0 +1,32 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+language_tool_layer(
+    name = "go-ltl",
+    base = "@ubuntu16_04//image",
+    env = {
+        "GOPATH": "/go",
+        "PATH": "$PATH:/usr/local/go/bin",
+    },
+    tars = ["//third_party/golang:tar"],
+)
diff --git a/container/ubuntu16_04/layers/java/BUILD b/container/ubuntu16_04/layers/java/BUILD
new file mode 100644
index 0000000..f6435a4
--- /dev/null
+++ b/container/ubuntu16_04/layers/java/BUILD
@@ -0,0 +1,46 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+JAVA_CLEANUP_COMMANDS = (
+    "rm -rf " +
+    "/etc/ssl/certs/java/cacerts " +
+    "/tmp/hsperfdata_root/* " +
+    "/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/classes.jsa"
+)
+
+language_tool_layer(
+    name = "java-ltl",
+    base = "@ubuntu16_04//image",
+    env = {
+        "JAVA_HOME": "/usr/lib/jvm/java-8-openjdk-amd64",
+    },
+    installation_cleanup_commands = JAVA_CLEANUP_COMMANDS,
+    packages = [
+        "ca-certificates-java",
+        "openjdk-8-jdk-headless",
+        "openjdk-8-jre-headless",
+    ],
+    symlinks = {
+        "/usr/bin/java": "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java",
+    },
+)
diff --git a/container/ubuntu16_04/layers/python/BUILD b/container/ubuntu16_04/layers/python/BUILD
new file mode 100644
index 0000000..f34543a
--- /dev/null
+++ b/container/ubuntu16_04/layers/python/BUILD
@@ -0,0 +1,48 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+licenses(["notice"])  # Apache 2.0
+
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "//container/rules:docker_toolchains.bzl",
+    "language_tool_layer",
+)
+
+PYTHON_CLEANUP_COMMANDS = (
+    "find /usr/lib/python* -name __pycache__ -exec rm -rf {} +"
+)
+
+language_tool_layer(
+    name = "python-ltl",
+    base = "@ubuntu16_04//image",
+    env = {
+        "PATH": "$PATH:/opt/python3.6/bin",
+    },
+    installation_cleanup_commands = PYTHON_CLEANUP_COMMANDS,
+    packages = [
+        "python-dev",
+        "python-setuptools",
+        "python3-dev",
+    ],
+    symlinks = {
+        "/usr/bin/python": "/usr/bin/python2.7",
+        "/usr/bin/python3": "/opt/python3.6/bin/python3.6",
+        "/opt/python3.6/bin/python3": "/opt/python3.6/bin/python3.6",
+        "/opt/python3.6/bin/pip3": "/opt/python3.6/bin/pip3.6",
+        "/opt/python3.6/bin/easy_install3": "/opt/python3.6/bin/easy_install-3.6",
+    },
+    tars = ["//third_party/python:ubuntu16_04_tar"],
+)
diff --git a/container/ubuntu16_04/ubuntu16_04.yaml b/container/ubuntu16_04/ubuntu16_04.yaml
new file mode 100644
index 0000000..880170e
--- /dev/null
+++ b/container/ubuntu16_04/ubuntu16_04.yaml
@@ -0,0 +1,8 @@
+# TODO(xingao) Update to 2.0.0 to enable metadataTest.
+schemaVersion: "1.0.0"
+
+# Distro-specific tests
+commandTests:
+- name: 'os-version'
+  command: ['sh', '-c', 'cat /etc/issue.net']
+  expectedOutput: ['Ubuntu 16.04.4 LTS']