在 Kubernetes + Docker-in-docker + 用户定义的 docker 网络中,`docker push` 到 gcr.io 失败
`docker push` to gcr.io fails in Kubernetes + Docker-in-docker + user-defined docker network
背景:
我正在使用 Drone 测试应用程序。 Drone 被部署到 Kubernetes,带有 docker
(dind / docker-in-docker) 容器。
测试完成后,我再次使用 drone 构建并推送几个 docker 个图像,每个图像大约 ~40mb 到 us.gcr.io
当 Drone 创建 docker 容器来测试我的应用程序,以及单独的容器来构建我的应用程序和图像时,它会创建一个 docker 网络到 link 要构建的容器服务,例如临时测试数据库(CI 管道中的标准)。
然而,Kubernetes pod 网络和 Docker-in-Docker 的组合在尝试推送到 gcr 时会导致以下结果:
time="2018-03-19T03:31:12.037507241Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.208009069Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.216232506Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.407608372Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.410403394Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:23.432621075Z" level=error msg="Upload failed, retrying: unexpected EOF"
但是,当推送到(我假设的)旧注册表版本时,它可以完美运行。
在未启用 docker 容器网络的情况下推送到 gcr 时,它也可以完美运行。
这里是 docker 命令 运行。显然敏感数据被省略了。
docker network create test-network && \
docker run --network=test-network -d cockroachdb/cockroach:v1.1.2 -c /cockroach sql --insecure && \
docker run --rm -it -e GKE_CLUSTER_NAME=my-cluster-1 -e GKE_CLUSTER_ZONE=us-east1-b -e GCP_PROJECT=my-gcp-project -e DOCKER_USE_GCP=true -v /var/run/docker.sock:/var/run/docker.sock --network=test-network us.gcr.io/my-project/runner /bin/sh -c 'mkdir -p src/git.example.com/project && git clone https://user:pass!@git.example.com/project/project $GOPATH/src/git.example.com/project/project && cd $GOPATH/src/git.example.com/project/project && git checkout gcr && jules -stage deploy_docker'
jules -stage deploy_docker
命令在 8 个不同的目录上同时运行 go build
、docker build
和 gcloud docker -- push...
。
所以,总结:
Kubernetes pod + docker-in-docker + gcloud docker 推送导致连接持续中断。
我可以使用 docker 守护进程或 kubernetes 网络设置做些什么,或者做些什么来缓解这种情况?至少我想明白为什么会这样。
谢谢!
更新:
这甚至不需要 Kubernetes 发生!
我刚用一个新的 GCE 实例尝试过 运行 Ubuntu 并且它也发生在那里。
我就此问题联系了 GCR 支持,因为它似乎只发生在 GCR 上,他们告诉我试图推送到注册表的 IAM 帐户实际上是 GCE 实例的默认服务帐户,而不是我提供给 Dockerfile 的帐户。
但是,这并没有解释 "Broken pipe" 和 "EOF" 错误,而我本应该得到 401 - Unauthorized
。
我尝试使用 google/cloud-sdk
docker 图像 here 进行相同的推送,当我在类似的环境中为它提供相同的密钥时它工作正常,所以这告诉我我在 docker 图像上安装 gcloud 的方式很糟糕。
这是我的:
RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz
RUN tar -xvf google-cloud-sdk.tar.gz
RUN rm google-cloud-sdk.tar.gz
RUN google-cloud-sdk/install.sh --usage-reporting=false \
--path-update=false \
--bash-completion=false
ENV PATH="/go/google-cloud-sdk/bin:${PATH}"
RUN gcloud components install kubectl
RUN gcloud components install docker-credential-gcr
这就是 google/cloud-sdk
所拥有的。更新我的 Dockerfile 以这种方式安装它解决了我的问题。
# Install gcloud
ENV CLOUD_SDK_VERSION 193.0.0
ARG INSTALL_COMPONENTS
RUN easy_install -U pip && \
pip install -U crcmod && \
export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
apt-get update && apt-get install -y google-cloud-sdk=${CLOUD_SDK_VERSION}-0 $INSTALL_COMPONENTS && \
gcloud config set core/disable_usage_reporting true && \
gcloud config set component_manager/disable_update_check true && \
gcloud config set metrics/environment github_docker_image && \
gcloud --version
我仍然对为什么这样做对我一无所知,所以如果有人有任何见解那就太好了。
背景:
我正在使用 Drone 测试应用程序。 Drone 被部署到 Kubernetes,带有 docker
(dind / docker-in-docker) 容器。
测试完成后,我再次使用 drone 构建并推送几个 docker 个图像,每个图像大约 ~40mb 到 us.gcr.io
当 Drone 创建 docker 容器来测试我的应用程序,以及单独的容器来构建我的应用程序和图像时,它会创建一个 docker 网络到 link 要构建的容器服务,例如临时测试数据库(CI 管道中的标准)。
然而,Kubernetes pod 网络和 Docker-in-Docker 的组合在尝试推送到 gcr 时会导致以下结果:
time="2018-03-19T03:31:12.037507241Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.208009069Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.216232506Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.407608372Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:17.410403394Z" level=error msg="Upload failed, retrying: net/http: HTTP/1.x transport connection broken: write tcp w.x.y.z:39662->z.y.x.w:443: write: broken pipe"
time="2018-03-19T03:31:23.432621075Z" level=error msg="Upload failed, retrying: unexpected EOF"
但是,当推送到(我假设的)旧注册表版本时,它可以完美运行。
在未启用 docker 容器网络的情况下推送到 gcr 时,它也可以完美运行。
这里是 docker 命令 运行。显然敏感数据被省略了。
docker network create test-network && \
docker run --network=test-network -d cockroachdb/cockroach:v1.1.2 -c /cockroach sql --insecure && \
docker run --rm -it -e GKE_CLUSTER_NAME=my-cluster-1 -e GKE_CLUSTER_ZONE=us-east1-b -e GCP_PROJECT=my-gcp-project -e DOCKER_USE_GCP=true -v /var/run/docker.sock:/var/run/docker.sock --network=test-network us.gcr.io/my-project/runner /bin/sh -c 'mkdir -p src/git.example.com/project && git clone https://user:pass!@git.example.com/project/project $GOPATH/src/git.example.com/project/project && cd $GOPATH/src/git.example.com/project/project && git checkout gcr && jules -stage deploy_docker'
jules -stage deploy_docker
命令在 8 个不同的目录上同时运行 go build
、docker build
和 gcloud docker -- push...
。
所以,总结:
Kubernetes pod + docker-in-docker + gcloud docker 推送导致连接持续中断。
我可以使用 docker 守护进程或 kubernetes 网络设置做些什么,或者做些什么来缓解这种情况?至少我想明白为什么会这样。
谢谢!
更新:
这甚至不需要 Kubernetes 发生!
我刚用一个新的 GCE 实例尝试过 运行 Ubuntu 并且它也发生在那里。
我就此问题联系了 GCR 支持,因为它似乎只发生在 GCR 上,他们告诉我试图推送到注册表的 IAM 帐户实际上是 GCE 实例的默认服务帐户,而不是我提供给 Dockerfile 的帐户。
但是,这并没有解释 "Broken pipe" 和 "EOF" 错误,而我本应该得到 401 - Unauthorized
。
我尝试使用 google/cloud-sdk
docker 图像 here 进行相同的推送,当我在类似的环境中为它提供相同的密钥时它工作正常,所以这告诉我我在 docker 图像上安装 gcloud 的方式很糟糕。
这是我的:
RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz
RUN tar -xvf google-cloud-sdk.tar.gz
RUN rm google-cloud-sdk.tar.gz
RUN google-cloud-sdk/install.sh --usage-reporting=false \
--path-update=false \
--bash-completion=false
ENV PATH="/go/google-cloud-sdk/bin:${PATH}"
RUN gcloud components install kubectl
RUN gcloud components install docker-credential-gcr
这就是 google/cloud-sdk
所拥有的。更新我的 Dockerfile 以这种方式安装它解决了我的问题。
# Install gcloud
ENV CLOUD_SDK_VERSION 193.0.0
ARG INSTALL_COMPONENTS
RUN easy_install -U pip && \
pip install -U crcmod && \
export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
apt-get update && apt-get install -y google-cloud-sdk=${CLOUD_SDK_VERSION}-0 $INSTALL_COMPONENTS && \
gcloud config set core/disable_usage_reporting true && \
gcloud config set component_manager/disable_update_check true && \
gcloud config set metrics/environment github_docker_image && \
gcloud --version
我仍然对为什么这样做对我一无所知,所以如果有人有任何见解那就太好了。