feat: upgrade Kubernetes to v1.16.0

Brings in Kubernetes v1.16.0.

Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
Andrew Rynhard 2019-09-20 02:57:56 +00:00
parent 9230ff4e35
commit 82c706a0fb
12 changed files with 59 additions and 57 deletions

View File

@ -221,7 +221,7 @@ COPY --from=docker.io/autonomy/runc:c79f79d / /rootfs
COPY --from=docker.io/autonomy/socat:032c783 / /rootfs
COPY --from=docker.io/autonomy/syslinux:85e1f9c / /rootfs
COPY --from=docker.io/autonomy/xfsprogs:5e50579 / /rootfs
COPY --from=docker.io/autonomy/kubeadm:3d99a76 / /rootfs
COPY --from=docker.io/autonomy/kubeadm:00495d0 / /rootfs
COPY --from=docker.io/autonomy/crictl:ddbeea1 / /rootfs
COPY --from=docker.io/autonomy/base:f9a4941 /toolchain/lib/libblkid.* /rootfs/lib
COPY --from=docker.io/autonomy/base:f9a4941 /toolchain/lib/libuuid.* /rootfs/lib

View File

@ -2,7 +2,7 @@ TOOLS ?= autonomy/tools:a9fa749
# TODO(andrewrynhard): Move this logic to a shell script.
BUILDKIT_VERSION ?= v0.6.0
KUBECTL_VERSION ?= v1.16.0-rc.2
KUBECTL_VERSION ?= v1.16.0
GO_VERSION ?= 1.12
BUILDKIT_IMAGE ?= moby/buildkit:$(BUILDKIT_VERSION)
BUILDKIT_HOST ?= tcp://0.0.0.0:1234

38
go.mod
View File

@ -80,34 +80,34 @@ require (
k8s.io/cri-api v0.0.0
k8s.io/kube-proxy v0.0.0
k8s.io/kubelet v0.0.0
k8s.io/kubernetes v1.16.0-rc.2
k8s.io/kubernetes v1.16.0
k8s.io/utils v0.0.0 // indirect
)
replace (
github.com/docker/distribution v2.7.1+incompatible => github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
github.com/opencontainers/runtime-spec v1.0.1 => github.com/opencontainers/runtime-spec v0.1.2-0.20180301181910-fa4b36aa9c99
k8s.io/api => k8s.io/api v0.0.0-20190913200010-d2ab659560cb
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190913202221-52e3edd98126
k8s.io/api => k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
k8s.io/apiserver => k8s.io/apiserver v0.0.0-20190913201147-5669a5603d96
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20190913202555-48793e229f24
k8s.io/client-go => k8s.io/client-go v0.0.0-20190913200447-5ff489491ea7
k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20190913203700-32e6ab0de2a2
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.0.0-20190913203524-c351f77e9a62
k8s.io/apiserver => k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20190918162238-f783a3654da8
k8s.io/client-go => k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90
k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20190918163234-a9c1f33e9fb9
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.0.0-20190918163108-da9fdfce26bb
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269
k8s.io/component-base => k8s.io/component-base v0.0.0-20190913200627-c1db07a83ddd
k8s.io/component-base => k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090
k8s.io/cri-api => k8s.io/cri-api v0.0.0-20190828162817-608eb1dad4ac
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.0.0-20190913203836-0443d78e4a59
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.0.0-20190918163402-db86a8c7bb21
k8s.io/klog => k8s.io/klog v0.3.1
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.0.0-20190913201430-06145edbcf86
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.0.0-20190913203351-7116f89e0eb2
k8s.io/kube-proxy => k8s.io/kube-proxy v0.0.0-20190913202909-61cd20ae3d92
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.0.0-20190913203215-88ce8cca4f54
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20190913204531-26d9723e03ae
k8s.io/kubelet => k8s.io/kubelet v0.0.0-20190913203039-8a485d6b870b
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.0.0-20190913204022-a09231045882
k8s.io/metrics => k8s.io/metrics v0.0.0-20190913202417-f6bee5ba35c7
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.0.0-20190913201707-470afe49ddf4
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.0.0-20190918161219-8c8f079fddc3
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.0.0-20190918162944-7a93a0ddadd8
k8s.io/kube-proxy => k8s.io/kube-proxy v0.0.0-20190918162534-de037b596c1e
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.0.0-20190918162820-3b5c1246eb18
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20190918164019-21692a0861df
k8s.io/kubelet => k8s.io/kubelet v0.0.0-20190918162654-250a1838aa2c
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.0.0-20190918163543-cfa506e53441
k8s.io/metrics => k8s.io/metrics v0.0.0-20190918162108-227c654b2546
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.0.0-20190918161442-d4c9c65c82af
k8s.io/utils => k8s.io/utils v0.0.0-20190801114015-581e00157fb1
)

56
go.sum
View File

@ -670,47 +670,47 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.0.0-20190913200010-d2ab659560cb h1:T3NLWI3mZkWRuDmujwGRPMsqZx1dRUBr0h+B7FECKdI=
k8s.io/api v0.0.0-20190913200010-d2ab659560cb/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48=
k8s.io/apiextensions-apiserver v0.0.0-20190913202221-52e3edd98126 h1:IU8J/xF+vw6/KEeLdgDVKG8jP3IZV2v6fMJf3K8fLDA=
k8s.io/apiextensions-apiserver v0.0.0-20190913202221-52e3edd98126/go.mod h1:hdJ+BtYqBqtWnXDjvh6p6S7NUKXQCnKWAXzaZD3Wbe8=
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f h1:8FRUST8oUkEI45WYKyD8ed7Ad0Kg5v11zHyPkEVb2xo=
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48=
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783 h1:V6ndwCPoao1yZ52agqOKaUAl7DYWVGiXjV7ePA2i610=
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY=
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 h1:CS1tBQz3HOXiseWZu6ZicKX361CZLT97UFnnPx0aqBw=
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
k8s.io/apiserver v0.0.0-20190913201147-5669a5603d96 h1:YZDJpZpSKuskfd7Mk0p3mB8bAdTcCyJtVBYYUYUuCi0=
k8s.io/apiserver v0.0.0-20190913201147-5669a5603d96/go.mod h1:COzdxwLiqIvEtImDywCC366TCOXiR23Rsru40DaTMhg=
k8s.io/cli-runtime v0.0.0-20190913202555-48793e229f24/go.mod h1:2b7pxOYAyu/On/yjcafOalwxjlpDEszJocDGFgLe3Ic=
k8s.io/client-go v0.0.0-20190913200447-5ff489491ea7 h1:KMJ79KgJ8CkPNrooJ+8paEgTFRFJTmKJlf5xr43Mcxg=
k8s.io/client-go v0.0.0-20190913200447-5ff489491ea7/go.mod h1:QhAAWWkFJ7tfWS6zIuCzN/fRVtiIIodvoWKj+UNCGNg=
k8s.io/cloud-provider v0.0.0-20190913203700-32e6ab0de2a2/go.mod h1:VTHFJxDIoZTPYczD7a0nbP3b7NM57LK4f3tMXdZK9v4=
k8s.io/cluster-bootstrap v0.0.0-20190913203524-c351f77e9a62 h1:vLCCjjURzvcTOE1vWKbWYvPnzWF2a45L6e2drCP7Ltw=
k8s.io/cluster-bootstrap v0.0.0-20190913203524-c351f77e9a62/go.mod h1:KJ0ECIB2aWUbSiABU/Qtzzpy7NK3tMWiegPaHzQG5hw=
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad h1:IMoNR9pilTBaCS5WpwWnAdmoVYVeXowOD3bLrwxIAtQ=
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg=
k8s.io/cli-runtime v0.0.0-20190918162238-f783a3654da8/go.mod h1:WRliO+M6Osz7/zdOF0RI42IsJgSYHUwbLgqAWJPneSs=
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 h1:mLmhKUm1X+pXu0zXMEzNsOF5E2kKFGe5o6BZBIIqA6A=
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk=
k8s.io/cloud-provider v0.0.0-20190918163234-a9c1f33e9fb9/go.mod h1:YfUBehfPUDgnhqAFcuXj8haXt/v86nhy8r4ZOuSvXhg=
k8s.io/cluster-bootstrap v0.0.0-20190918163108-da9fdfce26bb h1:VzoOqe8drBisvQPShYY6dfaIfAZkE3+irTlPGgGHI0A=
k8s.io/cluster-bootstrap v0.0.0-20190918163108-da9fdfce26bb/go.mod h1:mQVbtFRxlw/BzBqBaQwIMzjDTST1KrGtzWaR4CGlsTU=
k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE=
k8s.io/component-base v0.0.0-20190913200627-c1db07a83ddd h1:mxjuQNTeMzqXcj3od74+KumNO99dC+lo3hDaQKw7WU0=
k8s.io/component-base v0.0.0-20190913200627-c1db07a83ddd/go.mod h1:LEQCVXcGONZRN8PN2EI0AYq7KSifmCnnIyrrCczZpSI=
k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090 h1:0UWOjjag5IcVoAko0g+3qGhegdwWkRf4v4AHCIMVwnc=
k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA=
k8s.io/cri-api v0.0.0-20190828162817-608eb1dad4ac h1:ikDtGPX1DVIhl4E36+khq6RVyA65ycfiieBHecQiaX0=
k8s.io/cri-api v0.0.0-20190828162817-608eb1dad4ac/go.mod h1:BvtUaNBr0fEpzb11OfrQiJLsLPtqbmulpo1fPwcpP6Q=
k8s.io/csi-translation-lib v0.0.0-20190913203836-0443d78e4a59/go.mod h1:Z2da2HAosSCldKbxZUCUgW1iuDvFK/6komqmdj/4OKc=
k8s.io/csi-translation-lib v0.0.0-20190918163402-db86a8c7bb21/go.mod h1:Ja9f0K9MkTuUSyBgpjFt2am69TOjrmkQUN25WTF3CCM=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM=
k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/kube-aggregator v0.0.0-20190913201430-06145edbcf86/go.mod h1:mNqKusswM9AkvjLTACMpvM1PPbjZdRm3fw9+lX4u3IQ=
k8s.io/kube-controller-manager v0.0.0-20190913203351-7116f89e0eb2/go.mod h1:SjgoR0HT0G2LXEmTJfzIUb6aOG8x+9MB3DkeuJNAIWY=
k8s.io/kube-aggregator v0.0.0-20190918161219-8c8f079fddc3/go.mod h1:NJisPUqwlg1A99RhO1BTnNtwC4pKUyXJ2f3Xc4PxKQg=
k8s.io/kube-controller-manager v0.0.0-20190918162944-7a93a0ddadd8/go.mod h1:+HrHoqJm0UqnlrBEKXGzs2701YN4+ozi76oG7iYvJ8s=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-proxy v0.0.0-20190913202909-61cd20ae3d92 h1:rwbMw2DrDf61B3xkF7uNJhNgEBcV7ob4LWP2TA737Ao=
k8s.io/kube-proxy v0.0.0-20190913202909-61cd20ae3d92/go.mod h1:HQ4XNYdZG3Qz0hcSy1ErKt2gWcrFhyazy0HxC1JPyVs=
k8s.io/kube-scheduler v0.0.0-20190913203215-88ce8cca4f54/go.mod h1:ewr9YWw357NuVd0VeNRWpeGdsGu0sD5u5+9gYrTtl3c=
k8s.io/kubectl v0.0.0-20190913204531-26d9723e03ae/go.mod h1:LXehmDS6vJPlCnhVujbrbzBAW+s2VwSDXMTSrs6FoHs=
k8s.io/kubelet v0.0.0-20190913203039-8a485d6b870b h1:B8EpVgoT83ie7ssrt04zy5dUC1VLx3sfQbJ+nJQfcT4=
k8s.io/kubelet v0.0.0-20190913203039-8a485d6b870b/go.mod h1:2bD8LOeQ15cOrRBsuNSMroxIslV9lJHKbjNg9FV9MPA=
k8s.io/kubernetes v1.16.0-rc.2 h1:gYZKY/A7gI7MINFn+6wbTknhgSrmfw6rQxZy4f+Ya4Q=
k8s.io/kubernetes v1.16.0-rc.2/go.mod h1:nlP2zevWKRGKuaaVbKIwozU0Rjg9leVDXkL4YTtjmVs=
k8s.io/legacy-cloud-providers v0.0.0-20190913204022-a09231045882/go.mod h1:zcAjhaoZXE8lLprnr9NZKOd83cnqRjZGOoeQvHyoi7o=
k8s.io/metrics v0.0.0-20190913202417-f6bee5ba35c7/go.mod h1:bq7QOjnqfa7m78TNZjQjCUzG40KAIF+ItkeznvGHzYc=
k8s.io/kube-proxy v0.0.0-20190918162534-de037b596c1e h1:B4xV1wZN69nOG5/AM9hDPUW1347SOzLJIA7b0ajPgN0=
k8s.io/kube-proxy v0.0.0-20190918162534-de037b596c1e/go.mod h1:/48p8Y6dkWJrll4tsceAoGKudGpRmtQu/u1zlG14NnI=
k8s.io/kube-scheduler v0.0.0-20190918162820-3b5c1246eb18/go.mod h1:k2dnGirIGylr51dpqxn2Zv6Yt47A+6NiynBIYfAU67I=
k8s.io/kubectl v0.0.0-20190918164019-21692a0861df/go.mod h1:AjffgL1ZYSrbpRJHER9vC+/INYwTSdmoZD0DXhMKzxQ=
k8s.io/kubelet v0.0.0-20190918162654-250a1838aa2c h1:nOCXW6C3JQyp5olf4O0Tt1/6e4bzqAKfIXT5vnhasEs=
k8s.io/kubelet v0.0.0-20190918162654-250a1838aa2c/go.mod h1:LGhpyzd/3AkWcFcQJ3yO1UxMnJ6urMkCYfCp4iVxhjs=
k8s.io/kubernetes v1.16.0 h1:WPaqle2JWogVzLxhN6IK67u62IHKKrtYF7MS4FVR4/E=
k8s.io/kubernetes v1.16.0/go.mod h1:nlP2zevWKRGKuaaVbKIwozU0Rjg9leVDXkL4YTtjmVs=
k8s.io/legacy-cloud-providers v0.0.0-20190918163543-cfa506e53441/go.mod h1:Phw/j+7dcoTPXRkv9Nyi3RJuA6SVSoHlc7M5K1pHizM=
k8s.io/metrics v0.0.0-20190918162108-227c654b2546/go.mod h1:XUFuIsGbIqaUga6Ivs02cCzxNjY4RPRvYnW0KhmnpQY=
k8s.io/repo-infra v0.0.0-20181204233714-00fe14e3d1a3/go.mod h1:+G1xBfZDfVFsm1Tj/HNCvg4QqWx8rJ2Fxpqr1rqp/gQ=
k8s.io/sample-apiserver v0.0.0-20190913201707-470afe49ddf4/go.mod h1:tYne6pv68J3XTJYi2r7cNrjwzieQ8obdBcGkKhAcZuM=
k8s.io/sample-apiserver v0.0.0-20190918161442-d4c9c65c82af/go.mod h1:HP/BmiRyZTMIZ5RI2p4tCz/b2kre7URuKLQ7/KHqWAs=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=

View File

@ -1,5 +1,7 @@
#!/bin/bash
KUBE_TAG="kubernetes-1.16.0-rc.2"
# Example: kubernetes-1.16.0
KUBE_TAG="${1}"
export GOPROXY=https://proxy.golang.org

View File

@ -3,7 +3,7 @@
set -eou pipefail
export KUBERNETES_VERSION=v1.16.0-rc.2
export KUBERNETES_VERSION=v1.16.0
export TALOS_IMG="docker.io/autonomy/talos:${TAG}"
export TMP="/tmp/e2e"
export TALOSCONFIG="${TMP}/talosconfig"

View File

@ -27,6 +27,6 @@ e2e_run "set -eou pipefail
--plugin e2e \
--plugin-env e2e.E2E_USE_GO_RUNNER=true \
--mode certified-conformance \
--kube-conformance-image-version v1.16.0-rc.2
--kube-conformance-image-version v1.16.0
results=\$(sonobuoy retrieve --kubeconfig ${KUBECONFIG})
sonobuoy e2e --kubeconfig ${KUBECONFIG} \$results"

View File

@ -161,7 +161,7 @@ services:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
clusterName: cluster.local
kubernetesVersion: v1.16.0-rc.2
kubernetesVersion: v1.16.0
controlPlaneEndpoint: 1.2.3.4:443
apiServer:
certSANs: [ "1.2.3.4", "127.0.0.1" ]

View File

@ -121,7 +121,7 @@ services:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
clusterName: test
kubernetesVersion: v1.16.0-rc.2
kubernetesVersion: v1.16.0
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration

View File

@ -106,7 +106,7 @@ const (
KubeadmEtcdPeerKey = v1beta1.DefaultCertificatesDir + "/" + constants.EtcdPeerKeyName
// KubernetesVersion is the enforced target version of the control plane.
KubernetesVersion = "v1.16.0-rc.2"
KubernetesVersion = "v1.16.0"
// KubernetesImage is the enforced hyperkube image to use for the control plane.
KubernetesImage = "k8s.gcr.io/hyperkube:" + KubernetesVersion

View File

@ -172,7 +172,7 @@ services:
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
clusterName: test
kubernetesVersion: v1.16.0-rc.2
kubernetesVersion: v1.16.0
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration

View File

@ -69,7 +69,7 @@ const kubeadmConfig = `configuration: |
dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.16.0-rc.2
kubernetesVersion: v1.16.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12