Docker 深入篇之 Build 原理

使用 Docker 时,最常用的命令无非是 docker container 和 docker image 相关的子命令,当然最初没有管理类命令(或者说分组)的时候,最常使用的命令也无非是 docker run docker commit docker build 和 docker images 这些。 今天来聊一下和 Docker 中核心概念 image 相关的重要命令, docker build 或者说 docker image build 为了简便起见,下文的命令全部使用 docker build 。 Docker Image 先简单介绍下 Docker Image, 通常情况下我们将其称之为镜像,镜像是由多个层组成的文件,这些层用于在容器内执行代码(命令)等。每个镜像基本上都是根据应用程序完整的可执行版本进行构建的,并且需要注意的是,它会依赖于主机的系统内核。当用户在运行镜像时,这将会创建一个或者多个容器实例。 Dockerd Dockerd 是 Docker 的服务端,默认情况下提供 Unix Domain Socket 连接,当然也可以监听某个端口,用于对外提供服务。 所以有时候,我们也可以使用服务器上的 Docker daemon 来提供服务,以加快构建速度及解决一些网络问题之类的。 好的,基础概念了解了, 那我们开始进入正题。 使用 Dockerfile 我们知道构建镜像的方法有多种,本文中我们只介绍使用 Dockerfile 通过 docker build 的方式构建镜像。 为了简便,我们以一个简单的 Dockerfile 开始。构建一个容器内使用的 kubectl 工具 (当然选择它的原因在于 kubectl 足够大,并不考虑可用性,这个稍后解释)

GitLab CI 使用 InsecureRegistry

继上次分享后,有读者留言问 dind 使用 insecure-registry 相关的问题。 请教个问题,基于gitlab CI做java项目持续集成,用到了docker in docker, docker build使用的Dockerfile中使用了一个insecure registry,在dind的容器中如何配置insecure registry 我的回复是: 首先, 不推荐使用 insecure registry 毕竟有其固有限制, 如果一定要用的话, 其实在 services 层配置一个 command 就可以,这也是最简单的, 例如: services: - name: docker:dind command: ["--insecure-registry=myregistry:5000"] 由于留言字数的限制,就单独写个小文来回复下。 这个做法实际效果如下: (Tao) ➜ kubernetes git:(master) ✗ sudo docker run -d --privileged --name dind docker:dind --insecure-registry="myregistry:5000" 8fb68865638ebc65255bb568fbe1fd6b4ed4fca771075d8e55ebbbbdf0aef6d2 (Tao) ➜ kubernetes git:(master) ✗ sudo docker top dind UID PID PPID C STIME TTY TIME CMD root 18270 18252 1 11:27 ?

基于 GitLab 的 CI 实践

上个月受 DockOne 社区邀请,做了一次 CI 实践方面的线上分享,在此记录下。 本文讲述 GitLab CI 的架构及其能力特性,分析它在 DevOps 实践中的作用。 通过分析 Docker In Docker 的技术细节,详细讲述 CI 实践以及在生产环境中的所做的优化,包括但不限于镜像仓库等,以达到数倍的性能提升。 本次分享内容以 GitLab Community Edition 11.0.4 edb037c 为例。 为何选择 GitLab CI 认识 GitLab CI 什么是 GitLab CI GitLab CI 是 GitLab 为了提升其在软件开发工程中作用,完善 DevOPS 理念所加入的 CI/CD 基础功能。可以便捷的融入软件开发环节中。通过 GitLab CI 可以定义完善的 CI/CD Pipeline。 优势 GitLab CI 是默认包含在 GitLab 中的,我们的代码使用 GitLab 进行托管,这样可以很容易的进行集成 GitLab CI 的前端界面比较美观,容易被人接受 包含实时构建日志,容易追踪 采用 C/S 的架构,可方面的进行横向扩展,性能上不会有影响 使用 YAML 进行配置,任何人都可以很方便的使用。 重点概念 Pipeline Pipeline 相当于一个构建任务,里面可以包含多个流程,如依赖安装、编译、测试、部署等。 任何提交或者 Merge Request 的合并都可以触发 Pipeline

Install-Python3.6-on-CentOS7

拖了很久没有更新,抱歉啦~ 今天受邀写篇如何在 CentOS 7 上配置 Python 3 环境的文章。往常我都选择直接把我早年写的一篇文章源码编译MongoDB丢过去,让他们看其中的源码编译 Python 那一节,不过那节写的其实不太详细,而且最近被很多人催,所以还是单独写一篇好了。 当前最新的 CentOS 7.3 默认安装的是 Python 2 ,并且默认的官方 yum 源中不提供 Python 3 的安装包。有些用户想要升级使用 Python 3 但实际可能有各种各样的问题,导致出错,反观一下激进的 Fedora 社区,在23的时候,就将默认的版本修改成了 Python3 (如果我没记错的话)。 先说下我所使用的系统环境, 一个新创建的 Docker 容器。 使用 cat /etc/redhat-release 可以看到运行的是 CentOS 7.3 版本。 在纯净的 CentOS 系统上安装 Python 环境主要有两种办法。 一种是通过源码编译安装,另外一种就是安装已经打好的 RPM 包。依照个人习惯,我们先来看一下如何通过源码编译的方式安装 Python 3.6 并且配置虚拟环境。 使用源码进行编译安装 基础环境 先安装安装几个必须的包,以方便后续的操作 ➜ yum install wget gcc make ➜ # wget 用于下载源码包 ➜ # gcc 和 make 用于编译 上 Python的官网 下载源码包 ➜ wget https://www.

理解 Redis 的 RESP 协议

简介 Redis 的客户端和服务端之间采取了一种独立名为 RESP(REdis Serialization Protocol) 的协议,作者主要考虑了以下几个点: 容易实现 解析快 人类可读 注意:RESP 虽然是为 Redis 设计的,但是同样也可以用于其他 C/S 的软件。 数据类型及示例 RESP 主要可以序列化以下几种类型:整数,单行回复(简单字符串),数组,错误信息,多行字符串。Redis 客户端向服务端发送的是一组由执行的命令组成的字符串数组,服务端根据不同的命令回复不同类型的数据,但协议的每部分都是以 “\r\n” (CRLF) 结尾的。另外 RESP 是二进制安全的,不需要处理从一个进程到另一个进程的传输,因为它使用了前缀长度进行传输。 在 RESP 中, 一些数据的类型通过它的第一个字节进行判断: 单行回复:回复的第一个字节是 “+” 错误信息:回复的第一个字节是 “-” 整形数字:回复的第一个字节是 “:” 多行字符串:回复的第一个字节是 “\$” 数组:回复的第一个字节是 “*” 单行回复 以 “+” 开头,以 “\r\n” 结尾的字符串形式。e.g. +OK\r\n 响应的客户端库,应该返回除 “+” 和 CRLF 以外的内容,例如上面的内容,则返回 “OK”. e.g. 127.0.0.1:6379> set name TaoBeier +OK\r\n # 服务端实际返回 --- OK # redis-cli 客户端显示 错误信息 错误信息和单行回复很像,不过是把 “+” 替换成了 “-“。而这两者之间真正的区别是,错误信息会被客户端视为异常,并且组成错误类型的是错误消息本身。e.

2016 小回顾

时间很快, 已经走到了 2016 的末尾, 惯例的做个小回顾。(注:这篇起笔的时间是圣诞节TAT) 年初定的目标除了没有能合理安排追番时间, 其他的都基本完成了!(话说今年追番的时间简直少的可怜QAQ) 2016 年发生了太多的事情,要回顾的事情很多,索性就不写那么多了, 只按时间序稍微列几件有趣的事情。 单表亿级数据量的 MongoDB 做在线实时的数据拆分 在之前做的一些应用性能分析的方案上做了一些额外的设计和开发(明年修改下开源出来) PyCon China 2016 一些预期的计划顺利推进、落地,产出了一些系统 看了很多源码,折腾了很多东西,如果以后有空就写点东西出来(我又在给自己挖坑了) 认识了很多有趣的小伙伴~ 全年的状态基本和上面的截图是一致的, 全年都在 coding (截图仅限 GitHub上的记录)倒也比较开心, 另外就是现在看到自己项目的 star/fork 数,文章的阅读/收藏/转发数之类的,也已经不像以前看到 star 数刚上百时候会有那种喜悦了,大概这也是另一种成熟? 哈哈哈 另外写一下今年对我比较重要的几个数字: 1354 376 105 对这些数字的解释, 放在以后吧 :-) 2017 年,希望想做的事情都能基本完成,挖的坑慢慢填。 感谢一路上陪我走过的各位! 可以通过下面二维码订阅我的文章公众号【MoeLove】

关于 webpack 你可能忽略的细节(附源码分析)

注:本篇不是入门教程,入门请直接查看官方文档。本篇的主要目标是通过实际问题来介绍 webpack 中容易被人忽略的细节, 以及源码分析(以最新发布的 release 版本1.14.0的源码为例), 并且提供几种解决方案。 随着前端技术的火热发展,工程化,模块化和组件化的思想已逐步成为主流,与之相应的,就需要有一整套工具流可以支撑起它。 现在比较热门的前端资源模块化管理和打包工具应该非 Webpack 莫属了。 Webpack 是什么 它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。 –引自 Webpack 中文指南 使用举例 我们来看一下官方文档中的最小用例,新建并写入以下内容到这两个文件: cats.js var cats = ['dave', 'henry', 'martha']; module.exports = cats; app.js (Entry Point) cats = require('./cats.js'); console.log(cats); 这个时候,就可以使用 webpack 进行打包了: webpack ./app.js app.bundle.js 我们来看一下发生了什么, 目录下生成了一个打包后的文件 app.bundle.js ,这就是最基础的打包过程。 提出问题 如何判断打包是否成功? 通用方案 下面是我们常用的两种判断任务是否执行成功的方案 通过 return code 通过命令执行后的 return code 来判断(在 shell 中使用 $?

Composer 使用技巧简述

最近使用了世界最好的语言 PHP 用来管理依赖关系的工具 Composer. 稍微做点记录, 以做备忘. 如有错误还望指出. 安装 php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('SHA384', 'composer-setup.php') === 'aa96f26c2b67226a324c27919f1eb05f21c248b987e6195cad9690d5c1ff713d53020a02ac8c217dbf90a7eacc9d141d') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');" 上述代码来自官网. 局部安装 上述代码执行完成后, 只是下载到了 composer.phar 文件, 可以通过 php composer.phar 在任意位置执行. 全局安装 全局安装只是把 composer.phar 安装到 PATH 下即可. 可以像下面这样: sudo mv composer.phar /usr/local/bin/composer 国内镜像加速 使用Composer中文网提供的中国全量镜像进行加速. 单项目加速 进入项目目录(即 composer.json 文件所在目录) 执行:

Git workflow 详谈

作为一名工程师, Git 在日常开发中是不可或缺的工具。 这里详细介绍几种比较常用的基于 Git 的工作流模型, 以便于团队协作的规范化和效率提升。 中心化工作流 使用过SVN的应该都知道, SVN使用的是集中式管理流程, 如果你刚从SVN 切换到 Git , 你可以尝试使用中心化工作流的方式。这样,你几乎不需要变更之前的工作方式, 就可以完成平滑的过渡了。 而且在使用过程中还可以看到 Git 优于 SVN 的地方: 第一,每个成员都可以在本地拥有一份完整的项目代码仓库,而不只是一个工作区的副本,任何人都可以在本地执行 add 和 commit ,而不需要考虑远端仓库是否有变更,直到需要的时候再去提交即可。 第二,Git 的工作区、暂存区、引用更新等设计,可以给开发者更多自由来切换当前工作,且不会造成代码丢失。 工作细节 中心化工作流的方式是:在远端(远端可以是服务器端,也可以是本地的任意目录)新建一个仓库,默认是 master 分支,作为唯一的中心仓库。 所有人都 clone 这个仓库作为本地仓库,并在本地仓库进行开发。本地的提交是和远端仓库无关的,等需要的时候再 push 进主仓库的 master 分支即可。 在这种方式下, 远端是唯一确定的中心仓库, 所有人都要以这个仓库为准。 所以,在提交之前要先 fetch 最新提交,在这些提交之上作出自己的更改(一般我们使用 rebase来完成)。 如果本地的修改和远端仓库中的变更发生了冲突,那么 Git 会暂停 rebase ,并让你来解决这些冲突。我们可以很简单的使用 git status 和 git add 等命令完成冲突的合并。 另外, 如果我们解决不了冲突, 我们也可以使用 git rebase --abort 很容易的退出 rebase 的过程。 这样每天的工作方式就变成了,从中心仓库拉取最新代码, 然后开始一天的工作, 开发完成后,拉取中心仓库的更新, 合并代码后, 再提交至中心仓库, 结束一天的工作。 这样的好处就是不需要变更原先(使用SVN)的工作方式。当然弊端也很明显,你并不知道中心仓库的代码是否是稳定的,或者说并不能确定当你的代码和中心仓库代码合并后,是否是稳定的,带来的问题就是开发进度和回滚不那么方便控制。

Git 本地仓库和裸仓库

通常我们会用 git init 命令来将我们所在的目录转换为一个 Git 本地仓库或者初始化一个新的空仓库。 用法 将当前目录转换为一个本地仓库 git init 这个命令执行后会在本地生成一个 .git 的文件夹,用来追踪仓库的所有变更。效果如下: 指定某个目录成为本地仓库 git init <repo> 这个命令执行后, 将创建一个名为repo且只包含 .git 子文件夹的空目录。效果如下: 指定某个目录成为中心仓库(裸仓库) git init --bare <repo> 这个命令执行后,将在本地创建一个名为 repo 的文件夹, 里面包含着 Git 的基本目录, 我们一般会将这个文件夹命名为后面加 .git 的形式,如 repo.git (这也是为什么我们从 GitHub clone 仓库的时候,地址都是 xxx.git 这样的形式的原因)。效果如下: 详细说一下使用 --bare 参数的含义,使用 --bare 参数初始化的仓库,我们一般称之为裸仓库, 因为这样创建的仓库并不包含 工作区 , 也就是说,我们并不能在这个目录下执行我们一般使用的 Git 命令。 对比 我们来对比一下直接使用 git init 创建的仓库和加了 --bare 参数的两个仓库。 我们直接看两个仓库的的 config 文件中的内容: