[转帖]Docker里运行Docker docker in docker(dind)

时间:2022-09-24 16:08:17

Docker里运行Docker docker in docker(dind)

http://www.wantchalk.com/c/devops/docker/2017/05/24/docker-in-docer.html
 
mark一下 学习原作者的内容. 
Posted on 2017-05-24

目的

制作一个可以build docker镜像的docker镜像,jenkins CI服务节点,部署到阿里云的容器服务集群里.

阿里云官方有完整的镜像,master和slave的都有,时间稍微久远了一点,所以自己研究一下build个最新的版本.

关于 docker in docker

docker运行在docker里面分两种情况

  • (dind) docker inside docker
  • (dood) docker outside of docker

dood的好处是内部容器并不需要真正的安装docker而是挂载父级docker的socket和执行文件就可以,但是缺点也非常明显,就是内部容器必须和外部的docker环境保持一致,不然会报各种错误,缺少库文件什么的,而且安全性有很大问题,Docker-in-Docker ,贴吧翻译版本, 这个项目的作者本身就不建议这么去使用docker(dind的方式),有安全性问题,存储问题

看了这些文章之后,得出的结论如下

  • 真正的docker in docker 在docker官方有镜像直接就能用 官方dind镜像
  • docker in docker dind 是用来学习的,在实际生产环境中一般用不到
  • docker in docker dind 是有很多问题的(意想不到的), 比如存储空间,安全等等
  • 如果只是使用CI如jenkins这种,在容器里需要build镜像,那么不需要纯粹的dind, 可以变通的使用host的docker(通过二进制docker文件和宿主的sock来实现)

那么解决方案是什么

原文


The solution

Let’s take a step back here. Do you really want Docker-in-Docker? Or do you just want to be able to run Docker (specifically: build, run, sometimes push containers and images) from your CI system, while this CI system itself is in a container?

I’m going to bet that most people want the latter. All you want is a solution so that your CI system like Jenkins can start containers.

And the simplest way is to just expose the Docker socket to your CI container, by bind-mounting it with the -v flag.

Simply put, when you start your CI container (Jenkins or other), instead of hacking something together with Docker-in-Docker, start it with:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

Now this container will have access to the Docker socket, and will therefore be able to start containers. Except that instead of starting “child” containers, it will start “sibling” containers.

Try it out, using the docker official image (which contains the Docker binary):

docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -ti docker

This looks like Docker-in-Docker, feels like Docker-in-Docker, but it’s not Docker-in-Docker: when this container will create more containers, those containers will be created in the top-level Docker. You will not experience nesting side effects, and the build cache will be shared across multiple invocations.

Former versions of this post advised to bind-mount the docker binary from the host to the container. This is not reliable anymore, because the Docker Engine is no longer distributed as (almost) static libraries.

If you want to use e.g. Docker from your Jenkins CI system, you have multiple options:

  • installing the Docker CLI using your base image’s packaging system (i.e. if your image is based on Debian, use .deb packages),
  • using the Docker API.

翻译后


解决方案

退一步, 是需要一个真正的 docker in docker,还是只想在类似jenkins这样的CI系统里要运行docker命令(build push images)

我想大部分人只是需要后者,你所需要的是你的ci系统可以启动容器,或者构建容器(这是我加的)

最简单的方式是启动容器的时候以-v的方式挂载宿主机的docker的socket给含有jenkins这种CI的容器使用

简单的说,启动你的CI 容器(jenkins或者其他), 而不是用docker-in-docker上hacking, 启动方法:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

这样这个容器就会可以访问到宿主机的docker socket并使用它,因为这个容器就有能力启动容器,这样他启动和操作的容器和他本身是兄弟关系,是平级的而不是父子关系.

试试官方的docker镜像, 包含二进制可执行程序

docker run -v /var/run/docker.sock:/var/run/docker.sock -ti docker

插个楼,我再本机上做的实验

➜  jenkins docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -ti docker:17.05
Unable to find image 'docker:17.05' locally

17.05: Pulling from library/docker
cfc728c1c558: Pull complete
81d7b2e827ca: Pull complete
144b6478a622: Pull complete
e04c57814bdc: Pull complete
Digest: sha256:da22b37a64e68f7b2199ba619f61e0b82f95d6fa4ed812b2d6c19e486d933ed0
Status: Downloaded newer image for docker:17.05

/ # which docker
/usr/local/bin/docker
/ # docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                                NAMES
cae7df10f791        docker:17.05            "docker-entrypoint..."   20 seconds ago      Up 19 seconds                                            hungry_banach
d0c7c57ee2c9        jenkinsci/jenkins:lts   "/bin/tini -- /usr..."   18 hours ago        Up 8 hours          50000/tcp, 0.0.0.0:49001->8080/tcp   vigilant_pasteur
/ # docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS                                NAMES
cae7df10f791        docker:17.05            "docker-entrypoint..."   23 seconds ago      Up 22 seconds                                                    hungry_banach
512c903e80da        django:test03           "/bin/bash"              10 hours ago        Exited (0) 6 hours ago                                           testdjango01
d0c7c57ee2c9        jenkinsci/jenkins:lts   "/bin/tini -- /usr..."   18 hours ago        Up 8 hours                  50000/tcp, 0.0.0.0:49001->8080/tcp   vigilant_pasteur
cb5527ee98c5        jenkinsci/jenkins:lts   "/bin/tini -- /usr..."   18 hours ago        Created                                                          vigilant_easley
fcd7e2089a0d        12c901436f44            "/bin/sh -c 'echo ..."   19 hours ago        Exited (127) 19 hours ago                                        amazing_easley
0fb85d775afc        04b5d101ead1            "/bin/sh -c 'set -..."   20 hours ago        Exited (2) 19 hours ago                                          gracious_swirles
2ff8dce9c205        ee4682994d35            "/bin/bash"              20 hours ago        Exited (0) 19 hours ago                                          testpython2

可以清楚的看到,这些结果都是宿主机上的docker的结果,所以这里使用的docker命令实际上的空间和进程都是在宿主机上的.

可以看一些这个镜像的Dockfile

穿越回来,继续翻译

这看起来像是docker-in-docker,但是实际上不是,当你要在这个容器里创建新的容器的时候,这些容器并不是在容器里被创建的,而是在host机器上创建的,你将不会受到内嵌的影响,构建缓存也在多实例间共享.

这篇文章的老版本建议bind docker的二进制文件从host到容器,这个说法已经不再可靠,因为docker 引擎不再发布静态库,所以单纯用挂载的方式使docker的二进制文件在容器和host间共享的方式不存在了,取而代之的是直接在容器内解压一个编译好的docker.

所以现在如果你想使用docker在jenkins CI的容器里,你有以下选择:

  • 安装docker cli,在你的基础docker镜像里(比如,你使用debian, 就使用 deb packages)
  • 使用remote api

我的方案

好了看了这么多,是时候自己构建一个供jenkins子节点使用的镜像了,包含docker,可以build和push镜像

我的场景如下

  • 阿里云上用几台机器组件了容器的集群
  • 现在要搭建一个CI的demo(jenkins的)
  • jenkins是master agent模式,不同节点环境不一样的,有的是python的,有的是java的
  • 子节点在有代码更新的时候,触发任务,任务很简单,就是用Dockerfile构建新的镜像
  • 新的镜像构建完成以后,直接推送(走阿里云的内网,不用流量费)
  • 镜像有更新,触发容器集群重新部署应用.

需要的镜像

  • 1个jenkins master容器
  • 1个jenkins agent容器 用来build镜像并推送到镜像仓库
  • 一个python+mysql 编排

最后附上我已经配置好的Dockerfile(已经在阿里云的容器里运行)

FROM ubuntu:xenial

MAINTAINER Vincent Wantchalk <ohergal@gmail.com>

RUN apt-get update

RUN apt-get -y install wget \
	apt-utils \
	locales \
	tzdata \
	\
	build-essential \
	apt-transport-https \
	ca-certificates \
	curl \
	git \
	openssh-server \
	zlib1g \
	zlib1g.dev \
	openssl \
	libssl-dev \
	iptables && \
	rm -rf /var/lib/apt/lists/*

RUN locale-gen en_US.UTF-8
RUN dpkg-reconfigure locales

RUN echo "Asia/shanghai" > /etc/timezone
RUN ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
	&& dpkg-reconfigure -f noninteractive tzdata 

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

# To avoid annoying "perl: warning: Setting locale failed." errors,
# do not allow the client to pass custom locals, see:
# http://*.com/a/2510548/15677
# RUN sed -i 's/^AcceptEnv LANG LC_\*$//g' /etc/ssh/sshd_config

RUN apt-get -q update &&\
    DEBIAN_FRONTEND="noninteractive" apt-get -q install -y -o Dpkg::Options::="--force-confnew" --no-install-recommends software-properties-common && \
    add-apt-repository -y ppa:openjdk-r/ppa &&\
    apt-get -q update &&\
    DEBIAN_FRONTEND="noninteractive" apt-get -q install -y -o Dpkg::Options::="--force-confnew" --no-install-recommends openjdk-8-jdk && \
    apt-get -q clean -y && rm -rf /var/lib/apt/lists/* && rm -f /var/cache/apt/*.bin && \
	sed -i 's|session    required     pam_loginuid.so|session    optional     pam_loginuid.so|g' /etc/pam.d/sshd &&\
	mkdir -p /var/run/sshd

# clean compile tools

RUN apt-get purge -y --auto-remove build-essential libssl-dev

RUN useradd -m -d /home/jenkins -s /bin/bash jenkins && \
	echo "jenkins:jenkins" | chpasswd

# install docker binary files

ENV DOCKER_BUCKET get.docker.com
ENV DOCKER_VERSION 17.05.0-ce
ENV DOCKER_SHA256_x86_64 340e0b5a009ba70e1b644136b94d13824db0aeb52e09071410f35a95d94316d9
ENV DOCKER_SHA256_armel 59bf474090b4b095d19e70bb76305ebfbdb0f18f33aed2fccd16003e500ed1b7

RUN curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz" -o docker.tgz \
	&& echo "${DOCKER_SHA256_x86_64} *docker.tgz" | sha256sum -c - \
	&& tar -xzvf docker.tgz \
	&& mv docker/* /usr/local/bin/ \
	&& rmdir docker \
	&& rm docker.tgz \
	&& chmod +x /usr/local/bin/docker
#	&& docker -v \
#	&& docker ps -a

RUN echo "jenkins ALL=NOPASSWD: ALL" >> /etc/sudoers

# Standard SSH port
EXPOSE 22

COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]

# Default command
CMD ["/usr/sbin/sshd", "-D"]

参考:

[转帖]Docker里运行Docker docker in docker(dind)的更多相关文章

  1. jenkins和docker 在docker里运行jenkins

    在docker里运行jenkins server. 文章来自:http://www.ciandcd.com文中的代码来自可以从github下载: https://github.com/ciandcd ...

  2. 最简单的docker教程:在docker里运行nginx服务器

    命令行docker search nginx搜索名为nginx的docker image,返回结果的第一个,github上有10293个star,这就是我们想要搜索的结果: 使用命令docker pu ...

  3. docker里运行docker命令

    一.概述 现有环境的jenkins是在docker里面运行的,需要执行docker相关命令才行. 关于基于docker搭建jenkins,请参考链接: https://www.cnblogs.com/ ...

  4. docker里运行cron的要点笔记

    1.如果用精简的apline或debian:stretch-slim创建的docker,里面可能没有cron模块,需要独立安装 apt-get install -y cron 2.docker里面cr ...

  5. Docker容器运行GUI程序的配置方法

    0.环境说明 Ubuntu 16.04 docker 1.35 1.Docker的“可视化” Docker本身的工作模式是命令行的,因为主要的使用场景可能是做服务器后端方面的比较多. 但有时候我们会有 ...

  6. docker下运行Gitlab CE&plus;Jenkins&plus;Nexus3&plus;docker-registry-frontend

    DevOps - Gitlab CE - Jenkins - Nexus Gitlab CE https://hub.docker.com/r/gitlab/gitlab-ce/ https://do ...

  7. &lbrack;置顶&rsqb;&NewLine; Docker学习总结(1)——Docker实战之入门以及Dockerfile(一)

    一.Docker是什么? 首先Docker是软件工业上的集装箱技术 回顾,在没有集装箱出现以前,传统运输行业中,会存在这些问题: 在运输过程中,货物损坏 装卸.运输货物,效率低下 运输手续繁多及运输环 ...

  8. Docker实践 - 安装Docker并在容器里运行tomcat

    安装Docker yum install docker 本文使用的系统是centos7,ubuntu使用以下命令 sudo apt-get update sudo apt-get install do ...

  9. 从零开始通过idea插件将一个spring boot项目部署到docker容器里运行

    实操:将一个spring boot项目部署到docker容器里运行 实验需要的环境: 腾讯云+Ubuntu 16.04 x64+idea+插件docker integration+daocloud 第 ...

随机推荐

  1. boost构造&comma;解析json

    void asynDBCenter::isGetActorInfoEx(void* on_process, const char* arg) { std::stringstream ros(arg); ...

  2. ASP&period;NET MVC Model验证总结【转】

    一.启用客户端验证: 客户端验证主要是为了提高用户体验,在网页不回刷的情况下完成验证. 第一步是要在web.config里启用客户端验证,这在MVC3自带的模板项目中已经有了: <add key ...

  3. OpenCV例程实现人脸检测

    前段时间看的OpenCV,其实有很多的例子程序,参考代码值得我们学习,对图像特征提取三大法宝:HOG特征,LBP特征,Haar特征有一定了解后. 对本文中的例子程序刚开始没有调通,今晚上调通了,试了试 ...

  4. CentOS6&period;5 PHP基础环境搭建 &lbrack;个人整理-亲测可用&rsqb;

    ** * CentOS6.5 搭建基础PHP环境(yum安装) * http://www.aiplaypc.com/160.html **   #安装需要的包,有依赖关系,自动帮你解决 yum ins ...

  5. Android 基本控件

    http://www.cnblogs.com/LT-blogs/archive/2012/08/07/2626118.html http://blog.csdn.net/android_tutor/a ...

  6. SUI Mobile

    <header class="bar bar-nav"> <h1 class='title'>只有图标的表单</h1> </header& ...

  7. STL:set&sol;multiset用法详解

    集合 使用set或multiset之前,必须加入头文件<set> Set.multiset都是集合类,差别在与set中不允许有重复元素,multiset中允许有重复元素. sets和mul ...

  8. Failed to fetch URL http&colon;&sol;&sol;dl-ssl&period;google&period;com&sol;android&sol;repository&sol;addons&lowbar;list-2&period;xml&comma; reason&colon;

    http://blog.csdn.net/gyming/article/details/8168166/ 最近接受的这个项目需要Android SDK Tools revision 22.6.2 or ...

  9. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  10. mail工具的安装、配置及问题处理

    使用mail发邮件时,应先将相关邮件服务启动,本文主要介绍sendmail邮件工具的配置方法和问题处理. 1.安装 ubuntu中sendmail函数可以很方便的发送邮件,ubuntu sendmai ...