初试k8s自顶向下的学习kubernetes

之前就玩过docker,但是一直不知道怎么把容器运用到生产上。构建一个docker镜像,把他run起来很简单;难的是容器的部署(CICD),容器的网络,数据持久化等。如果我们像之前一样,打包好镜像,通过ssh连接到目标服务器run起来,这和打包成二进制传上去似乎也没多大进步。 k8s就是帮我们解决这些难点的工具。k8s是master-node架构,通过master管理node。首先需要将你的机器组成k8s集群,集群机器的内网应该是连通的,这样你的集群就捆绑成了一个整体由k8s接管了。你只需要准备好配置文件,用k8s的api或cli(命令行)发布镜像即可,k8s会根据你配置的规则来管理容器,应用场景有:一份镜像需要部署多少个容器(replicaSets),服务的升级策略(滚动更新),服务的容灾策略(某个node挂了可以在其他node补上缺失的容器),弹性伸缩(监控CPU等指标达到临界值后自动增加容器)等。 怎么样?是不是觉得很cool,你可能迫不及待的想去把k8s用起来了,可是你打开k8s官方文档大段大段的英文和各种生疏的概念就把你整懵了。你跟着教程敲了一遍,一大堆yaml配置,全是命令行操作,可能你已经被墙给干倒了(天朝ha);还有一堆概念,什么Pod, Deployment, ReplicaSet, Service都是些啥玩意。可能你花了大半天耐心的把文档过了一遍,觉得这个东西根本落不了地啊,这一大堆配置和命令行,这谁顶得住,k8s这么先进不应该是可视化的点点就完事了吗?我一开始天真的以为k8s dashboard能帮帮我,费了点力气把它装好后,发现只有一些监控数据。 下面我想介绍另一种学习思路,自顶向下的学习。其实你一开始不用了解k8s的各种概念,只需要看看别人是怎么用k8s的就行了(都9102年了,那些很潮的公司都已经玩了很久了)。不是说学东西必须得打好基础吗?自顶向下是个什么鬼?拿学开车举例,你开始只是在路上看到别人开车,很拉风可撩妹,比两轮的安全,不怕风吹雨打的,教练我也要开车;你去报了驾校(看到这里你肯觉得我要忽悠你报培训班),你摸到了车看到别人是咋开的,了解了基本知识你就可以在训练场地慢慢蠕动了(测试环境),你甚至不用了解交规,更不用了解汽车的原理,这些后面可以慢慢补。补好基础了你就可以上路,然后你可能需要了解汽车原理,改装它优化它,再练一练排水渠过弯的技巧,成为一代老司机。 回到正题,我们学k8s同样可以先看看别人是咋用的,再去了解其中细节,掌握它。咋看呢?一大部分公司还没跟上潮流,这时我们可以借助开源和云服务。首先我们的思路没有问题,要便捷的使用k8s我们需要一个可视化管理平台。开源的有rancher、Qihoo360/wayne等,云服务阿里云、腾讯云、AWS都提供容器服务管理后台。 这里就拿rancher开始吧,毕竟开源免费。值得一提的是,阿里云等的容器服务按量积分,master可托管,弄一两天低配node,一天也就几块。 在本地启动rancher容器: sudo docker run -d --restart=unless-stopped -p 8080:80 -p 8443:443 rancher/rancher打开https://127.0.0.1:8443平台,可以看到cluster, node, namespace, member等功能。 下面我们需要准备一个k8s cluster(集群),用minikube可以方便的部署一个本地集群。minikube是通过虚拟机创建集群,支持多种虚拟机,我这里用的virtualBox。启动很简单,一个命令minikube start,困难的是墙,下面贴一下配置代理的脚本: function ministart() { export HTTP_PROXY=http://192.168.99.1:1089 export HTTPS_PROXY=http://192.168.99.1:1089 export NO_PROXY=localhost,127.0.0.1,10.96.0.0/12,192.168.99.0/24,192.168.39.0/24 minikube start \ --docker-env=HTTP_PROXY=$HTTP_PROXY \ --docker-env=HTTPS_PROXY=$HTTPS_PROXY \ --docker-env=NO_PROXY=$NO_PROXY \ --registry-mirror=https://registry.docker-cn.com}注意一下这个ip,不能使用127.0.0.1,因为虚拟机需要使用宿主的代理,虚拟机跟宿主机通讯是使用虚拟网卡创建的网段,默认宿主的ip为192.168.99.1,虚拟机是192.168.99.100。你还得把你的梯子监听的地址改改,127.0.0.1->0.0.0.0,监听所有网卡。同样rancher里的ip也应使用192.168.99.1,这个ip必需是所有集群都能访问到的,如果你是用docker自带的k8s集群,你可以用ifconfig找一个无线网或有线网的ip,反正不能使用127.0.0.1。 minikube下载一些必需镜像后,k8s集群就在虚拟机里启动了,可以使用minikube ssh登录到虚拟机里探查一番。下面我们在rancher里引入集群: 集群引入了之后我们来部署我们第一个app,一个echo-server: 等了一会儿k8s把容器部署好了,上面配置了暴露随机端口值是32192,我们访问192.168.99.100:32192就能看的echo-sever返回的信息了。我们觉得一个pod不够,点击+号,k8s会帮我们做水平扩容启动第二个pod,虽然minikube是但节点的,但是依靠容器的隔离特性,单节点照样能部署多个相同应用。 体验一下rancher的pipline功能,集成了CICD功能,配置好代码仓库后run起来,会启动一个jenkins pod来处理构建,还会建一个内置的镜像仓库,还有个minio存储pod,大概是用来存镜像的。等了好一会儿后,可以看到workloads里example-server部署好了。jenkins和registry都集成了好像挺方便,不过这个镜像如何持久化呢? ok,下面自行探索一下rancher平台提供的一些页面,有workloads,load blance,service discory,pipline这些部署常用的,还提供报警、日志、监控、用户权限等功能,这就是一个完善的k8s管理平台了,到此你应该了解k8s大概有哪些用处了。 下面你需要再把k8s官方文档捡起来看一看,或者是一本系统介绍k8s的书籍,把你在rancher上用到的功能和k8s的概念对应起来,现在你才能抓住哪些是重点。 一些概念:pod:k8s最小调度单位,可以是一个或多个容器。 service:对内或对外暴露k8s服务。 deployment:pods和replicaSets的控制器,通过deployment配置的规则来管理pods。 三个主要的命令行程序:kubeadm:用了启动k8s集群。 kubelet:需要在所以节点上运行,处理集群内部通讯,类似agent。 ...

May 27, 2019 · 1 min · jiezi

Copy攻城狮日志Docker部署D2Admin-人人企业版

Created by huqi at 2019-5-24 21:01:30 Updated by huqi at 2019-5-26 00:00:42前言最近后端的小伙伴在探索docker部署,给我也提了需求,希望我别掉链子,也能将前端服务通过docker部署。于是乎,我在大掘金找到了一篇不错的实践,@快狗打车前端团队 的 [[手把手系列之]Docker 部署 vue 项目](https://juejin.im/post/5cce4b...。出于Copy的职业本能,看完文章立马动手尝试了一下,一顿操作猛如虎,通过Docker部署了一个vue-cli生成的demo,当然,理论上来看,也就是部署了一个静态目录dist。简单的实践效果如图。介于目前项目的前端开发基于D2Admin 人人企业版,有了快狗团队的手摸手,很快就能用Docker部署这样一个后台管理平台。本文默认使用linux且安装了docker@18.09.6、node@8.9.0及git@1.8.3.1。 git clone及项目打包“巧妇难为无米之炊”,代码都没有,何谈部署?说时迟那时快,先clone一下源代码。D2Admin 人人企业版大概9.25M的样子,我的ECS配置极差,网络环境也比较差,拉取的时间稍微长一点,都吃完一片西瓜了,都还在95%的进度。当然,乳沟您本地已经打包好了请略过一下操作,还有时间可以多吃几片西瓜。一般来说在实际上线中,前端可能只要给到打包之后的文件夹就够了。 git clone https://github.com/d2-projects/d2-admin-renren-security-enterprise.gitcd d2-admin-renren-security-enterprisenpm installnpm run build这里build主要目的还是为了获取到dist目录。 构建镜像,部署静态资源这里借助docke获取nginx镜像,通nginx镜像作为基础来构建D2Admin 人人企业版镜像。 拉取nginx镜像: docker pull nginx创建nginx配置文件: mkdir nginxvi nginx/deafult.confdeafult.conf server { listen 80; server_name localhost; #charset koi8-r; access_log /var/log/nginx/host.access.log main; error_log /var/log/nginx/error.log error; location / { root /usr/share/nginx/html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }}新建Dockerfile文件: ...

May 26, 2019 · 1 min · jiezi

Flaskpython3supervisorredisdockernginx技术架构web项目docker化二

背景手里有一个web项目,代码按照前端代码库、后端代码库分别在GitHub上,分散带来的结果是,不容易持续集成,比如你可能需要很多的job去保证一个项目的正常运作,但是这个项目也不是特别大,所以尝试将代码融合,于此同时将代码docker化,用于持续部署。 技术架构原来的代码使用gunicorn+gevent+supervisor+flask+DB的架构;具体的细节如下: 本地服务器搭建了一个nginx域名服务器,里面区分PC端还是手机端;访问域名通过nginx,访问前端静态页面的内容静态页面中加载指定地址的数据,提供数据的服务由flask后端提供接口;后端提供的接口,通过访问redis缓存和mongodb数据库,返回相应的数据; docker-compose上篇文章说了flask项目是怎么拆分和组合的,但是上次仅仅是使用docker,多个容器之间使用的--link连接起来的,本篇文章将介绍如何使用docker-compose代替原来的多个docker命令; docker compose是什么可以自行搜索,我直接上我的docker-compose.yml version: '3' services: flask: image: "flask:latest" restart: always depends_on: - mongoDB - redisDB tty: true stdin_open: false environment: SLEEP_SECOND: 10 container_name: flask logging: driver: "json-file" options: max-size: "200M" max-file: "10" command: "gunicorn manage:app -k gevent -w 4 -b 0.0.0.0" volumes: - $HOME/logs:/app/logs networks: - inline-network ports: - "8000:8000" matrix: image: "flask:latest" restart: always depends_on: - mongoDB - redisDB tty: true stdin_open: false environment: SLEEP_SECOND: 10 container_name: matrix command: "flask matrix" volumes: - $HOME/logs:/app/logs - /etc/localtime:/etc/localtime networks: - inline-network broadcast: image: "flask:latest" restart: always depends_on: - mongoDB - redisDB tty: true stdin_open: false environment: SLEEP_SECOND: 10 container_name: broadcast command: "flask broadcast" volumes: - $HOME/logs:/app/logs - /etc/localtime:/etc/localtime networks: - inline-network redisDB: image: "redis:latest" container_name: redis restart: always networks: inline-network: aliases: - redis ports: - "6379:6379" mongoDB: image: "mongo:latest" restart: always container_name: mongo ports: - "27017:27017" volumes: - /var/lib/mongo:/data/db networks: inline-network: aliases: - mongo networks: inline-network: driver: "bridge" ```解释:所有的启动的dontainer都在inline-network网络环境中,所以可以直接使用aliases指定的名字作为数据库连接时候的host,本来是不打算将数据库的端口的,只给flask用,但是后面由于切换的时候是现切换数据库,在切换后段flask的镜像,所以就将数据库端口和宿主机绑定了。其中flask、matrix、broadcast,都是之前代码中的功能,使用supervisor启动的,现在单独启动三个docker进程去完成。前端docker前端的PC端和移动端,都使用npm构建成dist文件,然后通过nginx定向到指定的dist文件内容就可以,所以我们对前端的代码也进行了docker化,使用的是nginx; ...

May 25, 2019 · 2 min · jiezi

kubernetes-Admission-Controller-原理介绍

Admission Controller介绍Apiserver干的最重要的三个事就是: 认证 : 看是否是合法用户授权 : 看用户具备哪些权限admission controller : 一个调用链,对请求进行控制或修改,比如是否允许这个请求。admission controller非常有用,也是经常会用到的k8s的一个扩展方式,今天在源码级别对其做一下介绍,以及如何自己去开发一个admission controller. 我们的应用场景是:我们希望把所有需要创建的pod都加上一个注解,因为我们早期是通过podpreset给pod注入lxcfs的配置的,但是用户在写yaml文件时很容易忘记加上,所以需要在apiserver上来个自动处理 metadata: name: test-net annotations: initializer.kubernetes.io/lxcfs: "true" # 就是在pod的metadata里加上这个配置默认admission controller已经有很多默认非常有用的admission插件,这里挑几个介绍一下: 名称作用AlwaysPullImages把所有镜像策略都调整成alwaysPull, 多租户安全时比较有用DefaultStorageClass默认存储类型DefaultTolerationSeconds节点notready:NoExecute时的容忍时间,比如有时我们升级kubelet,希望升级时pod不要漂移就会用到DenyEscalatingExec拒绝远程连接容器ExtendedResourceToleration比如我有扩展资源,那么我可以通过它来玷污节点,防止不需要该资源的pod到我的机器上来,如GPULimitRanger在多租户配额时相当有用,如果pod没配额,那么我可以默认给个很低的配额NamespaceAutoProvision这个也非常有用,资源的namespace不存在时就创建一个PodPreset可以对pod进行一些预处理设置ResourceQuota多租户配额时比较重要,看资源是否满足resource quota中的配置alwaysPullImages 介绍多租户时经常会开启这个,强制所有的镜像必须去拉取,因为如果不这样,那么别的租户如果知道了你的镜像名就可以写一个yaml去启动你的镜像,强制拉时犹豫需要image pull secret所以无法拉取你的镜像。 所以这个admission干的事就是把镜像拉取策略都改成alwaysPull: 代码位置: kubernetes/plugin/pkg/admission/alwayspullimages/admission.gofunc (a *AlwaysPullImages) Admit(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) { // 你可以在attibutes里获取到对象的一切信息,用户信息等 if shouldIgnore(attributes) { // 检查一下是不是你关注的object, 比如创建的一个configmap 那么显然可以忽视 return nil } pod, ok := attributes.GetObject().(*api.Pod) // 这里把initContainer和Container的拉取策略都给改了 for i := range pod.Spec.InitContainers { pod.Spec.InitContainers[i].ImagePullPolicy = api.PullAlways } for i := range pod.Spec.Containers { pod.Spec.Containers[i].ImagePullPolicy = api.PullAlways } return nil}# 还提供一个校验接口,看是不是真的都已经被改了func (a *AlwaysPullImages) Validate(attributes admission.Attributes, o admission.ObjectInterfaces) (err error) { pod, ok := attributes.GetObject().(*api.Pod) for i := range pod.Spec.InitContainers { if pod.Spec.InitContainers[i].ImagePullPolicy != api.PullAlways { return admission.NewForbidden(attributes, field.NotSupported(field.NewPath("spec", "initContainers").Index(i).Child("imagePullPolicy"), pod.Spec.InitContainers[i].ImagePullPolicy, []string{string(api.PullAlways)}, ), ) } } ... return nil}然后实现一个注册函数: ...

May 24, 2019 · 2 min · jiezi

宜信开源一个实例解析PaaS平台LAIN的9大杀手级功能

一、基于Docker的PaaS平台LAIN在金融的场景下,LAIN 是为解放各个团队和业务线的生产力而设计的一个云平台。LAIN 正式上线已经大约两年,基本已经成熟,为宜信大数据创新中心各个团队提供了统一的测试和生产环境,简化了服务的部署与上线流程,也降低了运维人员对系统管理的复杂度。 LAIN 规范了一个应用的开发、测试、上线工作流,提供了为应用做的容器编排、权限控制、SDN、流量管理、监控报警、备份、日志等 devops 问题的整体解决方案。(扩展阅读:宜信开源|详解PaaS平台LAIN的功能和架构) 在 LAIN 上,应用是一个基本的概念,某个应用的开发者只需要定义一个 lain.yaml 即可定义应用的编译和运行方式,对应用代码侵入性很低。LAIN 基于容器技术,面向多样化的技术栈,并且天然隔离系统和应用的依赖。 当 LAIN 用户创建一个应用(服务)时,可以到 LAIN 上注册该应用,当前的用户自动成为了该应用的维护者,拥有了进一步操作该应用的权限。构建应用的环境需要 docker 和 lain 命令行工具,为了方便,我们创建了一个 vagrant box 即 lain-box. 在构建应用时,除了工程代码外,还需要一个 Docker 镜像作为基础镜像,即编译的环境。如果是二进制的工程,如 golang,则可以在运行时换掉一个底,否则会使用 build 镜像为 release 镜像。准备好镜像和编译/运行的脚本后,就可以编辑 lain.yaml 了。 具体来说,lain.yaml 主要做了如下四件事: 1、应用名称的确定,体现一个应用的边界 2、应用的基础技术栈,即编译和运行的镜像 3、构建过程(如何编译) 4、微服务拆分及服务内部配置(如何运行、运维) 关于第4点,LAIN 上有一个 Proc 的概念,即每个应用都有一个或多个 Proc,Proc 在应用内有唯一的名字和类型,Proc 在底层对应于一组容器,一个应用之间的各个 Proc 的各个容器的网络是互通的,所以应用就是可以互相信任的几个 Proc,对外表现为现实中的某项功能。Proc 的类型是 LAIN 内置的,worker 类型是最简单的类型,LAIN 处理其它的 Proc 类型会做一些额外的事情。 在应用的层面上,LAIN 除了用 lain.yaml 将一个应用的依赖和行为固化外,还有以下几大亮点: 1、SDN 网络安全隔离 使用 calico 项目构建 SDN 网络高效率的应用内网络互通应用间网络默认隔离显式声明应用间的服务互访2、应用权限的控制 ...

May 23, 2019 · 2 min · jiezi

宜信开源详解PaaS平台LAIN的功能和架构

LAIN是宜信公司大数据创新中心开发的开源PaaS平台。在金融的场景下,LAIN 是为解放各个团队和业务线的生产力而设计的一个云平台。LAIN 为宜信大数据创新中心各个团队提供了统一的测试和生产环境,简化了服务的部署与上线流程,也降低了运维人员对系统管理的复杂度。 一、设计理念及解决问题LAIN 规范了一个应用的开发、测试、上线工作流,提供了为应用做的容器编排、权限控制、SDN、流量管理、监控报警、备份、日志等 devops 问题的整体解决方案。 在 LAIN 上,应用是一个基本的概念,某个应用的开发者只需要定义一个 lain.yaml 即可定义应用的编译和运行方式,对应用代码侵入性很低。LAIN 基于容器技术,面向多样化的技术栈,并且天然隔离系统和应用的依赖。 当 LAIN 用户创建一个应用(服务)时,可以到 LAIN 上注册该应用,当前的用户自动成为了该应用的维护者,拥有了进一步操作该应用的权限。构建应用的环境需要 docker 和 lain 命令行工具,为了方便,我们创建了一个 vagrant box 即 lain-box. 在构建应用时,除了工程代码外,还需要一个 Docker 镜像作为基础镜像,即编译的环境。如果是二进制的工程,如 golang,则可以在运行时换掉一个底,否则会使用 build 镜像为 release 镜像。准备好镜像和编译/运行的脚本后,就可以编辑 lain.yaml 了。 具体来说,LAIN 解决了以下四个问题: 1、应用开发之下的devops问题的整体解决方案常见问题 面对用户的应用级开发仅仅是冰山一角,在此之下有机房、网络、服务器、系统管理、运维管理、监控、告警、日志等等一系列背后的工作,而这部份的工作可能比应用级开发还要复杂采用IaaS解决了服务器采购和上架问题,但是依然需要一个强大的devops团队来负责上述事务,否则基础设施很容易成为发展瓶颈,且越拖越难解决上面的这些工作对于每一个产品可能都是同质化但又伴随着定制,会消耗大量的时间做这些重复的工作Lain是怎么做的 直接在几乎裸的IaaS或者服务器上即可构建lain集群,方便地进行在线的扩容缩容等集群底层资源操作整合了业界沉淀下来的良好的运维整体实践,提供了冰山下的这一大块工作的整体解决方案将纷繁复杂的系统管理和运维管理行为封装为更简单易用的工具包,极大简化大部分的系统工作,降低日常维护的技术门槛和人力需求将同质化的工作整合在一起,避免重复劳动开箱即用的各种管理组件,囊括了部署,扩容,监控,告警,日志等方方面面。还有附赠应用,包括mysql,redis的集群服务2、规范了应用开发的工作流程,并辅以适当的SCM支援常见问题 在个人开发者以及startup组织中,良好的工作流这件事几乎是不会被提及的,然而在日渐发展的过程中遗留的技术债务却会越来越多的影响开发部署的效率和质量设计、开发和部署行为的不规范会引发各种问题Lain是怎么做的 提供本地开发环境的解决方案提供本地开发过程的SDK / CLI工具链,使得开发和构建过程是嵌入在解决方案中的隐性的提供了SCM支援,约束了开发者的开发和发布行为3、提高整体资源利用率,优化冗余资源池常见问题 传统的按照产品线规划资源池的情况下,会给各产品预留专属的资源池以及配备冗余,以便进行灾备以及服务突发流量然而各产品线的资源需求类型不同,冗余类型也不同,无法共通共享,造成众多的重复冗余,资源利用率比较低通过服务器资源的冗余,扩容缩容,以及资源迁移的操作比较复杂,时间消耗大,风险高Lain是怎么做的 通过容器技术的资源隔离和控制,实现多种技术栈多种应用在集群内安全的不相互影响的混合部署,通过统一的资源池进行冗余,有效提高资源利用率容器技术的运用使得对下资源的使用形成完全统一的形式,扩容缩容以及迁移的成本很低,操作也更简单。4、TBD:架构上提供了服务治理的可能性和解决方案二、特征在应用的层面上,LAIN 还有以下特征: 1、基于配置文件定义应用 在现有的应用上只需要增加一个配置文件lain.yaml即可定义应用在lain集群里的编译和运行对应用代码的侵入性很低2、SDN网络安全隔离 使用开源的calico(https://github.com/projectcal...高效率的应用内网络互通应用间网络默认隔离显式声明应用间的服务互访3、基于容器技术支持多样化的技术栈 使用开源的docker项目构建容器云扩展封装Dockerfile,使用自定义的yaml格式进行应用的集群定义只需符合最简单的lain cluster runtime interface,可自由选择base image容器技术天然的支持隔离系统和应用的依赖 lain SDK / CLI以及可选的ci组件支援代码版本和镜像之间的对应关系编译时和运行时镜像均可完全定制和隔离4、应用在线扩容缩容 使用开源的swarm调度应用部署深度封装swarm docker API,自行开发集群控制器(deployd)以及应用控制器(console) 直接支持用户API调用进行容器实例数扩容,缩容直接支持用户API调用进行容器单实例资源的扩容,缩容(CPU,MEM)5、节点在线扩容缩容 使用开源的ansible(https://github.com/ansible/an...集群的服务器节点(NODE)兼容同一个C段内的物理服务器,虚拟机,公有云服务器集群管理工具包支持add NODE 和 remove NODE 指令,快速进行底层资源扩容和缩容6、服务自动维持和灾难恢复 ...

May 23, 2019 · 1 min · jiezi

在Linux系统中快速搭建NFS服务的新途径

也许各位朋友看到这个标题会觉得很奇怪,会问:在Linux中搭建NFS网络存储服务有多难?小菜一碟。也许对给位老手来说这是一件再简单不过的事,但是,这里给到大家的是一个全新的,能一键部署NFS服务的方案,感兴趣的朋友不妨了解一下。 这里的方案就是通过URLOS一键部署NFS,话不多说,直接开始: 打开URLOS系统后台,在应用市场中搜索“nfs”,点击安装:填写服务名称其实也没有什么需要设置的,点击提交即可。写到到这里,我们已经将nfs服务部署完,是的,就是这么快! 下面是演示如何挂载nfs共享存储,首先在别的机器上安装nfs客户端工具 root@ubuntu:/# apt-get install -y nfs-common安装完成后在根目录下新建一个目录nfsdir root@ubuntu:/# mkdir nfsdir在用以下命令挂载nfs root@ubuntu:/# mount 192.168.43.121:/ /nfsdir/192.168.43.121:/即我们刚才部署的nfs服务器,以上的意思就是将nfs服务器的根目录挂载到该机器的nfsdir目录。 我们在该机器创建一个文件a.txt,然后在urlos主控面板可以查看到该文件,说明共享存储服务生效了 root@ubuntu:/# cd nfsdir/root@ubuntu:/nfsdir# lsa.txt

May 23, 2019 · 1 min · jiezi

FastDFS-Docker化部署-以及-Java-SpringMVC实践

简介FastDFS是一个轻量级分布式文件系统。可以对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,而且可以集群部署,有高可用保障。相应的竞品有Ceph、TFS等。相比而言FastDFS对硬件的要求比较低,所以适合中小型公司。 概念FastDFS服务端由两个重要部分组成:跟踪器(Tracker)和存储节点(Storage)。 Tracker主要做调度工作,在访问上起负载均衡的作用。Tracker可以做集群部署,各个节点之间是平等的,客户端请求时采用轮询机制,某个Tracker不能提供服务时就换另一个。Storage启动后会连接到Tracker Server告知自己的Group信息,形成映射关联,并采用心跳机制保持状态。Storage存储节点负责文件的存储,Storage可以集群部署。 Storage集群有以下特点: 以组(Group)为单位(也有称呼为卷 Volume的),集群的总容量为所有组的集合。一个卷(组)内storage server之间相互通信,文件进行同步,保证卷内storage完全一致,所以一个卷的容量以最小的服务器为准。不同的卷之间相互不通信。当某个卷的压力较大时可以添加storage server(纵向扩展),如果系统容量不够可以添加卷(横向扩展)。上传流程此章节根据资料整理,可能随着版本有所改变,这里只介绍大致的,以便了解整个运作流程。如果需要深入研究,建议还是以官方文档为标准。 一,客户端请求会打到负载均衡层,到tracker server时,由于每个server之间是对等的关系,所以可以任意选择一个tracker server。 二,到storage层:tracker server接收到upload file请求时,会为该请求分配一个可以存储该文件的group。 分配group规则: Round robin 轮询Specified group 指定一个groupLoad balance 剩余存储空间多的group优先三,确定group后,tracker会在group内选择一个storage server给客户端。 在group内选择storage server时规则: Round robin 轮询First server ordered by ip 按ip排序First server ordered by priority,按优先级排序(优先级在storage上配置)四,选择storage path:当分配好storage server后,客户端向storage发送写文件请求,storage将会为文件分配一个数据存储目录,支持规则如下: round robin 轮询剩余存储空间最多的优先五,生成File id:选定存储目录之后,storage会为文件生成一个File id。规则如下: 由storage server ip、文件创建时间、文件大小,文件crc32和一个随机数拼接而成,然后将这个二进制串进程base64编码,转换为可打印的字符串。六,选择两级目录:每个存储目录下有两级256 * 256的子目录,storage会按文件Field进行两次hash,路由到其中的一个目录,然后将文件以file id为文件名存储到该子目录下。 一个文件路径最终由如下组成:组名/磁盘/目录/文件名 七,客户端upload file成功后,会拿到一个storage生成的文件名,接下来客户端根据这个文件名即可访问到该文件。 下载流程下载流程如下: 一,选择tracker server:和upload file一样,在download file时随机选择tracker server。 二,选择group:tracker发送download请求给某个tracker,必须带上文件名信息,tracker从文件名中解析出group、大小、创建时间等信息,根据group信息获取对于的group。 三,选择storage server:从group中选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到的时候,文件还没有同步到某些storage server上,为了尽量避免反问道这样的storage,tracker按照一定的规则选择group内可读的storage。 文件HTTP预览服务Storage还可以结合nginx的fastdfs-nginx-module提供http服务,以实现图片等预览功能。 这个部分这里不做介绍,后续可能单独写篇文章,因为我发现对fastDFS集群提供http服务还是挺复杂,包括我下面找的docker镜像都不完善,主要是规划的问题,包括衍生的服务,缓存,以及对图片的处理(nginx+lua)这些,后续打算研究下,重新开源个docker构建镜像。 ...

May 23, 2019 · 2 min · jiezi

Docker-入门一基础使用

查看docker版本,确认docker已正确安装 $ docker --versionDocker version 18.09.2, build 6247962 1.查看images(镜像)$ docker images拉取一个ubuntu images $ docker pull ubuntu默认拉去最新版本的ubuntu镜像,当然也可以指定ubuntu $ docker pull ubuntu:16.04「:」之后的数字为镜像版本;拉取成功后该数字即为镜像的tag(标签):lastest、16.04 2.进入ubuntu镜像首先查看我们的拉取的镜像: $ docker images 输出: REPOSITORY TAG IMAGE ID CREATED SIZEubuntu latest 7698f282e524 6 days ago 69.9MBubuntu 16.04 2a697363a870 6 days ago 119MBubuntu即为我们刚拉取的镜像,继续执行:$ docker run -i -t ubuntu 若TAG不是latest,需要带上TAG:$ docker run -i -t ubuntu:16.04 -i:以交互模式运行容器,通常与 -t 同时使用 -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用 成功进入Ubuntu终端 3.安装 nvm 与 node更新apt: $ apt-get update ...

May 22, 2019 · 1 min · jiezi

Docker-配置阿里云的Docker镜像加速器

进入阿里云控制台 => 容器镜像服务 => 镜像中心 => 镜像加速器 => 查看加速器地址: https://这里是你的地址.mirror.aliyuncs.com1.Ubuntu安装docker-ce # step 1: 安装必要的一些系统工具sudo apt-get updatesudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common# step 2: 安装GPG证书curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -# Step 3: 写入软件源信息sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"# Step 4: 更新并安装 Docker-CEsudo apt-get -y updatesudo apt-get -y install docker-ce配置镜像加速器 修改daemon配置文件/etc/docker/daemon.json来使用加速器 # sudo mkdir -p /etc/docker# sudo tee /etc/docker/daemon.json <<-'EOF'{ "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]}EOF# sudo systemctl daemon-reload# sudo systemctl restart docker2.Mac安装/升级Docker客户端 ...

May 22, 2019 · 1 min · jiezi

Mac-开发环境配置

引言本周收到了新的Mac mini,感谢潘老师。 然后开始了安装开发环境的生涯,相较于Linux和Windows,还是挺简单的。 配置学习软件微信、钉钉、印象笔记,少哪个都不行。 这里向大家推荐印象笔记,真的是学习神器,一键收藏最好用。 微信、知乎推荐的文章,虽然写得也挺好,但大都是标题党,点开看又占用时间打断思路,不看又怕错过什么好文章。 现在好了,管他什么标题党,直接收藏到笔记里,有时间再看。 docker之前起环境,都是装软件,搜命令。经过上次潘老师的指点,决定以后的环境都使用docker启动。 不得不说,docker是个好东西。 尤其是在docker又推出了Mac版的Kitematic之后,可以图形化管理docker容器。目前只有Mac版,但docker官方说目前正在开发其他平台版本。 需要什么容器直接在商店里搜索,点击CREATE在本地创建容器。 可以对容器进行管理,设置,以及端口映射。 就拿这个redis来举例,直接把容器中的6379端口映射为我本机的6379端口,看起来就像我本机装了redis一样。 Java最开始是想用docker起java然后映射到本地文件夹的,后来发现去Google搜索好像没有这么干的,就直接改用Homebrew安装了。 Homebrew也很简单,就官网的一条命令就安装成功了。 brew cast install java默认装的Java 12,Ctrl + C终止。 brew cask intall java8报错了,说java8不可用,没有这个名字相关的软件。 用Google查到了Homebrew官方仓库里的issue。看说话的语气像是官方人员,大体意思就是:Oracle Java8已经收费了,让我们把Oracle Java8删了,然后再加一个免费版本的Java8进来。 brew cask install adoptopenjdk8最终解决方案就是安装官方提供的免费版本,OpenJDK。 录屏软件之前录屏都是用的QQ里自带的录屏功能,录完了是mp4,文件特别大。潘老师推荐用LICEcap。 测试了一下,确实比QQ带的要好用,录完是gif,文件没那么大,并且可以控制每秒多少帧。 感慨5G时代,挑战美国的技术垄断是必然的。 如今正值多事之秋,中美贸易战,失去了美国的技术支持,华为各项备用技术转正,自主研发。 爱国不是买华为。 作为一个平凡的程序员,或许不能为国家作出多大的贡献。 但面对美国法律对Github的技术垄断,或许我写不出什么核物理的控制项目,也写不出什么机器学习的优秀模型,但我会尽我所能,写出更多国人的开源项目。 中国加油!

May 22, 2019 · 1 min · jiezi

1构建docker的flask镜像

基于alpine镜像构建自己的flask镜像python官方镜像地址: http://hub.docker.com/_/python 拉取官方的python镜像 docker pull python:3.7-alpine交互式方式生成一个python容器 docker run -it --name python37 --rm python:3.7-alpine /bin/sh进入交互式容器,查看当前python版本 python --version设置pip的阿里云镜像源 mkdir $HOME/.pip/tee $HOME/.pip/pip.conf <<-'EOF'[global]trusted-host=mirrors.aliyun.comindex-url=https://mirrors.aliyun.com/pypi/simpleEOF确认一下是否配置成功 cat $HOME/.pip/pip.conf我们的python使用的是alpine系统 alpine使用的是apk包管理器 命令如: apk addapk updateapk delalpine默认的镜像源也比较慢,我们也换成国内的 设置alpine镜像源 echo http://mirrors.ustc.edu.cn/alpine/v3.7/main > /etc/apk/repositoriesecho http://mirrors.ustc.edu.cn/alpine/v3.7/community >> /etc/apk/repositories设置后要执行 apk update && apk upgrade安装flask python -m pip install -U flask编写test.py from flask import Flaskapp = Flask(__name__)@app.route('/')def hello(): return 'Hello World!'@app.route('/abc')def abc(): return 'Hello abc'if __name__ == '__main__': app.run()第一种执行这个py文件方式 python test.py然后在另一个终端以交互式方式进入这个python容器 ...

May 22, 2019 · 1 min · jiezi

13使用Docker-Compose-实现nginx负载均衡

以Docker的网络管理,容器的IP设置为基础知识实现Nginx负载均衡查看所有docker网络 docker network ls/*NETWORK ID NAME DRIVER SCOPEb832b168ca9a bridge bridge local373be82d3a6a composetest_default bridge locala360425082c4 host host local154f600f0e90 none null local*/// composetest_default 是上一篇介绍Compose时,docker-compose.yml文件所在的目录名,// 所以,用docker-compose创建的容器会默认创建一个以目录名为网络名的网络,并且是dridge(桥接)类型指定容器IP地址 官网文档地址:https://docs.docker.com/compo... 继续编写上一篇《12.使用Docker Compose容器编排工具》文章中的docker-compose.yml version: "3"services: web1: container_name: web1 image: "centos:httpd" ports: - "8080:80" privileged: true volumes: - "/app/www/web1/:/var/www/html/" command: ['/usr/sbin/init'] networks: nginx-lsb: ipv4_address: 192.169.0.3 web2: container_name: web2 image: "centos:httpd" ports: - "8081:80" privileged: true volumes: - "/app/www/web2/:/var/www/html/" command: ['/usr/sbin/init'] networks: nginx-lsb: ipv4_address: 192.169.0.2networks: nginx-lsb: driver: bridge ipam: config: - subnet: 192.169.0.0/16使用docker-compose启动容器 ...

May 22, 2019 · 2 min · jiezi

nagios使用nrpe监控磁盘遇到的问题

问题描述nagios配合nrpe用来监控机器中运行项目的具体情况,还包括磁盘、网络、负载均衡和数据库等具体的使用情况; 我遇到的问题: 使用docker-compose替换原来项目,将所有的进程docker化;创建的docker镜像和docker-compose创建的containers都在/var/lib/docker目录下;在使用docker-compose up的时候,出现警报 XXXXX(inode=-9999%)/var/lib/docker/containers/mounts=6037182531735MB;4830712380730;5434551428321;0;6038390475913解决的过程遇到的坑解决的思路: 首先想的是既然报磁盘没有空间的错误,那就需要看这个目录到底是谁占用了这么多的空间:查看的时候发现,/var/lib/docker/目录没有权限,不能查看,所以我一路开权限,然后chmod,知道看到的结果是征程很正常接着因为权限打开,警报消除,但是当我重新docker-compose up的时候,加入新的镜像,又出现这个问题;无解想通过忽略指定的文件,让他消失在我的眼前,于是找到了-i ·regex·;但是当我修改之后,出现了Unknown告警;无解。。。。。 通过查看我的磁盘使用情况,并没有发现有什么不妥,而且,command[check_disk]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p /dev/vda1,看起来也没有问题哦; 是不是/dev/vda1/有问题,于是command[check_disk]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p /dev/vda1 -i '/dev/vda1/var/lib/dockder/',但是也不行最终解决的方法```command[check_disk]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p / -i '/var/lib/dockder/'```这个命令OK,生效了!为什么呢?你可以想一下,我今记录一下我的解决问题的过程。

May 21, 2019 · 1 min · jiezi

Rainbond-514发布复杂微服务架构整体升级和回滚

Rainbond 5.1.4发布, 复杂微服务架构整体升级和回滚 今天为大家带来Rainbond 5.1系列第四个更新版本,本次版本更新的主要内容是复杂微服务架构应用整体升级和回滚,能实现复杂微服务架构的持续交付,和复杂架构企业级应用快速交付和升级,另外还有一些小的优化和BUG的修复。 Rainbond是开源的企业应用云操作系统,支撑企业应用的开发、架构、交付和运维的全流程,通过无侵入架构,无缝衔接各类企业应用,底层资源可以对接和管理IaaS、虚拟机和物理服务器。 复杂微服务架构应用整体升级和回滚 面对复杂的微服务架构,微服务组件可能几十个,服务之间存在业务依赖;微服务的版本管理复杂;开发测试流程低效,针对以上问题,单个微服务管理的模式已经不适用,需要考虑微服务架构整体管理。这次的更新能实现复杂微服务架构的整体版本,微服务独立开发,测试环境和生产环境整体升级和回滚,升级的过程只更新变化的服务和配置,过程滚动更新,实现业务不间断升级。 升级和回滚的过程通过Rainbond应用市场实现,Rainbond应用市场定义了一种对应用的存储、共享、交付、管理途径. Rainbond应用市场与传统意义上的镜像仓库不同之处在于,它基于镜像仓库、包仓库和对象存储等存储系统支持,定义了支持大型、分布式数字化业务系统的标准云原生应用模型,并针对应用模型提供创建、发布、存储、交付、安装、升级等一系列业务支持,对内可作为以便捷灵活的方式共享企业创造的业务系统、中间件的业务性管理平台,对外可作为根据行业特性构建行业话交付标准、交付流程和交付路径的基础,应用市场的最大优点在于它涵盖的不仅是服务组件和应用(业务系统),甚至于解决方案都可以支持一键分享、一键安装使用,极大的便利用户,只需安装使用,使用者不需要懂技术。 在5.1.4之前, rainbond仅仅支持对云市应用中单个服务的升级, 如果想要升级整个云市应用, 则需要单独地对每个服务进行升级, 且无法升级新添加的服务. 这给各位用户的使用带来了极大的不便. 为了让用户有的操作更加的简单, 提高使用体验, 我们在5.1.4版本中, 对应用市场进行了改造升级. 功能特性 灵活的升级方式: 可以自由地选择需要升级的服务, 可以全部升级也可以部份升级.创建新添加服务: 除了可以升级已有的服务外, 还可以创建旧版本没有, 但是新版本有的服务.详细的变更信息: 在升级界面中, 可以查看当前版本与新版本服务之间属性的变更.详细的升级记录: 对每次升级操作, rainbond都进行了详细的记录, 包括: 升级操作的时间, 版本号的变更和各服务属性的变更信息等.自动回滚: 在应用升级的过程中, 如果程序发生了异常, 会回滚到升级前的状态, 避免只升级部分属性或服务.手动回滚: 升级成功后, 如果新版本有缺陷导致各个服务无法正常工作, 或者你更倾向升级前的版本, 那么可以选择手动回滚, 回到之前的版本.简单的演示 更详细的说明, 请参考: 服务升级文档 其他改进 第三方服务新添加实例地址时, 允许地址中带有端口镜像服务支持修改镜像仓库帐号, 密码等信息grctl命令行工具增加身份属性gateway将自定义网关策略的域名以环境变量的方式注入到服务中(相关文档)将环境变量,配置文件等配置信息综合为环境配置分享应用时支持定义不分享的服务支持服务链接信息和环境变量的相互转移关闭或重启服务时, 增加二次确认, 防止误操作安装方面: 优化安装时初始化数据中心流程优化调整安装任务结构,调整离线镜像文件路径支持调整网络类型优化部分组件配置参数优化安装过程中宿主机IP段与容器ip段冲突问题BUG修复 【重要】修复了关闭服务时, pod无法被删除或删除需要花费比较多时间的问题【重要】修复了多管理节点中, 某个节点rbd-hub服务异常了,但gateway没有将其下线导致goodrain.me服务异常的问题修复了第三方服务的网关访问策略控制错误修复了删除端口报系统异常的错误修复了编辑HTTPs网关策略, 无法勾选 HTTP rewriet HTTPs 的问题修复了更改构建源后无法重新检测语言的错误修复了无法修改健康检测参数的错误修复了云市应用版本号显示不全的问题修复了添加镜像服务时, 没有高级选项按钮的问题修复了构建源中镜像Tag显示不全的问题修复了创建应用时勾选的是有状态应用,创建成功后却是无状态应用的问题修复了无法将无状态应用修改为有状态应用的问题修复了禁止调度计算节点后, 导致可用资源统计错误的问题修复了第三方服务TCP访问策略状态错误且无法操作的问题修复了网关策略参数配置中Websocket不生效的问题修复了云市应用导出的docker-compose.yaml中的镜像有误的问题修复了环境变量名格式验证有误的问题, 支持带"."的环境变量名安装和升级 ...

May 21, 2019 · 1 min · jiezi

5Compose编排nginxphp

上一篇的手工操作多容器运行nginx+php,很麻烦,该怎么办?Docker Compose 跟上先删掉上篇创建的容器和网络,如若不然,完成本章会产生冲突 docker stop nginxdocker stop fpm docker network rm lnmp先将上节手工运行的nginx容器命令拿过来作为编写docker-compose.yml文件的参考: docker run -d --network lnmp --ip 192.169.0.3 --link fpm:php --name nginx --rm -p 80:80 -v ~/www:/usr/share/nginx/html -v ~/nginx.conf:/etc/nginx/nginx.conf nginx:1.15.0-alpine继续编辑前面章节创建的 mycompose/docker-compose.yml文件 version: "3"services: fpm: container_name: fpm image: "php:7.1-fpm-alpine3.8" volumes: - ~/www:/php networks: lamp: ipv4_address: 192.158.0.2 httpd: container_name: httpd image: "httpd:2.4-alpine" ports: - 8080:80 links: - fpm:php volumes: - ~/www:/usr/local/apache2/htdocs - ~/httpd.conf:/usr/local/apache2/conf/httpd.conf networks: lamp: ipv4_address: 192.158.0.3 nginx: container_name: nginx image: "nginx:1.15.0-alpine" ports: - 8081:80 links: - fpm:php volumes: - ~/www:/usr/share/nginx/html - ~/nginx.conf:/etc/nginx/nginx.conf networks: lamp: ipv4_address: 192.158.0.4networks: lamp: driver: bridge ipam: config: - subnet: 192.158.0.0/16docker-compose启动项目 ...

May 21, 2019 · 1 min · jiezi

8通过Python连接Docker进行编程

Docker其实有两个重要的概念:"Docker客户端"和"Docker守护进程" Docker服务端提供了一系列REST API (Docker Remote API),当我们敲docker命令时实际上是通过API和Docker服务端进行交互的。我们可以自己编写Docker客户端,调用REST API 和Docker服务端进行交互。 Docker官方提供了Python和Go的SDK,当然我们可以自己用熟悉的语言调用REST API的方式。 官方文档地址: https://docs.docker.com/devel... Docker官方提供的连接方式: unix:///var/run/docker/socktcp://host:portfd://docketfd默认不支持远程访问 配置远程访问 vi /usr/lib/system/docker.service// 把原本是下面这一行注释掉ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock// 添加如下这一行ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock// 然后保存后,重启Dockersystemctl daemon-reloadsystemctl restart docker// 重启之后查看一下docker的守护进程,确认是否配置成功ps -ef | grep dockernetstat -anput | grep docker// 开启远程访问端口iptables -I INPUT -p tcp --dport 2375 -j ACCEPT // 确保防火墙放行2375端口// 阿里云的ECS上部署的Docker,还需在安全组规则添加入方向、tcp、2375端口的开通// 使用本地测试连接通过Python连接Docker测试 # 通过pip安装docker sdkpip install dockerimport docker# 需要修改对应的Docker服务器IP地址client = docker.DockerClient(base_url='tcp://Docker服务器的IP:2375')# 获取所有镜像列表,相当于docker cli方式执行 docker imagesimages = client.images.list()print(images) # 打印结果: [<Image: 'centos:httpd'>, <Image: 'centos:latest'>]# 获取镜像idprint(images[0].id) # 打印结果:sha256:3ac6dda7648810e447c94fb9f919f6c2cfa97410935e60894ef94ea6e5e4d2d3# 这里发现镜像id比直接使用docker cli方式执行 docker images获取的镜像id长,# docker里面的各种镜像id、容器id都只要能确定唯一性就行了这里只是通过自己写的程序连接Docker进行编程的一个实例,可以帮助我们理解Docker的管理工具的工作原理。 ...

May 18, 2019 · 1 min · jiezi

1CentOS7上安装Docker

Docker越来越流行,这是Docker起步第一篇,跟着一起来吧安装依赖 yum install -y yum-utils device-mapper-persistent-data lvm2设置docker的yum仓库 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo安装之前可以查看所有仓库中所有的docker版本 sudo yum list docker-ce --showduplicates | sort -r不想选的话,就默认安装 sudo yum install docker-ce -y启动docker sudo systemctl start docker设置开机启动 sudo systemctl enable dockerdocker安装时默认创建了docker用户组,将普通用户加入docker用户组就可以不使用sudo来操作docker了。 sudo usermod -aG docker 用户名改变当前用户的有效群组 newgrp - docker文章首发至我的博客:http://www.mi360.cn/articles/6

May 18, 2019 · 1 min · jiezi

2配置阿里云的docker镜像源

仓库镜像,可以理解为别人帮你制作好的环境。让你可以直接使用。Docker镜像仓库地址: https://hub.docker.com 由于有墙,所以配置国内镜像,我们使用阿里云的镜像地址 https://dev.aliyun.com/search... // 配置使用阿里云镜像加速器sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-'EOF'{ "registry-mirrors": ["https://md4nbj2f.mirror.aliyuncs.com"]}EOF// 重载配置文件sudo systemctl daemon-reload // 重启docker sudo systemctl restart docker 文章链接:http://www.mi360.cn/articles/7

May 18, 2019 · 1 min · jiezi

github上Go项目使用Travis-CI和Docker-Hub实现持续集成

介绍在本文中,我们将介绍如何使用Github,Travis-CI和Docker Hub创建一个简单的持续集成过程。 项目这次使用的一个项目是自己写的一个爬虫小程序(https://github.com/Han-Ya-Jun... 项目目录news_watch_notice├── cmd //main├── conf├── dis├── Dockerfile├── Makefile├── pkg├── qrcode├── .travis.yml├── README.md├── vendor├── utilsDockerfileFROM alpine:3.6MAINTAINER hanyajun0123@gmail.comRUN apk update && apk add curl bash tree tzdata \ && cp -r -f /usr/share/zoneinfo/Hongkong /etc/localtimeADD news_watch_notice /usr/bin/ADD news_watch_notice.sha /usr/bin/CMD ["news_watch_notice"]makefileTARGET=news_watch_noticePKG=$(TARGET)TAG=latestIMAGE_PREFIX?=hanyajunIMAGE_PREFIX_PRD=hanyajunTARGET_IMAGE_DEV=$(IMAGE_PREFIX)/$(TARGET):$(TAG)TARGET_IMAGE_PRD=$(IMAGE_PREFIX_PRD)/$(TARGET):$(TAG)all: image$(TARGET): CGO_ENABLED=0 go build -o dist/$(TARGET) $(PKG)/cmdgitlog:target: mkdir -p dist git log | head -n 1 > dist/news_watch_notice.sha docker run --rm -i -v `pwd`:/go/src/$(PKG) \ -w /go/src/$(PKG) golang:1.11.5 \ make $(TARGET)image-dev: target cd dist && cp ../Dockerfile ./ && \ docker build -t $(TARGET_IMAGE_DEV) .push-dev: docker push $(TARGET_IMAGE_DEV)image-prd: target cd dist && cp ../Dockerfile ./ && \ docker build -t $(TARGET_IMAGE_PRD) .push-prd: docker push $(TARGET_IMAGE_PRD)clean: rm -rf dist.PHONY: image target clean push $(TARGET).travis.ymllanguage: gogo: # 语言版本号 - "1.11.5" # 默认使用最新版本,注意,需要 "1.10" 版本的时候必须表示为字符串形式,如果写成 1.10 则会使用 1.1 版本;x表示对应前缀的最新版本services: - docker #需要的docker环境install: - make image-dev #buildscript: - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - make push-dev # pushtravis的配置(https://travis-ci.org)打开项目ci开关 ...

May 16, 2019 · 3 min · jiezi

dockerk8s云

在https://segmentfault.com/a/11... 容器,隔离,云的概述。这篇对其中用途广泛的docker,k8s做详细介绍,并给出云搭建的生态环境体系。 docker1.与其他VM等对比容器发展,详见上面提到的文章 chroot1979Linux Vserver2001process container2006LXC2008Docker2013windows container2017典型图:VM与container对比,差异在于OS VMcontainer隔离OSkernel namespace可配额,可度量硬件页映射cgroups移动性snapshot,imageAUFS安全 gresc patch缺点 隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container公用一部分的运行库网络管理相对简单,主要是基于namespace隔离cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是安内存收费)docker对disk的管理比较有限(disk quota)container随着用户进程的停止而销毁,container中的log等用户数据不便收集 优点: 轻量级的特点,其启动快,而且docker能够只加载每个container变化的部分,这样资源占用小docker不只是容器,高级容器引擎,应用部署平台,应用镜像商店2.docker生态圈————不只是容器 Image 一个包含运行环境的只读 模板Container 镜像的运行态,docker利 用容器运行应用Registry 存储容器镜像的仓库Dockerfile 包含构建镜像一系列命令 和参数的脚本3.执行过程 Docker Daemon 可以认为是通过 Docker Server 模块接受 Docker Client 的请求,并在 Engine 中处理请求,然后根据请求类型,创建出指定的 Job 并运行。 Docker Daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。job运行过程的作用有以下几种可能:向 Docker Registry 获取镜像通过 graphdriver 执行容器镜像的本地化操作启动容器graphGraph在Docker架构中扮演已下载容器镜像的保管者,以及已下载容器镜像之间关系的记录者。一方面,Graph存储着本地具有版本信息的文件系统镜像,另一方面也通过GraphDB记录着所有文件系统镜像彼此之间的关系。GraphDB是一个构建在SQLite之上的小型图数据库,实现了节点的命名以及节点之间关联关系的记录。它仅仅实现了大多数图数据库所拥有的一个小的子集,但是提供了简单的接口表示节点之间的关系。Graph的本地目录中,关于每一个的容器镜像,具体存储的信息有:该容器镜像的元数据,容器镜像的大小信息,以及该容器镜像所代表的具体rootfs。networkdriver 执行容器网络环境的配置networkdriver的用途是完成Docker容器网络环境的配置,其中包括Docker启动时为Docker环境创建网桥;Docker容器创建时为其创建专属虚拟网卡设备;以及为Docker容器分配IP、端口并与宿主机做端口映射,设置容器防火墙策略等。execdriver 执行容器内部运行的执行工作execdriver作为Docker容器的执行驱动,负责创建容器运行命名空间,负责容器资源使用的统计与限制,负责容器内部进程的真正运行等。在execdriver的实现过程中,原先可以使用LXC驱动调用LXC的接口,来操纵容器的配置以及生命周期,而现在execdriver默认使用native驱动,不依赖于LXC。具体体现在Daemon启动过程中加载的ExecDriverflag参数,该参数在配置文件已经被设为"native"。这可以认为是Docker在1.2版本上一个很大的改变,或者说Docker实现跨平台的一个先兆libcontainerDocker架构中一个使用Go语言设计实现的库,设计初衷是希望该库可以不依靠任何依赖,直接访问内核中与容器相关的API。正是由于libcontainer的存在,Docker可以直接调用libcontainer,而最终操纵容器的namespace、cgroups、apparmor、网络设备以及防火墙规则等。这一系列操作的完成都不需要依赖LXC或者其他包。libcontainer提供了一整套标准的接口来满足上层对容器管理的需求。 docker run过程(1) Docker Client接受docker run命令,解析完请求以及收集完请求参数之后,发送一个HTTP请求给Docker Server,HTTP请求方法为POST,请求URL为/containers/create? +xxx;(2) Docker Server接受以上HTTP请求,并交给mux.Router,mux.Router通过URL以及请求方法来确定执行该请求的具体handler;(3) mux.Router将请求路由分发至相应的handler,具体为PostContainersCreate;(4) 在PostImageCreate这个handler之中,一个名为"create"的job被创建,并开始让该job运行;(5) 名为"create"的job在运行过程中,执行Container.Create操作,该操作需要获取容器镜像来为Docker容器创建rootfs,即调用graphdriver;(6) graphdriver从Graph中获取创建Docker容器rootfs所需要的所有的镜像;(7) graphdriver将rootfs所有镜像,加载安装至Docker容器指定的文件目录下;(8) 若以上操作全部正常执行,没有返回错误或异常,则Docker Client收到Docker Server返回状态之后,发起第二次HTTP请求。请求方法为"POST",请求URL为"/containers/"+container_ID+"/start";(9) Docker Server接受以上HTTP请求,并交给mux.Router,mux.Router通过URL以及请求方法来确定执行该请求的具体handler;(10) mux.Router将请求路由分发至相应的handler,具体为PostContainersStart;(11) 在PostContainersStart这个handler之中,名为"start"的job被创建,并开始执行;(12) 名为"start"的job执行完初步的配置工作后,开始配置与创建网络环境,调用networkdriver;(13) networkdriver需要为指定的Docker容器创建网络接口设备,并为其分配IP,port,以及设置防火墙规则,相应的操作转交至libcontainer中的netlink包来完成;(14) netlink完成Docker容器的网络环境配置与创建;(15) 返回至名为"start"的job,执行完一些辅助性操作后,job开始执行用户指令,调用execdriver;(16) execdriver被调用,初始化Docker容器内部的运行环境,如命名空间,资源控制与隔离,以及用户命令的执行,相应的操作转交至libcontainer来完成;(17) libcontainer被调用,完成Docker容器内部的运行环境初始化,并最终执行用户要求启动的命令。4.docker技术 ...

May 14, 2019 · 3 min · jiezi

如何使用docker和dockercompose在EOS本地Testnet上开发

EOS区块链的开发并不是立竿见影的,因为需要一些非显而易见的组件,需要对它们进行配置和协同工作。 nodeos:块生成器守护程序。keosd:钱包守护进程,存储私钥。eosio-cpp:智能合约编译器。eosio.token:平台的参考标记。cleos:用于与EOS区块链远程交互的CLI。scatter:为本地Testnet配置的EOS钱包。 我将学到什么?如何运行和初始化EOS本地Testnet。如何编译和运行EOS智能合约。如何通过cleos进行EOS交易。要求要学习本教程,你需要使用下面的软件: Ubuntu Linux(推荐)docker/docker-compose困难程度中间教程内容Dockerfile(你需要的软件)docker-compose.yml(该软件应该如何运行)cleos,命令行EOS钱包。部署eosio.token,即EOS货币系统智能合约。Dockerfile(你需要的软件)。你可以直接在Linux操作系统上安装以下组件,但这样可以使你的开发环境更加干净,更易于维护和测试。 以下所有文件均为官方文件,并由EOSIO发布: FROM ubuntu:18.04RUN apt-get update && apt-get install -y curl libicu60 libusb-1.0-0 libcurl3-gnutlsRUN curl -LO https://github.com/EOSIO/eos/releases/download/v1.7.0/eosio_1.7.0-1-ubuntu-18.04_amd64.deb \ && dpkg -i eosio_1.7.0-1-ubuntu-18.04_amd64.debRUN curl -LO https://github.com/EOSIO/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb \ && dpkg -i eosio.cdt_1.6.1-1_amd64.debRUN curl -LO https://github.com/EOSIO/eosio.cdt/archive/v1.6.1.tar.gz && tar -xvzf v1.6.1.tar.gz --one-top-level=eosio.cdt --strip-components 1RUN cd /eosio.cdt/ && curl -LO https://github.com/EOSIO/eosio.contracts/archive/v1.6.0-rc3.tar.gz && tar -xvzf v1.6.0-rc3.tar.gz --one-top-level=eosio.contracts --strip-components 1你可以使用以下命令生成打包的镜像沙箱: docker build -t my/eos .docker-compose.yml(该软件应该如何运行)正如我所说,需要一些配置来互相讨论所需的所有部分。 default.wallet是一个预配置的钱包,带有用于测试的私钥。config.ini是Block Producer(BP)的文件,在EOS Mainnet中你不会/不能改变它。version: '3'services: nodeos: container_name: nodeos image: my/eos command: nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::history_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --plugin eosio::http_plugin --http-server-address=0.0.0.0:8888 --access-control-allow-origin=* --contracts-console --http-validate-host=false --filter-on="*" stop_grace_period: 3m0s volumes: - ./:/eosio.cdt/contract - ./config.ini:/root/.local/share/eosio/nodeos/config/config.ini ports: - '8888:8888' - '9830:9876' depends_on: - keosd keosd: container_name: keosd hostname: keosd image: my/eos command: keosd --http-server-address=0.0.0.0:8901 --http-validate-host 0 --verbose-http-errors --unlock-timeout=9999999 volumes: - ./default.wallet:/root/eosio-wallet/default.wallet expose: - 8901 ports: - '8901:8901'运行在新终端中运行以下命令: ...

May 14, 2019 · 2 min · jiezi

Docker入门镜像使用篇2

列出镜像列出已经下载的镜像,使用docker image ls进行查看 如下图[root@host ~]# docker image lsREPOSITORY TAG IMAGE ID CREATED SIZEubuntu 18.04 d131e0fa2585 2 weeks ago 102MBhello-world latest fce289e99eb9 4 months ago 1.84kB列表包含了 仓库名、标签、镜像 ID、创建时间 和 所占用的空间。 镜像体积docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。[root@host ~]# docker system dfTYPE TOTAL ACTIVE SIZE RECLAIMABLEImages 2 2 101.8MB 0B (0%)Containers 4 1 0B 0BLocal Volumes 0 0 0B 0BBuild Cache 0 0 0B 0B虚悬镜像随着官方镜像维护,发布了新版本后,重新 docker pull xxx 时,xxx 这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 <none>。除了 docker pull 可能导致这种情况,docker build 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 <none> 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ,可以用下面的命令专门显示这类镜像: ...

May 13, 2019 · 2 min · jiezi

mongo-EOF二

任何事情的成功都需要掐准时间上一节mongo EOF中,关于容器的配置,只是粗略的使用了Docker-Compose-MongoDB-Replica-Set项目提供好的docker-compose.yml文件。在使用过程中,我发现这个文件本身一些不如意的地方。首先,services中的creator服务,entrypoint指令太长了,不美;其次,所有的service都没有给容器外部暴露端口,导致外部无法访问容器;再次,直接使用mongo repliSet的连接串进行访问,无法正常访问mongo服务。 在上一篇文章的基础上,这篇文章对docker-compse.yml做了一些调整,并且也包含了docker使用的入门介绍。更新后的docker-compose.yml请访问githubsi。 depends_onHowever, for startup Compose does not wait until a container is “ready” (whatever that means for your particular application) - only until it’s running. There’s a good reason for this.在creator service中使用了该指令, 但是,实际中creator不会等到mongo1、mongo2、mongo3容器ready后再启动,而是等到它们启动就开始启动。这也是我在setup脚本中执行sleep操作的原因。 creator: build: context: . dockerfile: dockerfile entrypoint: ["/data/conf/setup.sh"] depends_on: - mongo1 - mongo2 - mongo3entrypointEntrypoint sets the command and parameters that will be executed first when a container is run.entrypoint设置了容器启动时执行的命令和参数,传递给docker run <image>的参数都将追加到entrypoint命令之后,并且会覆盖CMD命令。比如,docker run <image> bash 将会追加bash到entrypoint命令末尾。 ...

May 12, 2019 · 2 min · jiezi

替换-Docker-或-Laradock-中-Debian-系统镜像源解决软件安装问题

Docker Debian 镜像源替换因多数默认的 Docker 镜像为国外的,而采用的镜像源也是国外的,故访问很慢,所以我们需要替换为国内的(比如阿里云或163等)。 163 - DebianAliyun - Debian注意: 不同版本的 Debian 镜像源地址不一样Debian 7.x (wheezy)# 更新apt-get源RUN echo \ deb http://mirrors.aliyun.com/debian/ wheezy main non-free contrib\ deb http://mirrors.aliyun.com/debian/ wheezy-proposed-updates main non-free contrib\ deb-src http://mirrors.aliyun.com/debian/ wheezy main non-free contrib\ > /etc/apt/sources.listDebian 8.x (jessie)# 更新apt-get源RUN echo \ deb http://mirrors.aliyun.com/debian/ jessie main non-free contrib\ deb http://mirrors.aliyun.com/debian/ jessie-proposed-updates main non-free contrib\ deb-src http://mirrors.aliyun.com/debian/ jessie main non-free contrib\ > /etc/apt/sources.listDebian 9.x (stretch)# 更新apt-get源RUN echo \ deb http://mirrors.aliyun.com/debian/ stretch main non-free contrib\ deb-src http://mirrors.aliyun.com/debian/ stretch main non-free contrib\ deb http://mirrors.aliyun.com/debian-security stretch/updates main\ deb-src http://mirrors.aliyun.com/debian-security stretch/updates main\ deb http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib\ deb-src http://mirrors.aliyun.com/debian/ stretch-updates main non-free contrib\ deb http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib\ deb-src http://mirrors.aliyun.com/debian/ stretch-backports main non-free contrib\ > /etc/apt/sources.listLaradock 镜像构建失败因为默认用的是国外 Debian 镜像源,故在执行 apt-get 等命令拉取软件包时会失败,我们需手动在对于的 Dockerfile 中添加一个 RUN 指令来替换掉默认的镜像源以下仅为示例: ...

May 9, 2019 · 1 min · jiezi

Docker入门镜像使用篇

使用镜像从仓库获取镜像;管理本地主机上的镜像;镜像实现的基本原理。获取镜像从DockerHub中获取镜像 命令为docker pull docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]比如: docker pull ubuntu:18.04镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。 运行拥有镜像后,可以以此镜像为基础启动一个容器。当我们需要进行启动里边的bash,并且进行交互操作的时候,可以执行以下命令 docker run -it --rm \ ubuntu:18.04 \ bashdocker run 就是运行容器命令 简述上用参数 -it: 这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。--rm:容器退出后随之将其删除。为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。ubuntu:18.04:是指指定 ubuntu:18.04这个镜像为基础来启动容器bash:放在镜像后的是命令,这里是因为需要有个交互的shell 因此使用了bashcat /etc/os-release,Linux查看当前系统版本命令、可返回查看容器是什么系统。 exit退出容器

May 9, 2019 · 1 min · jiezi

Docker入门

Docker简介Docker 是使用 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。隔离的进程独立于宿主和其它的隔离的进程。Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等优点是没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。Docker的优势高效的利用系统资源快速的启动时间一致的运行环境持续交付和部署:对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。 Docker 确保了执行环境的一致性,使得应用的迁移更加容易Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。社区健壮,一堆开源项目团队维护一批高质量的官方景象。对比图特性容器虚拟机启动秒级分钟级硬盘使用MBGB性能接近原生较弱系统支持量单机支持上千个容器一般几十个相关基本概念Docker 包括三个基本概念 镜像(Image)容器(Container) 容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。仓库(Repository) 一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。三个概念包括Docker的生命周期 安装(CentOS)卸载旧版本$ sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine使用 yum 安装$sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2国内网络问题,强烈建议使用国内源$ sudo yum-config-manager \ --add-repo \ https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo# 官方源$ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo安装 Docker CEsudo yum makecache fastsudo yum install docker-ce使用脚本自动安装$ curl -fsSL get.docker.com -o get-docker.sh$ sudo sh get-docker.sh --mirror Aliyun启动 Docker CE$ sudo systemctl enable docker$ sudo systemctl start docker建立 docker 用户组 ...

May 9, 2019 · 2 min · jiezi

DOS-Network三月中四月项目月报

各位亲爱的DOS社区的支持者们,欢迎阅读3月20日至4月30日的月度项目进度报告!???? 请关注我们的微信公众号或加入DOS官方社群,了解DOS网络的最新动态,希望您喜欢!现在就为大家带来最新的项目进展月报! ⚙️ 产品和开发我们正在筹备即将发布的测试版。修复了节点cpu重载和内存不足的问题。从Kademlia DHT切换到Gossip SWIM进行网络路由,对p2p层进行了更多的模拟和测试。用Geth light节点代替full节点进行实验,进一步降低节点运行者的维护成本。为Docker和二进制部署开发了安装脚本。升级的系统合同,以支持Solidity 0.5.x。使用客户端看门狗watchdog和监护节点启动新一轮分布式随机生成,而不是空转和消耗gas。支持并行的预言机请求处理。实施监护人职能。 监护人就像MakerDao系统中的守护者一样,每个人都包括但不限于DOS客户端节点能够运行监护人脚本(待开发)并获得奖励。截至目前,监护人功能仅整合到客户端节点中。最终的引导过程和实现commit-reveal机制,用于安全地生成创世纪随机数。最简单的权益质押合约开发和测试网通证发行。系统合同gas优化和黑客攻击。Beta 1.0即将来临,敬请关注????????????! ????交易所列表,钱包和排名网站DOS通证目前在 4 个交易平台上有 8 个交易对,我们正在努力让DOS上更多主流的交易所。 BitMax 交易所: https://bitmax.io/#/trade/usd... https://bitmax.io/#/trade/btc... Bilaxy交易所: https://bilaxy.com/exchange#s... Coinsuper交易所: https://www.coinsuper.com/coi... https://www.coinsuper.com/coi... DDEX去中心化交易所: https://ddex.io/trade/DOS-WETH MXC交易所: https://www.mxc.com/trade.htm... https://www.mxc.com/trade.htm... DOS通证也可在Blockfolio,imToken、Trust Wallet和麦子钱包上查看和搜索: CoinMarketCap、CoinGecko和Binance Info现在也都在同步DOS Network项目信息和通证表现: DOS网络(DOS)价格,图表,市值和其他指标| CoinMarketCap https://coinmarketcap.com/cur... DOS网络(DOS)价格,市价,图表和基本面信息| CoinGecko https://www.coingecko.com/en/... DOS网络令牌(DOS)价格,评级,新闻和分析 -  Binance Info https://info.binance.com/en/c... 国内平台 MyToken、非小号、TokenClub、火星币优等也有同步DOS Network项目信息和通证表现。 ????新伙伴关系DOS Network已与QuarkChain达成战略合作伙伴关系。双方将为彼此提供更多用例,合作以满足全球商业标准,并促进分散应用的大规模采用。回顾:DOS与QuarkChain携手共进,为满足区块链全球化商业标准 DOS网络和原力协议正式建立了长期战略伙伴关系。双方将在分布式加密金融服务领域密切合作,实现更多区块链金融应用场景。回顾:DOS与原力协议齐心协力,拓展分布式加密金融领域 DOS网络已成为企业以太坊联盟(EEA)的成员,该联盟是全球最大的开源区块链组织,拥有300多家成员公司。我们很高兴加入欧洲经济区,为其使命做出贡献 - 增强基于以太坊的区块链技术的隐私性,安全性和可扩展性。回顾:DOS Network正式加入企业以太坊联盟(EEA) ???? 活动DOS网络成功地用BitMax进行了 1,000,000 DOS赏金计划。超过 5000 名用户参与了该计划,共有 397,326 个参赛作品。 DOS网络联合创始人兼运营负责人王琦,在Unitimes社区举办了AMA会议,该社区是全球领先的金融科技媒体平台。回顾:对话 DOS Network:我们不生产数据,我们只是数据的搬运工 | Unitimes AMA DOS网络提出了一种创新的令牌分发模型--DropBurn启动权益质押网络的新模型。我们希望分享和收集社区,感兴趣的开发人员,潜在的beta测试人员和节点运行者的反馈。 DOS Network的联合创始人华思远应邀参加芝加哥与BitMax,CTIA和Ankr Network的会面,讨论数字资产的现状和未来发展。华思远发表演讲,分享有关DropBurn的宝贵见解,并参与了一个小组讨论:区块链技术的转型角色。 ...

May 9, 2019 · 1 min · jiezi

Docker常用命令

Docker中常用的命令可以分为以下几种类型: 容器生命周期管理命令容器的生命周期管理命令指的是容器的启动,停止,重启等命令,具体如下: 容器操作命令容器操作命令主要用于查看容器的相关信息 容器的远程仓库镜像管理命令 本地镜像管理命令 容器文件管理命令 系统信息命令

May 8, 2019 · 1 min · jiezi

使用-docker-搭建-wordpress

导语这不是一篇正规搭建 wordpress 的文章,是基于上一篇的基础之上,进行的实现。最终的实现是使用 nginx 做代理,独立的 wordpress 容器,连接 laradock 的 MySQL 做存储。 修改 nginx 代理相较于 laradock 的配置,只是修改监听的域名以及转发的端口。在 /etc/nginx/conf.d/ 目录下新建 wordpress.conf 文件,如下 server { listen 80; server_name blog.you_site.com; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://[宿主机IP]:8001; }}修改之后记得重启 搭建 wordpress 容器拉取镜像 docker pull wordpress因为 wordpress 要连接 MySQL 容器,正好 laradock 就有,就用这个好了。连接的方式不用 --link,用 --network,可以参考这里laradock 中 MySQL 的 network 在 docker-compose.yml 文件中有写,如下同时使用 docker network ls 查看,可以看到 laradock_backend 这个网络。显而易见使用 laradock_backend 就可以 ...

May 7, 2019 · 1 min · jiezi

弹性云服务器有哪些优点如何选择群英来说说

弹性云服务器,顾名思义就是可弹性伸缩,用户可根据自身需求灵活设定所需的各项服务器配置。它有哪些优点呢?群英来简单说说。 1.灵活扩展:用户可自由搭配CPU、内存、磁盘、带宽等资源的配置额,当不需要这些资源时,可随时减少资源量或增加; 2.稳定可靠:当发生硬件故障时,弹性云服务器可以在多个服务器集群上实时备份用户网站数据,并提供快照备份,整个过程不影响客户网站正常使用; 3.安全独享:客户之间互相独立,资源独享,网站稳定性得到最大保障; 4.节省成本:根据不同的情况进行弹性伸缩,按需定制,价格便宜,规避了传统独立服务器资源闲置和浪费的情况; 5.快速搭建:用户拥有最高管理权限,可自由搭建任意应用环境,安装任意操作系统和相应软件; 6.提升效率:在运维上无需关心硬件设施的性能效率监控和管理,这些都由服务商负责,更有效提升企业工作效率。 现在,是不是对它有了更深一步的认识了呢,马上去选购一款适合自己的云服务器吧.

May 7, 2019 · 1 min · jiezi

Docker打包nodejs项目和数据库

看这篇文章,必须知道基础的docker, 本文只提供思路和部分代码, 不负责教所有的命令必须谨慎操作!三思而后行命令停止所有运行的容器docker stop $(docker ps -a -q)删除所有的容器docker rm $(docker ps -a -q)使用docker-compose启动容器docker-compose up -d使用docker-compose关闭容器docker-compose down查看Logdocker logs ${容器id}部署mysqldocker-composeservices: mysql: network_mode: "host" environment: MYSQL_ROOT_PASSWORD: "yourpassword" MYSQL_USER: 'test' MYSQL_PASS: 'yourpassword' image: "docker.io/mysql:latest" restart: always // 连不上就一直重试 // depends_on: 选择依赖于某个服务,依赖的服务会先加载 // - 'sss' volumes: - "./db:/var/lib/mysql" - "./conf/my.cnf:/etc/my.cnf" - "./init:/docker-entrypoint-initdb.d/" ports: - "3306:33060"自动加载sql语句,实现初始化数据库 mysql的官方镜像中,会在加载时执行docker-entrypoint-initdb.d下面文件夹下的sql文件 利用这个实现初始化如果mysql数据文件夹中有数据,则不会加载sql文件EGG项目配合docker: 直接被中断因为egg-scripts自己有一套守护进程,去掉daemon参数 "start": "egg-scripts start --title=egg-server-broken-chain",部署NodeJs项目新建Dockerfile文件FROM node:10.13-alpineENV NODE_ENV productionWORKDIR /usr/src/appCOPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]RUN npm install -g cnpmRUN cnpm install --production --silentCOPY . .EXPOSE 7001CMD [ "npm", "start"]在docker-compose.yml中添加信息,用docker-compose管理多个镜像相当方便最终的docker-compose.yml文件version: '2'services: broken-chain: image: broken-chain build: . environment: NODE_ENV: production ports: - 7001:7001 depends_on: - "mysql" restart: always mysql: environment: MYSQL_ROOT_PASSWORD: "123" image: "docker.io/mysql:5.6" volumes: - "./mysql/init:/docker-entrypoint-initdb.d/" ports: - "3306:3306"发布镜像登录Dockerhubdocker login给镜像打上标签docker tag ${镜像id} ${用户名}/${镜像名}:${tag标签}push推到dockerhubdocker push ${用户名}/${镜像名}:${tag标签}最后最终,你要把你做的项目给别人用,开箱即用的那种。你需要 ...

May 7, 2019 · 1 min · jiezi

Docker-脚本化一键部署

Dockerinstall Docker参照官网 install kubernetes安装kubernetes的时候,需要安装kubelet, kubeadm等包,但k8s官网给的yum源是packages.cloud.google.com,国内访问不了,此时我们可以使用阿里云的yum仓库镜像。 阿里云上没有附Help说明连接,简单摸索了下,如下设置可用(centos)。注意不要开启check。 cat <<EOF > /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64enabled=1gpgcheck=0repo_gpgcheck=0gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg开发思路1 寻找基础镜像2 基于基础镜像编写Dockerfile脚本3 根据Dockerfile脚本创建项目镜像4 将创建的镜像推送到docker仓库 (根据自身需要,可做可不做)5 基于项目镜像创建并运行docker容器 (实现最终部署)思路:使用 centos 容器安装对应的软件环境,最后将环境导出。 操作步骤创建容器$ docker pull centos $ sudo docker run --privileged --cap-add SYS_ADMIN -e container=docker -it --name my_centos -p 80:8080 -d --restart=always centos:7 /usr/sbin/init 启动容器$ docker exec -it my_centos /bin/bash导出和导入$ docker export my_centos > /data/app/meifen/my_centos-export-0428.tar$ docker import /data/app/meifen/my_centos-export-0428.tar保存save格式:docker save IMAGE(镜像) 使用 docker images 查看本机已有的镜像(也可以使用 docker commit <CONTAIN-ID> <IMAGE-NAME>命令把一个正在运行的容器保存为镜像) $ docker save 9610cfc68e8d > /data/app/meifen/my_centos-export-0428.tar加载 load有点慢,稍微等待一下,没有任何warn信息就表示保存OK。9610cfc68e8d 是镜像ID ...

May 7, 2019 · 1 min · jiezi

docker在centos上安装beego及部分理解

诚如前面一篇文章,是简单的布置了golang的一个demo,再次布beego 1、写Dockerfile# docker build# Version 1.0FROM centosMAINTAINER yanyue@78dk.comENV GOROOT /usr/local/goENV GOPATH /data/gopathENV PATH $GOROOT/bin:$PATHADD go/ /usr/local/goRUN mkdir -p /data/gopathADD src/ /data/gopath/srcADD pkg/ /data/gopath/pkgWORKDIR /data/gopath/src/lotteryRUN cd /data/gopath/src/lotteryRUN go build -o server.sh main.goRUN cp /data/gopath/src/lottery/server.sh /usr/bin/server.shRUN chmod 777 /usr/bin/server.shENTRYPOINT /usr/bin/server.sh注最后一行不能使用RUN和CMD,不然会将启动日志输出到命令行,加&会导致docker内server.sh未启动(血泪史) 2、创建镜像docker build -t golang:v1 .3、创建容器docker run -itd -p 80:8080 golang:v1 /bin/bash注端口号绑定:前面为本机的端口,后面为容器端口 4、查看容器docker ps注 此命令后面加上-a就能查看所有状态的镜像 坑点:坑点已经填平了,按照上面的步骤,不会错(泪目)

May 6, 2019 · 1 min · jiezi

K8S-生态周报-2019042820190505

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。Docker Hub 只读维护在上周的推送中,有写到 Docker Hub 用户隐私数据泄漏。受此事件影响,5 月 4 日 Docker Hub 进行升级维护,在此期间 Docker Hub 有一段时间处于只读模式,包括自动构建等服务不可用;在最后有小于 15 分钟的完全宕机时间,服务完全不可用。 如果只是看事情表面的话,可能这就是一个由于发现“安全问题”而进行的升级/维护;但如果仔细考虑下,作为云原生服务,升级为何会有宕机的情况,为何会有服务完全不可用的时候? 摘录一段来自本次维护的公告内容: Q: Is this maintenance related to recent Docker Hub data breach?A: While we discovered unauthorized access to a single Hub database storing a subset of non-financial user data last week, which has since been remediated, we are always looking at ways to improve and enhance our security practices to protect our customers and their data. The planned maintenance for Docker Hub on Saturday May 4 is a proactive step we are taking to provide the best possible customer experience and highest level of security ...

May 6, 2019 · 1 min · jiezi

在Mac上安装Minikube-10

在Mac上安装Minikube 1.0最近这几年,软件开发翻天覆地的变化,当个软件行业从业者,不学习新东西肯定是不行的。从微服务到容器化服务开发,其实并没有多长时间,随着Docker和Kubenetes的大热,还必须要跟上脚步才行,做一个程序员真不容易,做一个老程序员更难。 Docker和Kubenetes是什么,我这里就不介绍了,比我了解这玩意的的人,大有人在,如果你想了解,请自我学习,本文结尾也推荐了《IBM微讲堂 Kubenetes》系列,一共十个视频,看一遍基本也就都懂了。如果你开发微服务想控制和容器编排工具有互动,比如调用K8s的API之类,或者你想本Mac地装一个单机版本的K8s,我也走了一些弯路,没少浪费时间。K8s安装是一个不小的工程,但是我并不是一个很好的运维,也仅仅在开发层面了解K8s,所以装一个单机版本非常有必要,这里推荐你去安装Minikube,这就是一个单机版本的单节点K8s。其实本来就想一个安装记录,但是估计也有不少人会遇到安装的问题,那我就稍微写详细一点,帮助大家稍微少走一点弯路。 安装Minikube第一步,你先要越过GFW,至于什么是GFW怎么越过去这里就不详细说了。Minikube需要你本地装有VirtualBox,推荐你下载一个比较新的版本,因为要在上面运行一个虚拟机来跑K8s的节点。 修改网络配置我用的软件是ShadowsocksX-NG这个软件,早期版本并不支持代理,后期版本使用了privoxy实现了HTTP和Socks,但是本文只需要使用HTTP代理就好了。 首先修改进入Performance中,把Advance中的Socks5地址和HTTP中的监听地址都改为0.0,0,0就Ok了,这样你就能接收非本地的请求代理访问ss了。 安装Mac下安装太容易了,别告诉我你没有brew。 brew cask install minikube大功告成。 下载安装kubectl ,需要手工该权限,这是K8s的命令行控制工具 curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.14.0/bin/darwin/amd64/kubectlsudo mv kubectl /usr/local/bin/chmod +x /usr/local/bin/kubectl安装完Minikube 先测试下网络环境,下面命令正常说明代理服务没问题 curl -x 192.168.99.1:1087 http://baidu.com启动用下面命令,让K8s节点的docker,使用下面代理访问,insecure-registry详解见本文末尾扩展阅读 minikube start --docker-env HTTP_PROXY=http://192.168.99.1:1087 --docker-env HTTPS_PROXY=http://192.168.99.1:1087 --docker-env NO_PROXY=127.0.0.1/24 --insecure-registry=192.168.99.1:5000见到下面log为启动成功。 ???? minikube v1.0.0 on darwin (amd64)???? Downloading Kubernetes v1.14.0 images in the background ...???? Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...???? "minikube" IP address is 192.168.99.105???? Configuring Docker as the container runtime ... ▪ env HTTP_PROXY=http://192.168.99.1:1087 ▪ env HTTPS_PROXY=http://192.168.99.1:1087 ▪ env NO_PROXY=127.0.0.1/24???? Version of container runtime is 18.06.2-ce⌛ Waiting for image downloads to complete ...E0503 17:26:45.170139 5798 start.go:209] Error caching images: Caching images for kubeadm: caching images: caching image /Users/freewolf/.minikube/cache/images/k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64_1.14.13: fetching remote image: Get https://k8s.gcr.io/v2/: dial tcp 74.125.203.82:443: i/o timeout✨ Preparing Kubernetes environment ...❌ Unable to load cached images: loading cached images: loading image /Users/freewolf/.minikube/cache/images/gcr.io/k8s-minikube/storage-provisioner_v1.8.1: stat /Users/freewolf/.minikube/cache/images/gcr.io/k8s-minikube/storage-provisioner_v1.8.1: no such file or directory???? Pulling images required by Kubernetes v1.14.0 ...???? Launching Kubernetes v1.14.0 using kubeadm ... ⌛ Waiting for pods: apiserver proxy etcd scheduler controller dns???? Configuring cluster permissions ...???? Verifying component health .....???? kubectl is now configured to use "minikube"???? Done! Thank you for using minikube!中间的错误信息说明本地的cache中没有所需文件都要连接互联网拉取。中间时间很长需要20分钟,因为要下载1g的内容。 ...

May 4, 2019 · 2 min · jiezi

简单聊会-Docker

本文来自于我的慕课网手记:简单聊会 Docker,转载请保留链接 ;)最近在工作中一直在忙基础设施构建,发现在选型的时候,大家心里基本上都有一个自己的成熟架构。而在服务部署这块发现公司的同事们都大多数考虑Docker,在业余闲聊了后,发现他们对Docker只是在停留在使用,对一些Docker的基本知识还是不了解,并不清楚 Docker 到底是什么,要解决什么问题,好处又在哪里?今天就来详细解释,帮助大家理解它,还带有简单易懂的实例,教你如何将它用于日常开发并用其部署微服务。 Docker简介Docker是基于Go语言实现的云开源项目,诞生于2013年初,最初发起者是dotCloud公司。Docker自开源后受到广泛的关注和讨论,目前已有多个相关项目,逐渐形成了围绕Docker的生态体系。dotCloud公司后来也改名为Docker Inc,专注于Docker相关技术和产品的开发。Docker 一直广受瞩目,被认为可能会改变软件行业。那么什么是Docker呢?我查阅了网上的一些相关资料,现用一段话总结了一下。Docker是一个开源的容器引擎,它可以帮助我们更快地交付应用。Docker可将应用程序和基础设施层隔离,并且能将基础设施当作程序一样进行管理。使用Docker,可更快地打包、测试以及部署应用程序,并可减少从编写到部署运行代码的周期。对一个事物有了一定了解后,我们的继续学习Docker官方的给出文档和源码。(这个今天不在此文章扩展,不然聊不完。) TIPS (1) Docker官方网站:https://www.docker.com/ (2) Docker GitHub:https://github.com/docker/docker Docker快速入门执行如下命令,即可启动一个Nginx容器``docker run -d -p 91:80 nginx`` Docker架构我们来看一下来自Docker官方文档的架构图,如图所示。 我们来讲解上图中包含的组件。(1) Docker daemon(Docker守护进程) Docker daemon是一个运行在宿主机(DOCKER_HOST)的后台进程。我们可通过Docker客户端与之通信。 (2) Client(Docker客户端) Docker客户端是Docker的用户界面,它可以接受用户命令和配置标识,并与Docker daemon通信。图中,docker build等都是Docker的相关命令。 (3) Images(Docker镜像) Docker镜像是一个只读模板,它包含创建Docker容器的说明。它和系统安装光盘有点像——我们使用系统安装光盘安装系统,同理,我们使用Docker镜像运行Docker镜像中的程序。 (4) Container(容器) 容器是镜像的可运行实例。镜像和容器的关系有点类似于面向对象中,类和对象的关系。我们可通过Docker API或者CLI命令来启停、移动、删除容器。 (5) Registry Docker Registry是一个集中存储与分发镜像的服务。我们构建完Docker镜像后,就可在当前宿主机上运行。但如果想要在其他机器上运行这个镜像,我们就需要手动拷贝。此时,我们可借助Docker Registry来避免镜像的手动拷贝。 一个Docker Registry可包含多个Docker仓库;每个仓库可包含多个镜像标签;每个标签对应一个Docker镜像。这跟Maven的仓库有点类似,如果把Docker Registry比作Maven仓库的话,那么Docker仓库就可理解为某jar包的路径,而镜像标签则可理解为jar包的版本号。 Docker Registry可分为公有Docker Registry和私有Docker Registry。最常用的Docker Registry莫过于官方的Docker Hub,这也是默认的Docker Registry。Docker Hub上存放着大量优秀的镜像,我们可使用Docker命令下载并使用。 Docker应用场景常用的8个Docker的真实使用场景,分别是简化配置、代码流水线管理、提高开发效率、隔离应用、整合服务器、调试能力、多租户环境、快速部署。我们一直在谈Docker,Docker怎么使用,在怎么样的场合下使用? 首先你在享有Docker带来的虚拟化能力的时候无需担心它带来的额外开销。其次,相比于虚拟机,你可以在同一台机器上创建更多数量的容器。 Docker的另外一个优点是容器的启动与停止都能在几秒中内完成。Docker公司的创始人 Solomon Hykes曾经介绍过Docker在单纯的LXC之上做了哪些事情,你可以去看看。 下面是我总结的一些Docker的使用场景,它为你展示了如何借助Docker的优势,在低开销的情况下,打造一个一致性的环境。 简化配置这是Docker公司宣传的Docker的主要使用场景。虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker在降低额外开销的情况下提供了同样的功能。它能让你将运行环境和配置放在代码中然后部署,同一个Docker的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。 代码流水线(Code Pipeline)管理前一个场景对于管理代码的流水线起到了很大的帮助。代码从开发者的机器到最终在生产环境上的部署,需要经过很多的中间环境。而每一个中间环境都有自己微小的差别,Docker给应用提供了一个从开发到上线均一致的环境,让代码的流水线变得简单不少。 提高开发效率这就带来了一些额外的好处:Docker能提升开发者的开发效率。如果你想看一个详细一点的例子,可以参考Aater在DevOpsDays Austin 2014 大会或者是DockerCon上的演讲。 ...

May 2, 2019 · 1 min · jiezi

如何选择云服务器机房群英简单说说

购买云服务器时,会出现不同地区的机房可选择,价格也差异,该如何选择呢? 群英网络教你一招,遵循一个基本原则——以用户的访问来源为导向: 1.若网站以南方目标用户为主,推荐华南等地区的电信机房;2.若网站以北方目标用户为主,推荐华北等地区的联通机房;3.若网站目标用户是面向全国各地,为保证良好的访问速度,建议选择双线或多线机房;4.若网站用户是面向海外的话,一定要选择香港机房或韩国机房,这些都是很不错的海外机房。

April 30, 2019 · 1 min · jiezi

docker进阶nginx部署的几个重要点详解以及开发流程持续更新

部署基础知识url:协议://网站地址:端口(/)路径地址?参数eg: http://www.baidu.com:80/abc/dd/ www.baidu.com找服务器 80端口:找服务器上提供服务的应用 nginx uri:/abc/dd/ nginx的pid文件是可变化的等号两边不能空格,否则会报错tail -f 1.txt 实时监控文件变化 1.1 部署基础1.11.1 项目生命周期 传统项目生命周期 阶段 调研阶段 找方向点 设计阶段 方向点可视化 产品:产品需求文档、项目里程表 开发阶段 产品阶段功能实现 测试阶段 保证产品的阶段功能 运营阶段 项目部署 + 运营维护 关键点: 阶段间是有前后关系依赖的 阶段间项目的推进是有文档来主导 理想化的生命周期和开发模型1.2新型项目周期 软件项目: 一个产品被拆分成了非常多的子功能 团队组织:高效协作,沟通 图的理解: 四个圈串在一起 --- 子功能的完整周期 单个圈 --- 岗位的工作内容 图片: https://uploader.shimo.im/f/hRwe365QitwNgyS7.png 团队组织间的高效协作是很重要的 流程: 1 根据需求文档来梳理网站的目标架构 2 分析产品需求文档的功能,来梳理部署结点 部署节点示意图:图片: https://uploader.shimo.im/f/U... 3 根据部署结点去互联网上梳理各种解决方案(根据业务需求 4 整合所有的解决方案,-- 初版部署方案 5 根据实际的公司业务情况,对初版部署方案进行优化调整1.3 部署环境: ...

April 29, 2019 · 8 min · jiezi

开源-js-在线编程答题系统

前言:开源一套javascript的在线编程答题系统。技术架构:前端: Vue后端: Spring Boot数据库: Mysql持久层框架: Mybatis缓存存储: redis项目部署: docker部分截图: 项目演示: http://xcoding.me 项目前端: https://github.com/Zo3i/CodeJsFront 项目后端: https://github.com/Zo3i/CodeJsSystem 线上部署安装dockerwget https://raw.githubusercontent.com/Zo3i/OCS/master/docker/dockerInstall.sh && chmod +x dockerInstall.sh && ./dockerInstall.sh安装gityum install git一键部署wget https://raw.githubusercontent.com/Zo3i/CodeJsSystem/0040aa0b50f950f6bac160b81dced0a260ddac0b/web/src/main/docker/dockerRun.sh && chmod +x dockerRun.sh && ./dockerRun.sh完成部署访问前端:ip: 80 访问后端: ip: 8090/jsweb 账号/密码: system/admin

April 29, 2019 · 1 min · jiezi

K8S-生态周报-2019042220190428

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。Docker Hub 用户隐私数据泄漏2019 年 4 月 25 日,Docker Hub 团队发现了对存储非财务用户数据子集的单个 Hub 数据库的未授权访问。 在发现异常后官方团队迅速采取行动并保护网站免受攻击。 经过官方团队的调查,目前大概有 190000 帐号的敏感信息(小于总用户数的 5% )包括用户名和哈希后的用户密码,当然也包括 GitHub 及 Bitbucket 等的用于自动构建的 Token 。 当前的主要措施是对可能被泄漏信息的用户发送了邮件通知,对于可能泄漏哈希密码的用户发送了重置密码的邮件,并且 主动 将密码失效,以及自动构建的 Token 也都被失效。( 所以如果你收到了 Docker Hub 团队关于此次事件的直接报告邮件,很大概率是因为你的信息已经被泄漏了 ) 附上官方声明中关于此次事件的处理声明: During a brief period of unauthorized access to a Docker Hub database, sensitive data from approximately 190,000 accounts may have been exposed (less than 5% of Hub users). Data includes usernames and hashed passwords for a small percentage of these users, as well as GitHub and Bitbucket tokens for Docker autobuilds. ...

April 29, 2019 · 2 min · jiezi

Docker搭建GitLab

官方中文教程:https://www.gitlab.com.cn/ins... 官方安装链接:https://about.gitlab.com/install 普通方式安装请见:https://segmentfault.com/a/11...环境要求:内存至少4G,GitLab是很耗内存滴 一、安装一般会将 GitLab 的配置 (etc) 、 日志 (log) 、数据 (data) 放到容器之外, 便于日后升级 docker pull gitlab/gitlab-ce:11.6.4-ce.0# 通过docker run中加入环境变量,取名为gitlabdocker run --detach \ # 后台运行 -d # --hostname song.local \ # 指定容器域名,未知功能:创建镜像仓库的时候使用到 -p 8443:443 \ # 将容器内443端口映射到主机8443,提供https服务 -p 80:80 \ # 将容器内80端口映射到主机8080,提供http服务 -p 10022:22 \ # 将容器内22端口映射到主机1002,提供ssh服务 --name gitlab \ # 指定容器名称 --restart=unless-stopped \ # 容器运行中退出时(不是手动退出),自动重启 --volume /var/lib/docker/volumes/gitlab-data/etc:/etc/gitlab \ # 将本地/var/lib/docker/volumes/gitlab-data/etc挂载到容器内/etc/gitlab --volume /var/lib/docker/volumes/gitlab-data/log:/var/log/gitlab \ # 将本地将本地/var/lib/docker/volumes/gitlab-data/log挂载到容器内/var/log/gitlab --volume /var/lib/docker/volumes/gitlab-data/data:/var/opt/gitlab \ # 将本地将本地/var/lib/docker/volumes/gitlab-data/data挂载到容器内/var/opt/gitlab gitlab/gitlab-ce:11.6.4-ce.0 # 镜像名称:版本为了方便日后启动,创建一个启动脚本:gitlab-docker-restart.sh,代码如下:#!/bin/bashserverName="gitlab"imageName="gitlab/gitlab-ce:11.6.4-ce.0"function runServer(){ docker run --detach \ -p 8443:443 \ -p 80:80 \ -p 10022:22 \ --name ${serverName} \ --volume /var/lib/docker/volumes/gitlab-data/etc:/etc/gitlab \ --volume /var/lib/docker/volumes/gitlab-data/log:/var/log/gitlab \ --volume /var/lib/docker/volumes/gitlab-data/data:/var/opt/gitlab \ -v /etc/localtime:/etc/localtime \ --restart=unless-stopped \ ${imageName}}runningCount=`docker ps -f status=running -f status=restarting | grep -w ${serverName} |wc -l`;if [[ ${runningCount} > 0 ]];then echo "docker restart 重启项目:${serverName}" docker restart ${serverName} exit 0fiserverCount=`docker ps -f status=exited -f status=created | grep -w ${serverName} |wc -l`;# 判断是否已经启动过,且端口为默认端口if [[ ${serverCount} > 0 ]];then if [[ ${serverCount} > 1 ]]; then echo "Error : 查找到多个 ${serverName} 容器,请手动启动" exit 1 else echo "docker start 启动项目:${serverName}" docker start ${serverName} fielse name=${imageName%%:*} tag=${imageName##*:} # 判断是否有该镜像 imageCount=`docker images | grep -w ${name} | wc -l`; if [[ ${imageCount} > 0 ]];then echo "docker run 第一次启动项目: ${imageName}" runServer else echo "Error : 还没有该镜像" exit 1 fifi将 gitlab-docker-restart.sh赋予执行权限: ...

April 28, 2019 · 2 min · jiezi

docker的centos安装操作及部分理解

前两天在本地安装了docker,熟悉了下命令之后,还是忍不住到centos上进行了一波golang镜像部署,以下是我的操作步骤和一些想法。准备:一台安装了docker的可联网的centos服务器 1、不多说,写Dockerfile(只想体验dockerfile的操作流程,所以选择了yum的安装方式)# docker build# Version 1.0#FROM centos#MAINTAINER yancoder@163.com#RUN yum install -y epel-releaseRUN yum install -y docker-ioRUN yum provides '*/applydeltarpm'RUN yum install deltarpm -yRUN yum install -y gccRUN yum install -y goRUN mkdir -p /data/gopathENV GOPATH /data/gopathADD src/ /data/gopath/srcADD pkg/ /data/gopath/pkgADD test.go /data/gopath/test.goWORKDIR /data/gopathRUN go build -o server.bin test.go#CMD /data/gopath/server.bin注释别问我在gcc和go安装之前为什么还有四个安装步骤,我特么也不知道,反正就是报错了提示要我安装 源码安装如下 FROM centosMAINTAINER yancoder@163.comENV GOROOT /usr/local/goENV GOPATH /data/gopathENV PATH $GOROOT/bin:$PATHRUN yum install -y curlRUN curl -s -o go.tar.gz https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gzRUN tar --remove-files -C /usr/local/ -zxf go.tar.gzRUN mkdir -p /data/goRUN ln -sv /usr/local/go/bin/go /binADD src/ /data/gopath/srcADD pkg/ /data/gopath/pkgADD test.go /data/gopath/test.goWORKDIR /data/gopathRUN go build -o server.bin test.goCMD /data/gopath/server.bin2、创建镜像(注意最后面有一个小数点)docker build -t golang:v1.0 .3、创建容器,如果要绑定端口,也在这一步进行docker run -d -p 80:80 golang:v1.04、在外部浏览器访问一下~ ...

April 28, 2019 · 1 min · jiezi

程序员笔记如何编写优雅的Dockerfile

导读Kubernetes要从容器化开始,而容器又需要从Dockerfile开始,本文将介绍如何写出一个优雅的Dockerfile文件。 文章主要内容包括: Docker容器Dockerfile使用多阶构建感谢公司提供大量机器资源及时间让我们可以实践,感谢在此专题上不断实践的部分项目及人员的支持。 一、Docker容器1.1 容器的特点我们都知道容器就是一个标准的软件单元,它有以下特点: 随处运行:容器可以将代码与配置文件和相关依赖库进行打包,从而确保在任何环境下的运行都是一致的。高资源利用率:容器提供进程级的隔离,因此可以更加精细地设置CPU和内存的使用率,进而更好地利用服务器的计算资源。快速扩展:每个容器都可作为单独的进程予以运行,并且可以共享底层操作系统的系统资源,这样一来可以加快容器的启动和停止效率。1.2 Docker容器目前市面上的主流容器引擎有Docker、Rocket/rkt、OpenVZ/Odin等等,而独霸一方的容器引擎就是使用最多的Docker容器引擎。 Docker容器是与系统其他部分隔离开的一系列进程,运行这些进程所需的所有文件都由另一个镜像提供,从开发到测试再到生产的整个过程中,Linux 容器都具有可移植性和一致性。相对于依赖重复传统测试环境的开发渠道,容器的运行速度要快得多,并且支持在多种主流云平台(PaaS)和本地系统上部署。Docker容器很好地解决了“开发环境能正常跑,一上线就各种崩”的尴尬。 Docker容器的特点: 轻量:容器是进程级的资源隔离,而虚拟机是操作系统级的资源隔离,所以Docker容器相对于虚拟机来说可以节省更多的资源开销,因为Docker容器不再需要GuestOS这一层操作系统了。快速:容器的启动和创建无需启动GuestOS,可以实现秒级甚至毫秒级的启动。可移植性:Docker容器技术是将应用及所依赖的库和运行时的环境技术改造包成容器镜像,可以在不同的平台运行。自动化:容器生态中的容器编排工作(如:Kubernetes)可帮助我们实现容器的自动化管理。二、DockerfileDockerfile是用来描述文件的构成的文本文档,其中包含了用户可以在使用行调用以组合Image的所有命令,用户还可以使用Docker build实现连续执行多个命令指今行的自动构建。 通过编写Dockerfile生磁镜像,可以为开发、测试团队提供基本一致的环境,从而提升开发、测试团队的效率,不用再为环境不统一而发愁,同时运维也能更加方便地管理我们的镜像。 Dockerfile的语法非常简单,常用的只有11个: 2.1 编写优雅地Dockerfile编写优雅的Dockerfile主要需要注意以下几点: Dockerfile文件不宜过长,层级越多最终制作出来的镜像也就越大。构建出来的镜像不要包含不需要的内容,如日志、安装临时文件等。尽量使用运行时的基础镜像,不需要将构建时的过程也放到运行时的Dockerfile里。只要记住以上三点就能写出不错的Dockerfile。 为了方便大家了解,我们用两个Dockerfile实例进行简单的对比: FROM ubuntu:16.04RUN apt-get updateRUN apt-get install -y apt-utils libjpeg-dev \ python-pipRUN pip install --upgrade pipRUN easy_install -U setuptoolsRUN apt-get cleanFROM ubuntu:16.04RUN apt-get update && apt-get install -y apt-utils \ libjpeg-dev python-pip \ && pip install --upgrade pip \ && easy_install -U setuptools \ && apt-get clean我们看第一个Dockerfile,乍一看条理清晰,结构合理,似乎还不错。再看第二个Dockerfile,紧凑,不易阅读,为什么要这么写? ...

April 28, 2019 · 2 min · jiezi

URLOS应用开发基础10分钟制作nginx静态网站环境应用

URLOS开发者功能已上线有一段时间了,目前通过部分开发者的使用体验来看,不得不说URLOS在服务器软件开发效率方面确实有着得天独厚的优势,凭借docker容器技术与其良好的应用生态环境,URLOS必将迅速成为软件开发者的新宠儿。 本篇内容以入门为主,通过制作一个简单的静态网站环境应用,让新晋开发者能在短时间内对URLOS的开发流程有所认识。 URLOS基于docker容器技术,因此在应用开发过程中我们离不开docker的相关命令,对docker还不太了解的朋友,可以先大致了解一下docker的相关内容,本篇不做详细讨论。 URLOS应用开发的基本流程本篇目标是制作nginx静态网站环境,那么我们需要做的内容包括:运行一个基础镜像,在此镜像基础上安装nginx,设置网站根目录,打包并上传新镜像,通过URLOS添加新应用,发布并导出应用。 制作nginx静态网站环境一、拉取Alpine基础镜像为什么选择Alpine作为基础镜像?因为Alpine的文件体积小啊,基础镜像只有5.53MB,相比ubuntu镜像的88.9MB要小十几倍。使用docker pull alpine命令拉取alpine镜像: root@ubuntu:~# docker pull alpineUsing default tag: latestlatest: Pulling from library/alpinebdf0201b3a05: Pull completeDigest: sha256:28ef97b8686a0b5399129e9b763d5b7e5ff03576aa5580d6f4182a49c5fe1913Status: Downloaded newer image for alpine:latestroot@ubuntu:~#然后使用docker images命令查看镜像: root@ubuntu:~# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEurlos/urlos latest 4810506f7202 12 hours ago 447MBalpine latest cdf98d1859c1 2 weeks ago 5.53MBroot@ubuntu:~#二、更新镜像,安装nginx运行Alpine镜像并进入容器内部: root@ubuntu:~# docker run -it alpine sh/ #更换更新源: / # vi /etc/apk/repositories将其中内容换成阿里云的源 / # cat /etc/apk/repositorieshttps://mirrors.aliyun.com/alpine/v3.6/main/https://mirrors.aliyun.com/alpine/v3.6/community// #使用apk update执行更新: / # apk updatefetch https://mirrors.aliyun.com/alpine/v3.6/main/x86_64/APKINDEX.tar.gzfetch https://mirrors.aliyun.com/alpine/v3.6/community/x86_64/APKINDEX.tar.gzv3.6.5-25-g77eea063d8 [https://mirrors.aliyun.com/alpine/v3.6/main/]v3.6.5-18-gfdfe1f6192 [https://mirrors.aliyun.com/alpine/v3.6/community/]OK: 8453 distinct packages available/ #使用apk add nginx安装nginx: ...

April 27, 2019 · 2 min · jiezi

使用-nginx-反向代理多个-docker-容器

导语之前介绍 docker 的时候说过它的优势之一,就是可以在同一服务器中搭建多个环境,互相隔离。昨天就实际操作下,万万没想到如此多的坑,比之前从零开始搭建服务器都费时间。变换了好几种方案,最终还是解决了,中间的心酸就忽略吧,直接说操作方法。 架构服务器中已存在的是 laradock 镜像,可以运行 laravel 环境以及其他的 PHP,包含了 nginx、mysql、redis 等。我的想法是再添加一个 nginx 容器,用来做反向代理。根据子域名进行分发,可以分发给 laradock,也可以给其他任何容器(包括 wordpress、python、java)等等 修改 lradock要修改的只有一个地方,就是 nginx 监听的端口。 进入到 laradock 目录中修改 .env 文件,修改 NGINX_HOST_HTTP_PORT 值由 80 为 8000停止 nginx, docker-compose stop nginx重装 nginx,docker-compose build nginx启动 docker-compose up -d nginx这个时候在浏览器中是不能访问成功的,因为 nginx 已经不再监听 80 端口。 添加 nginx 容器新添加一个 nginx 容器用来做反向代理。在安装 laradock 的时候,已经有了 nginx:alpine 的镜像,可以直接生成容器。当然你也可以重新 pull 一个新的镜像。(推荐使用 alpine版本) 查看 nginx 镜像 ID,docker iamges生成新的 ngixn 容器, docker run --name proxy_nginx -p 80:80 -d [nginx image id]。也可以添加 -v 参数来映射配置文件,我的环境较少变动就不需要了此时在浏览器中访问,应该是 nginx 的默认页面,说明启动成功进入到生成的容器中 docker exec -it proxy_nginx sh安装 vim,apk add vim查看宿主机 ip,/sbin/ip route|awk '/default/ { print $3 }'在 /etc/nginx/conf.d/ 目录下添加新配置文件 laradock.conf,内容如下server { listen 80; server_name you_sits; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://[宿主机IP]:8000; }}退出容器,然后重启 docker restart proxy_nginx打开 8000 端口,参考这里结语这个时候访问的话,就可以代理到 laradock 中的 nginx 了。后续想要新增其他的容器,只要在 proxy_nginx 中添加新的代理规则就可以了。 ...

April 27, 2019 · 1 min · jiezi

URLOS应用开发基础课Docker基础镜像Alpine入门教程

我们在进行URLOS应用开发时,经常会用到一些基础系统镜像,如:ubuntu、CentOS、Debian等,我们可以通过docker pull命令直接拉取官方镜像。 root@ubuntu:~# docker pull ubuntu:18.0418.04: Pulling from library/ubuntu898c46f3b1a1: Already exists63366dfa0a50: Already exists041d4cd74a92: Already exists6e1bee0f8701: Already existsDigest: sha256:017eef0b616011647b269b5c65826e2e2ebddbe5d1f8c1e56b3599fb14fabec8Status: Downloaded newer image for ubuntu:18.04root@master-node:~# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEubuntu 18.04 94e814e2efa8 6 weeks ago 88.9MBroot@ubuntu:~#以上是从docker官方拉取的ubuntu18.04镜像,我们可以基于此镜像制作相关的应用,比如LNP网站环境、LAP网站环境、Nodejs环境等等。简单理解,就是说几乎所有的docker应用都是在这些镜像上层层打包后得到的,应用的最终体积也许有几百M甚至上G,我们如何为应用瘦身以减少对磁盘的消耗呢? docker官方为我们打造了Alpine。Alpine 的意思是“高山的”,比如 Alpine plants高山植物,Alpine skiing高山滑雪、the alpine resort阿尔卑斯山胜地,其实Alpine是一个操作系统。 Alpine 操作系统是一个面向安全的轻型 Linux 发行版。目前 Docker 官方已开始推荐使用 Alpine 替代之前的 Ubuntu 做为基础镜像环境。这样会带来多个好处。包括镜像下载速度加快,镜像安全性提高,主机之间的切换更方便,占用更少磁盘空间等。 Alpine的特点: 1、小巧:基于Musl libc和busybox,和busybox一样小巧,最小的Docker镜像只有5MB; 2、安全:面向安全的轻量发行版; 3、简单:提供APK包管理工具,软件的搜索、安装、删除、升级都非常方便。 4、适合容器使用:由于小巧、功能完备,非常适合作为容器的基础镜像。 在制作URLOS应用时,我们可以选择Alpine作为系统基础镜像,这样一来可有效降低应用的大小,方便其他用户下载安装。现在我们开始使用Alpine(如果你的系统中没有安装docker,建议先安装URLOS,因为它自带了docker)。 docker下运行Alpine使用docker pull命令拉取Alpine镜像 root@ubuntu:~# docker pull alpineUsing default tag: latestlatest: Pulling from library/alpinebdf0201b3a05: Pull completeDigest: sha256:28ef97b8686a0b5399129e9b763d5b7e5ff03576aa5580d6f4182a49c5fe1913Status: Downloaded newer image for alpine:latestroot@ubuntu:~#使用docker images命令查看镜像 ...

April 26, 2019 · 2 min · jiezi

windows下安装docker

作为伟大的21世纪接班人,怎么呢不会docker技术呢?好吧,由于种种原因,我的几块钱云服务器docker不能动它的配置,于是就想在win7上装一个练练手~ 1、下载windows下的docker工具docker-toolbox,我下载的是最新版 2、安装,我把方框中的勾去掉了(就是这么任性) tip1中间有个选择项,就是安装GIT,因为我已经安装过了,所以我也把这个勾去掉了 tip2然后就是一直next,有三个弹窗直接点安装就行了,静待安装完成。 tip3安装完成之后会有三个图标 3、双击 Docker Quickstart**那个图标打开图形化界面 tip1好吧,直接点击浏览,找到我自己之前安装git的目录,选择bin下的bash.exe 坑点好吧,事情怎么可能会这么一帆风顺!我遇到了一个错误 Error in driver during maching creation:this computer doesn't have vt-x/amd-..........搞个蛋蛋 !我的bios不支持虚拟化?网上查了查bios怎样打开虚拟化,好吧进入bios设置,什么esc、f2、f8、del都试了,才发现f12是真理(旁边同事就一脸蒙逼的看我重启了n次电脑……) 找找找,都没看到有V开头的单词!最后在CPU设置里头找到了,把disenable改成了enable,F10 yes enter,然后重启再次进行上面第第三步,ok,成功了! 注现在一般的bios都会支持虚拟化的,所以放心大胆的去装,网上说的先看看支不支持啥的,基本可以忽略。我i3一点都不虚。如下图,我打开虚拟化之后,还是不能直观的看到我是否打开了虚拟化。 注群里有朋友说github上的一个玩意儿报错,可以直接根据那个github地址下载,我看其它帖子都说放到C:UsersAdministrator.dockermachinecache这个下头去,如果碰到那个错误了可以试试

April 26, 2019 · 1 min · jiezi

下篇中高级前端大厂面试秘籍寒冬中为您保驾护航直通大厂

引言本篇文章会继续沿着前面两篇的脚步,继续梳理前端领域一些比较主流的进阶知识点,力求能让大家在横向层面有个全面的概念。能在面试时有限的时间里,能够快速抓住重点与面试官交流。这些知识点属于加分项,如果能在面试时从容侃侃而谈,想必面试官会记忆深刻,为你折服的~???? 另外有许多童鞋提到: 面试造火箭,实践全不会,对这种应试策略表达一些担忧。其实我是觉得面试或者这些知识点,也仅仅是个初级的 开始。能帮助在初期的快速成长,但这种策略并没办法让你达到更高的水平,只有后续不断地真正实践和深入研究,才能突破自己的瓶颈,继续成长。面试,不也只是一个开始而已嘛。~???? 建议各位小伙从基础入手,先看 (上篇)中高级前端大厂面试秘籍,寒冬中为您保驾护航,直通大厂(中篇)中高级前端大厂面试秘籍,寒冬中为您保驾护航,直通大厂小菜鸡博客求赞 ???? blog进阶知识Hybrid随着 Web技术 和 移动设备 的快速发展,在各家大厂中,Hybrid 技术已经成为一种最主流最不可取代的架构方案之一。一套好的 Hybrid 架构方案能让 App 既能拥有 极致的体验和性能,同时也能拥有 Web技术 灵活的开发模式、跨平台能力以及热更新机制。因此,相关的 Hybrid 领域人才也是十分的吃香,精通Hybrid 技术和相关的实战经验,也是面试中一项大大的加分项。 1. 混合方案简析Hybrid App,俗称 混合应用,即混合了 Native技术 与 Web技术 进行开发的移动应用。现在比较流行的混合方案主要有三种,主要是在UI渲染机制上的不同: Webview UI: 通过 JSBridge 完成 H5 与 Native 的双向通讯,并 基于 Webview 进行页面的渲染;优势: 简单易用,架构门槛/成本较低,适用性与灵活性极强;劣势: Webview 性能局限,在复杂页面中,表现远不如原生页面;Native UI: 通过 JSBridge 赋予 H5 原生能力,并进一步将 JS 生成的虚拟节点树(Virtual DOM)传递至 Native 层,并使用 原生系统渲染。优势: 用户体验基本接近原生,且能发挥 Web技术 开发灵活与易更新的特性;劣势: 上手/改造门槛较高,最好需要掌握一定程度的客户端技术。相比于常规 Web开发,需要更高的开发调试、问题排查成本;小程序 通过更加定制化的 JSBridge,赋予了 Web 更大的权限,并使用双 WebView 双线程的模式隔离了 JS逻辑 与 UI渲染,形成了特殊的开发模式,加强了 H5 与 Native 混合程度,属于第一种方案的优化版本;优势: 用户体验好于常规 Webview 方案,且通常依托的平台也能提供更为友好的开发调试体验以及功能;劣势: 需要依托于特定的平台的规范限定2. WebvievWebview 是 Native App 中内置的一款基于 Webkit内核 的浏览器,主要由两部分组成: ...

April 26, 2019 · 7 min · jiezi

解决-laradock-中-GuzzleCurl-出现-error-curl-7

导语今天在使用 Guzzle 的时候,出现了 [curl] 7: Failed to connect to xxx port 80: Connection refused 这个问题。没有查到相关的中文资料,最终踩了一些坑后解决。简而言之就是修改 docker-compose.yml 中关于 nginx 的配置,然后重新安装就可以了。 修改配置在 NGINX Server 修改如下 networks: frontend: aliases: - you_site backend: aliases: - you_site重装 nginx切换到 laradock 中docker-compose stop nginxdocker-compose build --no-cache nginxdocker-compose up -d nginx参考资料:GitHub issues。

April 25, 2019 · 1 min · jiezi

如何抵御大规模的DDoS攻击

发起DDoS的方法很多种,最基本的一种是:攻击者伪装出一个与攻击目标相同的IP地址,然后向预先选定的DNS服务器发送一个伪装的DNS请求,当DNS服务器接收到DNS请求时,服务器会检查其数据库,回复一个表示没有包含欺骗性IP地址的DNS记录的响应消息,因此无法追踪到攻击者来源。企业该如何应付这种攻击呢?群英网络教你几招。1.与一些DDoS防御供应商合作,如Arbor、CloudFlare、Akamai、Prolexic等,这是应对最严重攻击的一个可行方法; 2.如果没有足够资源购买第三方产品和服务的话,可以采取一些措施,尽量减小DDoS攻击的危害:①了解网站的互联网连接,定期报告统计信息;②部署防御机制,检查所有到达的DNS响应;③更多地将基础架构部署到云上。 因此,在防御和应对DDoS攻击时,保持警惕至关重要。管理员要了解互联网系统的最新攻击趋势、策略和流程,提前做好防御准备。

April 25, 2019 · 1 min · jiezi

基于-Docker-GogsJenkinsKubernetes-实践工程源代码的自动构建和持续集成与部署交付

本期目标 : 基于 Centos 7.6 , 封装出一个可用于运行 php 项目的开箱即用镜像本文不讨论 dockerfile 语法 , 并且假设你懂得基本的类unix 操作系统常识并拥有类unix 运行环境 (包括但不限于安装了mac 或 linux 的实体机 , 类unix虚拟机 , 安装了 MinGW 或 CygWin 的 windows 机器) , 并且认为你懂得基本的 docker 操作和有一定的 dockerfile 阅读能力准备工作建立工作目录 mkdir ~/docker-learncd ~/docker-learn创建Dockerfile touch Dockerfile然后拷贝你常用的 nginx.conf 到工作目录 cp xxx/nginx.conf nginx.conf封装基础镜像编辑我们创建好的 Dockerfile 基础内容声明本镜像继承自 centos 最新版 FROM centos安装 nginx创建nginx源文件 由于 centos 仓库里是没有 nginx 的 , 所以我们要自力更新添加nginx的源到 docker 里复制 nginx.org 里关于 RHEL 源的内容到 nginx.repo 文件也可以本地执行以下命令创建 nginx.repo ...

April 25, 2019 · 4 min · jiezi

Docker-之-ubuntu-安装

Docker 作为一种新兴的虚拟化方式,Docker 跟传统的虚拟机方式相比具有众多的优势。Docker 可以更高效的利用系统资源、更快速的启动时间、一致的运行环境、持续交付和部署、更轻松的迁移、更轻松的维护和扩展。 博主第一次使用Docker就深深喜欢上了这种方式,一次配置,到处运行,不用再反反复复的配置环境可以说是非常的方便了。本篇博客就来说一说Docker的安装及基本使用方法,后续还会不定时的更新Docker系列博客。 对比传统虚拟机Docker是什么?Docker属于容器的一种技术封装,提供更为简单易用的使用接口,让开发运维人员可以更方便快捷的使用容器。 特性容器虚拟机启动秒级分钟级硬盘使用一般为 MB一般为 GB性能接近原生弱于系统支持量单机支持上千个容器一般几十个从上面对比来看,容器的各方面性能及特性是优于虚拟机的。 Docker 的安装Docker是一个开放源码的产品,分为 社区版(Community Edition,缩写为 CE)和 企业版(Enterprise Edition,缩写为 EE)。社区版是免费的,而企业版包含一些收费服务,一般来说个人开发者用社区版就足够了,本篇博文的教程也只是针对社区版。 安装环境及版本: 系统:ubuntu 18.04 LTSDocker 版本:18.9.05英文好的小伙伴也可以直接阅读官方文档,本文只详细介绍 Ubuntu 系统下的 Docker 安装,其他系统的安装请自行参考官方文档。 MacWindowsCentOSDebianFedoraUbuntu其他Linux版本卸载老版本一般来说Ubuntu系统中默认是不会安装Docker的,但是如果安装了老版本的话可以使用下面的命令进行卸载。 $ sudo apt-get remove docker docker-engine docker.io containerd runc安装 Docker CE安装Docker CE有多种不同的方式: 设置Docker的存储库,然后安装。这种方式便于安装及更新,也是最推荐的方式。下载DEB软件包,手动安装并完全手动管理升级。在测试和开发环境中,部分用户选择使用自动便捷脚本来安装Docker。本篇博客将介绍第一种安装方式。 设置 Docker 存储库 更新apt包索引:$ sudo apt-get update允许apt通过HTTPS使用存储库来安装软件:$ sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common添加Docker官方 GPG 密钥:$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -添加完成之后,使用下面命令进行验证秘钥,通过搜索指纹的最后8个字符,验证现在是否具有指纹9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88的密钥 ...

April 25, 2019 · 2 min · jiezi

laradock-使用-phpworker-配置-supervisor

导语因为项目使用了队列,所以想着用 supervisor 来守护进程。开始在 workspace 中没有找到,准备自己安装了。后来一查才发现是自己大意了,原来是在 php-worker 中。 编辑配置文件切换到 laradocke/php-worker 目录中,Dockerfile 和 supervisord.conf 可以根据自己的需求修改,没有需求的话可以不做改动php-worker 还有关于 schedule 的配置,有需要的可以一并配置好在 supervisord.d 中有示例文件,根据示例文件新建 web-worker.conf 如下process_name=%(program_name)s_%(process_num)02dcommand=php /var/www/you_project_path/artisan queue:work --sleep=3 --tries=3 --daemonautostart=trueautorestart=truenumprocs=2user=laradockredirect_stderr=true启动容器在 laradock 目录下 docker-compose build --no-cache php-worker启动 docker-compose up -d php-worker结语很简单的几步就搞定了,这就是 laradock 的好处之一,当然这一切都是建立在 docker 之上。

April 24, 2019 · 1 min · jiezi

Kubernetes从懵圈到熟练读懂这一篇集群节点不下线

排查完全陌生的问题,完全不熟悉的系统组件,是售后工程师的一大工作乐趣,当然也是挑战。今天借这篇文章,跟大家分析一例这样的问题。排查过程中,需要理解一些自己完全陌生的组件,比如systemd和dbus。但是排查问题的思路和方法基本上还是可以复用了,希望对大家有所帮助。 问题一直在发生I'm NotReady 阿里云有自己的Kubernetes容器集群产品。随着Kubernetes集群出货量的剧增,线上用户零星的发现,集群会非常低概率地出现节点NotReady情况。据我们观察,这个问题差不多每个月,就会有一两个客户遇到。在节点NotReady之后,集群Master没有办法对这个节点做任何控制,比如下发新的Pod,再比如抓取节点上正在运行Pod的实时信息。 需要知道的Kubernetes知识 这里我稍微补充一点Kubernetes集群的基本知识。Kubernetes集群的“硬件基础”,是以单机形态存在的集群节点。这些节点可以是物理机,也可以是虚拟机。集群节点分为Master和Worker节点。Master节点主要用来负载集群管控组件,比如调度器和控制器。而Worker节点主要用来跑业务。Kubelet是跑在各个节点上的代理,它负责与管控组件沟通,并按照管控组件的指示,直接管理Worker节点。 当集群节点进入NotReady状态的时候,我们需要做的第一件事情,肯定是检查运行在节点上的kubelet是否正常。在这个问题出现的时候,使用systemctl命令查看kubelet状态,发现它作为systemd管理的一个daemon,是运行正常的。当我们用journalctl查看kubelet日志的时候,发现下边的错误。 什么是PLEG 这个报错很清楚的告诉我们,容器runtime是不工作的,且PLEG是不健康的。这里容器runtime指的就是docker daemon。Kubelet通过直接操作docker daemon来控制容器的生命周期。而这里的PLEG,指的是pod lifecycle event generator。PLEG是kubelet用来检查容器runtime的健康检查机制。这件事情本来可以由kubelet使用polling的方式来做。但是polling有其成本上的缺陷,所以PLEG应用而生。PLEG尝试以一种“中断”的形式,来实现对容器runtime的健康检查,虽然实际上,它同时用了polling和”中断”两种机制。 基本上看到上边的报错,我们可以确认,容器runtime出了问题。在有问题的节点上,通过docker命令尝试运行新的容器,命令会没有响应。这说明上边的报错是准确的. 容器runtimeDocker Daemon调用栈分析 Docker作为阿里云Kubernetes集群使用的容器runtime,在1.11之后,被拆分成了多个组件以适应OCI标准。拆分之后,其包括docker daemon,containerd,containerd-shim以及runC。组件containerd负责集群节点上容器的生命周期管理,并向上为docker daemon提供gRPC接口。 在这个问题中,既然PLEG认为容器运行是出了问题,我们需要先从docker daemon进程看起。我们可以使用kill -USR1 <pid>命令发送USR1信号给docker daemon,而docker daemon收到信号之后,会把其所有线程调用栈输出到文件/var/run/docker文件夹里。 Docker daemon进程的调用栈相对是比较容易分析的。稍微留意,我们会发现大多数的调用栈都类似下图中的样子。通过观察栈上每个函数的名字,以及函数所在的文件(模块)名称,我们可以看到,这个调用栈下半部分,是进程接到http请求,做请求路由的过程;而上半部分则进入实际的处理函数。最终处理函数进入等待状态,等待的是一个mutex实例。 到这里,我们需要稍微看一下ContainerInspectCurrent这个函数的实现,而最重要的是,我们能搞明白,这个函数的第一个参数,就是mutex的指针。使用这个指针搜索整个调用栈文件,我们会找出,所有等在这个mutex上边的线程。同时,我们可以看到下边这个线程。 这个线程上,函数ContainerExecStart也是在处理具体请求的时候,收到了这个mutex这个参数。但不同的是,ContainerExecStart并没有在等待mutex,而是已经拿到了mutex的所有权,并把执行逻辑转向了containerd调用。关于这一点,我们可以使用代码来验证。前边我们提到过,containerd向上通过gRPC对docker daemon提供接口。此调用栈上半部分内容,正是docker daemon在通过gRPC请求来呼叫containerd。 Containerd调用栈分析 与输出docker daemon的调用栈类似,我们可以通过kill -SIGUSR1 <pid>命令来输出containerd的调用栈。不同的是,这次调用栈会直接输出到messages日志。 Containerd作为一个gRPC的服务器,它会在接到docker daemon的远程请求之后,新建一个线程去处理这次请求。关于gRPC的细节,我们这里其实不用关注太多。在这次请求的客户端调用栈上,可以看到这次调用的核心函数是Start一个进程。我们在containerd的调用栈里搜索Start,Process以及process.go等字段,很容易发现下边这个线程。 这个线程的核心任务,就是依靠runC去创建容器进程。而在容器启动之后,runC进程会退出。所以下一步,我们自然而然会想到,runC是不是有顺利完成自己的任务。查看进程列表,我们会发现,系统中有个别runC进程,还在执行,这不是预期内的行为。容器的启动,跟进程的启动,耗时应该是差不对的,系统里有正在运行的runC进程,则说明runC不能正常启动容器。 什么是DbusRunC请求Dbus 容器runtime的runC命令,是libcontainer的一个简单的封装。这个工具可以用来管理单个容器,比如容器创建,或者容器删除。在上节的最后,我们发现runC不能完成创建容器的任务。我们可以把对应的进程杀掉,然后在命令行用同样的命令尝试启动容器,同时用strace追踪整个过程。 分析发现,runC停在了向带有org.free字段的dbus写数据的地方。那什么是dbus呢?在Linux上,dbus是一种进程间进行消息通信的机制。 原因并不在Dbus 我们可以使用busctl命令列出系统现有的所有bus。如下图,在问题发生的时候,我看到客户集群节点Name的编号非常大。所以我倾向于认为,dbus某些相关的数据结构,比如Name,耗尽了引起了这个问题。 Dbus机制的实现,依赖于一个组件叫做dbus-daemon。如果真的是dbus相关数据结构耗尽,那么重启这个daemon,应该是可以解决这个问题。但不幸的是,问题并没有这么直接。重启dbus-daemon之后,问题依然存在。 在上边用strace追踪runC的截图中,我提到了,runC卡在向带有org.free字段的bus写数据的地方。在busctl输出的bus列表里,显然带有这个字段的bus,都在被systemd使用。这时,我们用systemctl daemon-reexec来重启systemd,问题消失了。所以基本上我们可以判断一个方向:问题可能跟systemd有关系。 Systemd是硬骨头Systemd是相当复杂的一个组件,尤其对没有做过相关开发工作的同学来说,比如我自己。基本上,排查systemd的问题,我用到了四个方法,(调试级别)日志,core dump,代码分析,以及live debugging。其中第一个,第三个和第四个结合起来使用,让我在经过几天的鏖战之后,找到了问题的原因。但是这里我们先从“没用”的core dump说起。 没用的Core Dump 因为重启systemd解决了问题,而这个问题本身,是runC在使用dbus和systemd通信的时候没有了响应,所以我们需要验证的第一件事情,就是systemd不是有关键线程被锁住了。查看core dump里所有线程,只有以下一个线程,此线程并没有被锁住,它在等待dbus事件,以便做出响应。 ...

April 23, 2019 · 1 min · jiezi

将你的前端应用打包成docker镜像并部署到服务器仅需一个脚本搞定

1.前言前段时间,自己搞了个阿里云的服务器。想自己在上面折腾,但是不想因为自己瞎折腾而污染了现有的环境。毕竟,现在的阿里云已经没有免费的快照服务了。要想还原的话,最简单的办法就是重新装系统。而一旦重装,之前的搭建的所有环境就都白搭了。 再加上之前本身就想引入docker,所以就打算利用docker容器来部署这次的前端应用。 2.构建前端应用在打包之前,首先需要一个可正常运行的前端应用。这个可以使用umi或者create-react-app来构建。 3.nginx的默认配置文件然后需要在项目中加上默认nginx配置文件。 server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; }}4.编写本地构建脚本4.1. 移除上次的目录和Dockerfile#!/bin/bashif [ -d "./dist" ]; then rm -rf ./distfiif [ -f "./Dockerfile" ]; then rm -f ./Dockerfilefi因为每次更改后dist中的内容肯定与之前不同,其实这一步显得不是那么必要。运行npm的打包命令也会自动清楚该目录。 而清除Dockerfile则是为了防止更新了Dockerfile,而这次却不能得到最新的配置。 4.2. 打包前端应用执行前端的打包命令,生成静态文件目录。 yarn build4.3. 生成Dockerfileecho "FROM nginx:latest" >> ./Dockerfileecho "COPY ./dist /usr/share/nginx/html/" >> ./Dockerfileecho "COPY ./default.conf /etc/nginx/conf.d/" >> ./Dockerfileecho "EXPOSE 80" >> ./DockerfileFROM制定了该定制容器的基础镜像为nginx:latest;COPY命里将打包好的静态文件目录复制到容器内的/usr/share/nginx/html/目录下,然后将nginx的配置写入容器中对应的位置; EXPOSE则是设置对外暴露容器的80端口。 4.4. 生成并推送定制imagedocker build -t detectivehlh/mine .docker login -u detectivehlh -p ********docker push detectivehlh/mine这里是在开发本地,使用docker命令来打包,所以该脚本对docker有强依赖。build命令表示打包docker应用的,-t选项则制定了docker镜像的名字和tag,tag会默认为latest。 ...

April 23, 2019 · 2 min · jiezi

laradock 添加 redis 配置

导语今天想去修改 redis 的配置,才发现默认安装的时候并没有添加 redis 的配置。所以重装配置下。 修改 Dockerfile编辑 redis/Dockerfile 如下 FROM redis:latestLABEL maintainer="Mahmoud Zalt <mahmoud@zalt.me>"## For security settings uncomment, make the dir, copy conf, and also start with the conf, to use itRUN mkdir -p /usr/local/etc/redisCOPY redis.conf /usr/local/etc/redis/redis.confVOLUME /dataEXPOSE 6379CMD ["redis-server", "/usr/local/etc/redis/redis.conf"]#CMD ["redis-server"]编辑配置文件默认情况 redis 目录下有 redis.conf 文件,修改以下两点即可 注释 bind 127.0.0.1protected-mode 改为 no其他配置根据自己情况进行修改。 重装 redis切换到 laradock 目录停止 redis docker-compose stop redis重装 docker-compose build --no-cache redis启动 docker-compose up -d redis正常情况就启动成功了。 ...

April 22, 2019 · 1 min · jiezi

K8S 生态周报| 2019-04-15~2019-04-21

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。Prometheus v2.9.0 正式发布Prometheus 是 CNCF 毕业项目,可用于监控系统及服务状态。它整体是使用 Pull 的模式,在周期时间内采集目标的 metrics ,并且提供了 PromQL 的查询语言,以供对监控数据进行查询过滤等操作。并且可以通过配置规则来触发报警等。我首次接触 Prometheus 大概是在 2015 年 0.15.0 版本左右,当时 Prometheus 还处于比较早期的阶段,不过在进入 CNCF 后,Prometheus 基本就成为了 K8S 监控的实施标准了,并且多数软件也都增加了对 Prometheus metrics 的支持。 v2.9.0 的主要更新: 从 2.8 开始引入了的从 WAL 读取进行 remote write 有时候会丢数据的问题已经得到修复;Kubernetes 和 OpenStack 在服务发现时候增加了更多元数据;Consul 现在支持多 tag;添加了一个 honor_timestamps 的选项;TLS 证书会自动从磁盘加载;日志也变的更易读;其他更新请阅读 ReleaseNote Linkerd 2.3 正式发布Linkerd 是一个 service mesh 旨在提供平台范围的可观察性,可靠性和安全性,而无需用户更改代码。在本月初的周报推送中,推荐了一篇关于 Linkerd v2 从产品中吸取的教育和经验的文章,Linkerd v2 使用 Go 和 Rust 进行了重写,并因此获得了巨大的收益。 ...

April 22, 2019 · 1 min · jiezi

Gartner容器市场指南中国语境:容器成为新常态,灵雀云等本地厂商在选择中占据优势

在2019年2月“ China Summary Translation: 'Market Guide for Container Management Software'”的报告中,Gartner认为,在中国市场,容器技术的使用是近期的热点。本地厂商由于能够贴近客户实际需求,而在选择中占据优势,例如阿里云、灵雀云等中国本地厂商。 Gartner容器市场指南 报告中Gartner指出,到2020年,全球50%以上的企业将在生产环境中运行容器。容器的普及程度将在未来18到24个月内持续上升。 随着容器技术的日渐成熟,客户在部署微服务平台时,往往会考虑容器落地。但是,由于其快速敏捷的特点,容器的数量会在快速扩展时急剧上升,大大增加了技术管理的复杂度。原来虚拟机的管理方式已经无法应对容器管理,很多客户使用容器管理软件来协助管理大规模的容器集群。 在中国市场,容器技术的使用是近期的热点。目前,主要是互联网公司在大规模部署使用容器技术,但在生产环境中部署超过50个容器的大型企业案例并不多见。Gartner认为,本地厂商由于能够贴近客户实际需求,而在选择中占据优势,例如,阿里云、灵雀云等中国本地厂商。 Gartner给出几个关键结论: 应用开发者是容器技术的主要使用者,但容器管理软件供应商越来越多地将基础设施和运营(I&O) 作为目标领域,以开发企业级市场机会。 容器编排能力十分关键,需要重点考虑,但是选择解决方案时也须考虑其他方面的能力,如应用生命周期集成、策略管理、监控、安全、存储、网络、治理以及应用编程接口(API)和管理用户界面(UI)功能。 很多供应商强调多云的主要优势,尝试将软件作为支持多云环境部署和工作负载可移动性的层结构来提供,以减少公有云锁定。现在判断这种部署模式是否会成功,还为时尚早。 应用开发和运营领域的发展日益完善,这些领域与容器技术有很大的互补性,包括: 应用开发——DevOps将不断推动面向CI / CD模型的交付最佳实践。应用架构——组件化云原生设计, 包括网格应用和服务架构(MASA),miniservices和microservices,正在不断发展。基础设施管理——作为最佳实践的不可变的基础设施发展。云计算的采用还在继续,自服务、自动化和水平可伸缩组件将成为标准。 Gartner指出,针对内部定制开发的容器技术兴趣在不断增加,市场上将出现更多的供应商。其中许多供应商都有一些“遗产”,如应用程序发布自动化,持续配置自动化或PaaS。ISV也将增加对容器的使用,这要求企业具有支持容器的基础设施。一些早期采用的企业已经拥有了自己的容器堆栈。但是,大多数组织没有广泛或深度的专业知识来自己做。他们需要解决方案层面的意见。例如,用本地容器工具,还是从PaaS发展而来的工具?这没有好坏之分,取决于开发人员所希望的抽象级别。 关于容器的未来 为了解容器当前和未来的状态,国外研究分析师 Tom Smith近期收集了30余位积极使用容器技术的IT高管的见解。大家一致的观点认为:容器继续成熟,采用率上升,复杂度下降,Serverless兴起。 成熟 我们期待与AI,AR和VR一起使用更多的技术,随着人们使用AI轻松地开发、部署和管理容器,容器将会被大量采用和创新,会有更多的计算能力来更快地完成任务。 预计会有越来越多的人采用,容器在企业中已经被高度渗透。CNCF表示容器已经有60%-70%的部署,但是运行在Kubernetes上的计算工作负载占比要低得多。因此,Kubernetes还有巨大的增长机会。 越来越多的公司将会发现容器的好处,不仅因为可以使用容器来构建新的应用程序,而且真正开始重构现有的应用程序,并有效利用底层平台提供的水平可伸缩性等功能。企业从谈论云和容器转向在生产中使用容器,容器的使用成为主流。与此同时,围绕安全性和合规性的思考也将改变。 容器在容器编排和调度环境中提供了更好的状态管理,以及更好的执行时间,以支持无服务器的用例。 容器使用率将继续增长。推动新技术快速部署的能力不容忽视,容器的快速部署、管理和短生命周期的快速发展将推动新功能的开发。公司不得不跟上容器技术环境的快速变化,安全、编排和开发等领域都充斥着破坏的机会! 未来,容器将作为企业应用部署和管理的关键基础设施。随着技术的成熟,它会变得更加稳定、标准化和便携。希望成熟的容器技术能够带来更多的用例,诸如应用程序智能、性能表现等。 就像所有优秀的技术一样,容器变得“Boring”。解决方案提供商在包装和分销方面做得更好,将会有更多关于如何在容器周围加入信任,确保不是恶意以及防止臃肿的知识。 围绕Kubernetes的编排正在标准化,这将加速开源和商业生态系统的发展,并推动工具开发。还将看到,随着云供应商提供一致的产品,这个堆栈也将成熟起来。甚至微软、亚马逊和IBM都支持Kubernetes。五年后,不运行Kubernetes和Docker的企业将成为少数。 清晰 容器将像任何优秀的技术一样继续消失于背景中,工具使得利用技术变得更容易,容器的部署和使用将有更大的简化。 容器是一种在本地或云中构建类云应用程序的机制,容器变得更容易处理和扩展,没有单点故障,也没有单一供应商。 容器使事情变得不那么复杂,成为新的常态。开发人员希望在容器中构建所有新应用程序,人们需要改变构建的方式,首先分析应用程序,以便在发布时,可以监控从构建到生产到建设和扩展的全流程。 1)今天Kubernetes不是以app开发者为核心角色而构建的。需要让Kubernetes更易于开发人员快速启动和运行。 2)我们看到了在Knative和OpenFast等Kubernetes之上构建抽象的趋势,在Kubernetes之上部署了无服务器功能,抽象了the knobs of Kubernetes。随着越来越多的项目成熟并以原生方式运行,更多开发人员可以更轻松地使用该技术。只有28%的应用程序在容器上运行,它还处于早期阶段,我们有机会让这项技术变得更加平易近人和实用。 容器仍然太复杂。如果比较一下现在开发人员所需要的知识量,就会发现间接需要的能力比五六年前要复杂得多。五年前,如果想构建一个Python应用程序,有一些众所周知的标准。现在开发人员不仅要学习如何生成Docker镜像,还要学习如何在编排系统上部署,如何将配置传递到容器,以及所有关于安全性的细节。最终,开发人员将不必处理容器,因为更高级别的抽象是构建在容器之上的。 无服务器和FaaS已经在路上 在开发人员体验和开发速度方面,容器的价值得到坚实地证明。然而,在容器安全性方面肯定会有所改进。未来,我们设想一个更安全的容器,运行沙箱在Nano VMs,就像Kata容器或AWS Firecracker一样。Serverless函数将代替传统API应用程序的大量工作。 在运营框架和如何描述自动化之间有两个巨大的机会。Kubernetes已经成为标准。快速脚本工作。运营者有可能在非常强大的环境中实现这一目标。我们一直在寻找可以使用的80/20工具。当使用标准化的YAML语言进入Kubernetes时,标准化的应用程序自动化将为我们提供一个功能强大的地方,在这里我们可以看到一个真正的服务目录。无服务器FaaS也非常令人兴奋,因为它允许您只专注于应用程序的逻辑。 容器使每个人都可以轻松实现无服务器。没有必要依赖虚拟机,虚拟机正在消失。它更容易转向Serverless,容器随着时间的推移会有所改善。将有更多选项可以在容器内运行更多应用程序。他们将继续改变,改善,变得更加稳定,更快地从失败中恢复,同时省下大笔资金。 无服务器和FaaS已经在路上。更高级别的抽象有助于在系统中获得更小的组件。随着颗粒越来越小,必须弄清楚如何管理和知道在哪里运行,这时候 Istio作为一种服务网格产品,可以帮助跟踪所有组件。 1)在去年的KubeCon上,“Serverless”计算的概念是指向容器创新未来的一个重要话题和热点——即构建和部署几乎任何类型的应用程序,而无需配置或管理运行这些应用程序的服务器。此外,用户将根据使用模式付费,只支付所消耗的计算时间,不运行时不收费。 2) 容器最终将取代虚拟机。与vm相比,容器提供了显著的优势,如降低了部署成本、显著降低了启动性能、减少了机器占用空间,且具备易用性。随着越来越多的公司和IT组织使用容器,将会出现应用程序从虚拟机到容器的大规模迁移。 3) 容器的采用幅度将远远超出仅以Docker为主要容器类型的情况。竞争产品将被更广泛地接受和使用。Docker作为市场领导者,已经偏离了标准容器技术的开发,而是更加专注于开发和营销一个全面的应用程序开发平台。导致其他容器产品的普及和使用的大幅增长。 参考资料: Gartner “China Summary Translation: 'Market Guide for Container Management Software'“,by Kevin Ji & Dennis Smith, Published on 18 February 2019, ID: G00382483.2.The Future of Containers ...

April 22, 2019 · 1 min · jiezi

Docker 使用简介

Docker 是使用 GoLang 开发的开源容器引擎,可以方便的打包开发好的应用,然后分发到任意 linux 主机上。 与传统的虚拟机相比拥有以下优势: 高效的系统资源利用率由于不需要进行硬件虚拟和运行完整的操作系统等额外开销,无论是应用执行速度、内存损耗或者文件存储速度, Docker 都更加高效 更快的启动速度Docker 容器应用直接运行与宿主内核,无需启动完整的操作系统,可以做到秒级启动 一致的运行环境Docker 镜像提供了除内核外的完整运行环境,确保了应用运行环境的一致性 持续交付和部署可以通过 Docker 镜像来实现服务的持续交付、部署。使用 Dockerfile 来构建镜像,使用持续集成系统进行集成测试;使用镜像结合持续部署系统进行自动部署 迁移轻松只需要迁移镜像及镜像运行的数据就可在其他主机或平台运行 易于维护和扩展由于使用镜像进行部署,使维护更为容易。由于支持在镜像的基础上进行定制,使得扩展变得更简单。而官方也维护了一大批高质量的镜像,大大降低了镜像的制作成本 基本概念仓库Docker 提供了仓库(Repository)用于存放制作好的镜像,方便使用者获取,在本地可通知配置多个 Repository 。 拉取可以使用命令来拉取镜像: docker pull [repo url>/]image name> 默认的 repo url 是 hub.docker.com ,拉取默认仓库中的镜像时是不需要 url 的。如拉取 debian : docker pull debian 。 推送我们也可将自己制作好的镜像推送到仓库,以便分发,使用命令: docker push [<repo url>/]<image name>[:<image tag>> 搜索使用 docker search 命令则可搜索默认 repo url 内的镜像。 镜像加速 由于默认 repo url 在国外,为了加快拉取速度,需要指定其为国内的,向 /etc/docker/daemon.json 中添加: { "registry-mirrors": ["https://registry.docker-cn.com"]}便可使用 Docker 在中国的镜像加速站。 ...

April 21, 2019 · 2 min · jiezi

Serverless五大优势,成本和规模不是最重要的,这点才是

导读:近期灵雀云技术专家邵明岐翻译了Mike Roberts & John Chapin所著的《What is Serverless》一书的部分内容,可以说是对Serverless科普与观察的上佳素材。在了解了何为Serverless,各种服务组件之后,如何将服务组件组合成完整的应用程序? 基于Serverless开发的应用架构什么样子?与传统非Serverless应用程序架构相比,Serverless有哪些优势?本文将回答这些问题。原著:《What is serverless : understand the latest advances in cloud and service-based architecture》作者:Mike Roberts & John Chapin译文来源:深入浅出谈架构(ID:deep-easy-arch)译者:灵雀云邵明岐假设有这么一个应用程序,它是一个支持多用户的手机游戏,具有以下高级要求:友好的移动端交互界面具备用户管理和身份验证有一些基本的业务逻辑,比如游戏排行榜,历史记录等我们暂时忽略游戏中可能会遇到的其他功能,毕竟我们的目的不是实际开发一个游戏,而是将Serverless程序架构与传统的非serverless架构进行比较。传统非Serverless架构 根据上面的要求,传统非Serverless架构看起来应该是这样的:Native Mobile App 是iOS或者安卓客户端。Java Application Server是Java代码编写的应用逻辑,运行在Tomcat或者JBoss这类应用服务器里面。数据存储在关系型数据库,比如Mysql里面。在这个架构中,移动应用程序负责呈现游戏界面并处理来自用户的输入,但它将大多数实际逻辑删除到后端,从代码的角度来看,移动应用程序简单轻便,它使用HTTP调用后端Java应用程序提供的不同API。用户管理、身份验证和各种游戏操作都使用Java应用程序代码进行封装, 后端应用程序还与单个关系数据库交互,以便维护正在进行的游戏的状态,并存储已完成游戏的结果。为什么要改变架构?这个简单的架构似乎符合我们的要求,那么为什么对它做改进呢? 关键在于未来开发和运维方面带来的一系列潜在的挑战和陷阱。在构建游戏时,需要具备iOS和Java开发方面的专业知识,以及配置,部署和操作Java应用程序服务器的专业知识,还需要配置和操作关系数据库服务器。 除了应用服务器和数据库,也需要配置和运行各自的主机,无论这些系统是基于容器还是直接在虚拟或物理硬件上运行。 我们还需要通过配置路由策略,访问控制列表等,来确保系统组件之间以及用户端和服务端之间的网络连通性。有了上面这些,我们仍然只是提供最基本的让游戏可用的环境还没有涉及安全性、可扩展性或高可用性,这些都是现代生产系统的关键方面。 最重要的是,即使在简单的体系结构中,也存在许多固有的复杂性,用来满足现实世界各种各样的需求。 构建系统并不难,但是当我们修复错误,添加功能或尝试快速构建新的创新想法时,所有这些复杂性将会变成强大的阻力。如何改变?现在已经发现了传统架构的一些挑战,如何改变它? 让我们看看如何能够满足高级需求,并使用Serverless架构模式和组件来解决传统方法的一些挑战。在之前的文章已经说过了,Serverless组件可以分为两类,BaaS和FaaS。 考虑到游戏的要求,其中一些可以通过BaaS组件解决,一些可以通过FaaS组件解决。Serverless 架构基于Serverless构建的游戏,架构看起来应该是下图这个样子的:虽然用户界面仍是移动应用程序的一部分,需要自己通过代码来实现,但用户身份验证和管理可由AWS Cognito等BaaS服务处理,这些服务可以直接从移动应用程序调用,以处理注册和身份验证等面向用户的功能,其他后端组件可以使用相同的BaaS来检索用户信息。现在由BaaS处理用户管理和身份验证,后端Java应用程序的逻辑被简化了, 可以使用另一个组件AWS API Gateway,以安全、可扩展的方式来处理移动应用程序和后端游戏逻辑之间的HTTP请求。 然后可以将每个不同功能的操作封装在FaaS函数中。这些后端FaaS功能可以与像DynamoDB这样的NoSQL数据库进行交互,以存储游戏的状态。 实际上,一个重大变化是不再在服务器端应用程序代码中存储任何会话状态,而是将所有会话状态保存到NoSQL存储中。 虽然这可能看起来很麻烦,但它有助于扩展。移动应用程序可以无缝访问同一个数据库,以检索过去的结果和排行榜数据。 这允许我们将一些业务逻辑移动到客户端实现,而不是将其放到到后端实现。Serverless架构优势这种新的Serverless架构看起来很复杂,而且它比传统架构需要更多的组件,但是,由于我们使用完全托管的Serverless组件,已经消灭了很多因为管理应用程序基础设施和底层系统而带来的挑战。我们编写的代码现在几乎完全集中在游戏独特的业务逻辑上,更重要的是,组件已经解耦和分离,因此,可以非常快速地将它们切换出来或添加新逻辑,而不会出现非无服务器架构中固有的阻力。扩展,高可用性和安全性也有所提升,这意味着随着我们的游戏越来越流行,不需要担心购买功能更强大的服务器,也不需要担心数据库是否会崩溃,或者排查防火墙配置故障。简而言之,我们降低了制作游戏的人工成本,以及运行游戏的风险和计算成本,它的所有组成部分都将灵活扩展。 当我们有一些新的想法,交付期会大大缩短,可以开始获得反馈并更快迭代。云计算的基础设施外包带来五大好处:降低人工成本、降低风险、降低基础设施成本、扩展性、交付时间 。Serverless 同样也有这五大优点, 前四个都或多或少是关于成本节约的,这就是Serverless最为人所知的:如何以更低的成本做以前做过的同样的事情。但是,对我们来说,节省成本并不是无服务器最令人兴奋的部分,最大的好处是,它减少了从新的想法到实施上线的时间,换句话说,它能够让你更快地创新。降低人工成本我们在之前说过,Serverless本质上不再需要关心自己的服务器和进程 ,只需要关心应用程序的业务逻辑和状态,所有其他不必要的工作都交给平台来处理。这里的第一个明显好处是运维工作量减少, 您不再管理操作系统,补丁级别,数据库版本升级等。如果您正在使用BaaS数据库,消息总线或对象存储,那么祝贺你,这些基础架构也都不要你来运维。通过其他BaaS服务,对于节省人工成本是比较直观的,自己开发的逻辑更少了。 我们已经多次讨论过身份验证的BaaS服务,其中最大的好处是可以使用较少的代码来定义开发、测试、部署和运营,所有这些都减少了工程师时间成本,另一个例子是像Mailgun这样的第三方邮件 BaaS 服务,它消除了处理电子邮件发送和接收的大部分复杂工作。与传统方法相比,FaaS还具有显著的劳动力成本优势。 使用FaaS进行软件开发得以简化,因为大部分基础架构代码已移至平台。 这里的一个例子是HTTP API服务的开发,这里所有的HTTP级请求和响应处理都是由API网关完成的。使用FaaS进行部署更容易,因为我们只是上传打包成Zip格式(如果是 JS或者Python脚本语言)的基本代码,或者如果是Java的话,则上传普通的JAR文件,没有要管理的Puppet,Chef,Ansible或Docker配置。其他类型的操作活动也变得更加简单,例如,由于不再关注“永远在线”服务器进程,因此可以将监控限制为更多面向应用程序的指标。 这些是统计信息,例如执行持续时间和面向客户的指标,而不是可用磁盘空间或CPU使用率。降低风险当考虑软件应用风险时,我们经常考虑对故障和宕机的敏感程度,我们的团队负责管理的不同类型的系统或组件的数量越多,发生问题的风险就越大。我们可以不是自己管理这些系统,而是像之前描述的那样,让“外包”系统来解决这些问题。虽然整体而言仍然面临应用程序发生故障的风险,但我们选择以不同的方式管理风险–我们现在依靠其他人的专业知识来解决其中的一些故障,而不是自己修复它们。这通常来说是一个好主意,因为应用的技术栈中,一些技术是平时很少发生变更的,当它们发生故障时,修复时间和难度都不确定。通过Serverless,我们可以显著减少直接操作的技术栈数量,那些我们仍在自己管理的技术,通常是我们非常熟悉并且频繁变更的,因此我们更有能力在失败时自信地处理失败。例如,管理分布式NoSQL数据库。 一旦安装了组件,节点发生中的故障可能相对罕见,但是当它发生故障时,会发生什么? 您的团队是否具备快速有效地诊断,修复和恢复问题的专业知识? 常常没有。 相反,团队可以选择使用Serverless 的NoSQL数据库服务,例如Amazon DynamoDB, 虽然DynamoDB中的中断偶尔会发生,但由于亚马逊拥有致力于此特定服务的整个团队,因此它们发生故障的次数更少,并且能够更快的恢复。因此,我们说当使用Serverless技术时,风险会降低,因为组件的预期宕机时间会减少,并且修复它们的时间会更少。降低资源投入成本通常,当运行应用程序时,我们必须弄清楚它们将运行的底层主机类型和数量。 例如,数据库服务器需要多少内存和CPU? 需要多少个不同的实例来支持扩展? 或者如何支持高可用性(HA)?一旦规划了我们需要的主机或资源,就可以分配应用程序的哪些部分将在哪些资源上运行。 最后,一旦我们开始准备部署应用程序,就需要实际获得我们想要的主机,这是环境配置。整个环境配置过程很复杂,我们很少提前知道我们的资源要求是什么,因此高估了我们的计划,这称为过度配置,这实际上是正确的做法:拥有备用容量并保持应用程序运行比在负载下降低更好。对于某些类型的组件(如数据库),可能很难在以后扩展,因此可能希望通过过度配置,来承载未来预期的负载。过度供应意味着我们总是为满足处理峰值预期负载所需的容量付费,即使我们的应用程序没有遇到负载也是如此。最极端的情况是,我们的应用程序处于空闲状态时,我们正在为服务器付费,而事实上它并没有做任何有用的事情。但即使我们的应用程序处于活动状态,我们也不希望主机得到充分利用。相反,我们希望留下一些空间,以应对意外的负载峰值。无服务器给这个领域带来的巨大好处是不需要计划,分配或配置资源,让服务精确地提供我们在任何时间点所需的容量,如果我们没有任何负载,那么不需要任何计算资源,也不会支付任何费用。 如果我们只有1 GB的数据,我们不需要容量来存储100 GB。我们相信当需要时,服务将按需扩展,并且这同样适用于FaaS和BaaS服务。除了消除资源分配带来的问题,无服务器还使成本更加高效。对于负载不一样的各种应用程序,我们将通过使用无服务器来节省资源成本。 例如,如果我们的应用程序每小时只运行5分钟,我们只需支付每小时5分钟,而不是整个60分钟。 此外,良好的无服务器产品将具有非常精确的使用增量; 例如,AWS Lambda按100毫秒的使用时间收费,比EC2的每小时计费精确36,000倍。在现代非 Serverless 应用程序中,我们通过自动伸缩等技术获得了一些收益,但是,这些方法通常不如无服务器产品那么精确,并且通常无法自动扩展数据库。提高扩展性所有这些资源成本优势都来自于这样一个事实,即Serverless服务可以精确地满足我们的需求。那么如何才能真正实现这种扩展呢? 我们需要设置自动缩放组吗? 监控流程? 没有! 事实上,缩放是自动完成的,不费力气。以AWS Lambda为例。 当平台收到第一个触发函数事件时,它会启动一个容器来运行代码,如果在收到另一个事件时仍在处理此事件,则平台将启动代码的第二个实例以处理第二个事件。 这种自动、零管理、水平扩展将持续到Lambda有足够的代码实例来处理负载。一个特别好的方面是AWS仍然只会根据你代码执行的时间收取费用,无论它有多少个容器要启动。例如,假设所有事件的总执行时间相同,在一个容器中按顺序调用Lambda 100的成本与在100个不同容器中同时调用Lambda 100次的成本完全相同。减少交付周期通过采用Serverless技术,可以带来显著的成本节省。康卡斯特有线电视公司首席技术官Sree Kotay在2016年8月AWS峰会上说:他不是在谈论Serverless,他在谈论康卡斯特如何从各种其他基础设施外包中获益匪浅,从“本地”转向云计算:经历了云和敏捷的这一旅程,过去五年我们已经实现了收益,而且这些收益都是围绕成本和规模进行的,它们是关键且重要的,但有趣的是它们并不是最引人注目的,最关键部分是这真的改变了你的创新周期,它从根本上改变了你对产品开发的看法。Sot Kotay复制代码我们要提出的一点是,一家大公司的首席技术官说,成本和规模对他来说并不是最重要的,最重要的是创新。 那么Serverless如何在这方面提供帮助呢?Adrian Cockcroft(AWS云架构战略副总裁,Netflix前云架构师)谈到:我们开始看到开发应用程序的时间越来越短,小型开发团队在短短几天内从头开始构建生产就绪的应用程序。 他们使用简短的功能和事件将强大的API驱动的数据存储和服务粘合在一起。 已完成的应用程序已具有高可用性和可扩展性,高利用率,低成本和快速部署。-Adrian Cockcroft复制代码在过去几年中,我们看到通过持续交付和自动化测试以及Docker等技术改进开发的增量周期时间取得了很大进展。 这些技术很棒,但只有在设置和稳定后才能实现。 对于真正蓬勃发展的创新而言,缩短周期时间是不够的,您还需要更短的交付周期–从新产品或功能的概念化到以最小的可行方式部署到生产环境的时间。由于Serverless消除了在生产中大规模构建,部署和运行应用程序的大量附带复杂性,因此它为我们提供了巨大的杠杆作用,以至于软件交付方式可以颠倒过来。通过正确的组织支持,创新和“精益创业”风格,实验可以成为所有企业的默认工作方式,而不仅仅是为初创公司或“黑客日”保留的东西。这不仅仅是一种理论。 除了Adrian的的观点之外,我们看到相对缺乏经验的工程师完成项目通常需要几个月的时间,并需要更多资深工程师的帮助。 相反,使用Serverless,他们能够在几天内基本上无需帮助地实施项目。这就是为什么对Serverless感到非常兴奋:除了节省所有成本之外,还可以释放他们的能力,让他们专注于让产品与众不同的地方。 ...

April 18, 2019 · 1 min · jiezi

用cAdvisor InfluxDB Grafana监控docker容器的TcpState

问题搭建完cAdvisor InfluxDB Grafana监控集群后, 发现没有tcp相关的数据.源码版本:https://github.com/google/cad…git commit hash:9db8c7dee20a0c41627b208977ab192a0411bf93搭建cAdvisor InfluxDB Grafana参考https://botleg.com/stories/mo…定位过程是否cadvisor没有记录tcp state?容易搜索到, 因为cadvisor的高cpu占用, 需要–disable_metrics=““https://github.com/google/cad…实际上并非如此. 不带任何参数情况下, 本地启动cadvisor.~/gopath/src/github.com/google/cadvisor(master*) » sudo ./cadvisor -logtostderr 在浏览器中打开 http://127.0.0.1:8080/containers/ 可以看到response中, 带有TcpState.是否写入了influxdb?打开influx db shellInfluxDB shell 0.9.6.1> show databasesname: databases—————name_internalmydbcadvisor> use cadvisorUsing database cadvisor> show tag keysname: cpu_usage_system———————-tagKeycontainer_namemachine可以看到, 这些tagKey对应grafana中的select column.那么, 是否cadvisor没有写入influxdb呢?cadvisor/storage/influxdb/influxdb.go:174func (self *influxdbStorage) containerStatsToPoints( cInfo *info.ContainerInfo, stats *info.ContainerStats,) (points []*influxdb.Point) { // CPU usage: Total usage in nanoseconds points = append(points, makePoint(serCpuUsageTotal, stats.Cpu.Usage.Total)) // CPU usage: Time spend in system space (in nanoseconds) points = append(points, makePoint(serCpuUsageSystem, stats.Cpu.Usage.System)) // CPU usage: Time spent in user space (in nanoseconds) points = append(points, makePoint(serCpuUsageUser, stats.Cpu.Usage.User)) // CPU usage per CPU for i := 0; i < len(stats.Cpu.Usage.PerCpu); i++ { point := makePoint(serCpuUsagePerCpu, stats.Cpu.Usage.PerCpu[i]) tags := map[string]string{“instance”: fmt.Sprintf("%v”, i)} addTagsToPoint(point, tags) points = append(points, point) } // Load Average points = append(points, makePoint(serLoadAverage, stats.Cpu.LoadAverage)) // Memory Usage points = append(points, makePoint(serMemoryUsage, stats.Memory.Usage)) // Working Set Size points = append(points, makePoint(serMemoryWorkingSet, stats.Memory.WorkingSet)) // Network Stats points = append(points, makePoint(serRxBytes, stats.Network.RxBytes)) points = append(points, makePoint(serRxErrors, stats.Network.RxErrors)) points = append(points, makePoint(serTxBytes, stats.Network.TxBytes)) points = append(points, makePoint(serTxErrors, stats.Network.TxErrors)) self.tagPoints(cInfo, stats, points) return points}结论需要修改cadvisor代码, 将自己需要的metrics加上. ...

April 17, 2019 · 1 min · jiezi

Docker入门(二)

检查安装情况centos7下// 删除旧版本和相关依赖yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine// 安装依赖yum install -y yum-utils \ device-mapper-persistent-data \ lvm2// 配置稳定的repositoriesyum-config-manager \ –add-repo \ https://download.docker.com/linux/centos/docker-ce.repo// 安装docker yum install docker-ce docker-ce-cli containerd.io // 完成后通过docker version命令看到docker信息:docker version// 启动:systemctl start docker// 开机启动:systemctl enable docker // 接下来安装docker-composecurl -L “https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose// 给docker-compose执行权限chmod +x /usr/local/bin/docker-compose// 检查,运行docker-compose –versiondocker-compose –version ubuntu16.04下请输入代码docker参考文档:https://docs.docker.com/get-s…docker-compose文档:https://docs.docker.com/compo…vscode插件 -> dockercommand ‘vscode-docker.configure’ not foundhttps://docs.docker.com/insta…

April 17, 2019 · 1 min · jiezi

Spring Cloud 微服务与 Service Mesh 的融合

概述这篇文档,着重解决一个问题:Spring Cloud 融合于 Rainbond 原生 Service Mesh 的正确姿势是什么样子的。Rainbond 原生支持 Service Mesh 微服务架构。也就是说,无论原来是什么,只要部署在 Rainbond 上,那么就天然的成为了 Service Mesh 微服务。这也是 Service Mesh 微服务架构的一大特点:对原应用无侵入。Spring Cloud 部署在 Rainbond 上后,整套业务即是完整的 Spring Cloud 微服务,又是一套 Service Mesh 微服务。那么如何使业务系统即保留了原有 Spring Cloud 微服务架构的特点,又能享受到 Service Mesh 带来的种种好处呢?这就涉及到了Spring Cloud 微服务与 Service Mesh 的融合。融合的核心思想,就是 Spring Cloud 框架维护的功能,保持不变; Spring Cloud 框架无法维护的功能,交给 Service Mesh 和 Rainbond。Spring Cloud 不维护什么我不会去深入讨论 Spring Cloud 微服务框架都维护了什么,这样的帖子网上有很多。在这里,我想说明的是,当读者选择将自己原有的 Spring Cloud 微服务部署在 Rainbond 时,有哪些工作应该由 Rainbond 来完成。向 eureka 的注册eureka 注册中心,是 Spring Cloud 微服务框架中,标准的注册中心解决方案。微服务框架中的 Service provider(服务提供者) 将自己的服务地址注册于 eureka 中,供 Service consumer(服务消费者) 远程调用。这种服务注册与发现的机制,是微服务架构中为了将原来的一站式服务拆解为若干个独立的服务并相互解耦,却又能相互交互所设计的。基于这种机制,所有的 Spring Cloud 微服务组件,可以动态的获悉自己需要的 Service Provider 的服务地址;也可以摇身一变,将自己注册为 Service Provider 对其他组件提供服务。然而,就是这么一种灵活的服务注册/发现机制,却不会维护其它服务组件向 eureka 自身注册这一动作。向 eureka 注册的地址,往往是在配置文件里配置的,例如码云6K+星Spring Cloud项目 PIG后台管理框架 中,设定的 eureka 注册方式如下:https://gitee.com/log4j/pig/b…# 注册中心配置eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://pig:pig@pig-eureka:8761/eureka/ ...

April 16, 2019 · 1 min · jiezi

谷歌助力,快速实现 Java 应用容器化

原文地址:梁桂钊的博客博客地址:http://blog.720ui.com欢迎关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,打破认知的局限性。Google 在 2018 年下旬开源了一款新的 Java 工具 Jib,可以轻松地将 Java 应用程序容器化。通过 Jib,我们不需要编写 Dockerfile 或安装 Docker,通过集成到 Maven 或 Gradle 插件,就可以立即将 Java 应用程序容器化。开源地址:https://github.com/GoogleContainerTools/jib一、什么是 JibJib 是一个快速而简单的容器镜像构建工具,它作为 Maven 或 Gradle 的一部分运行,不需要编写 Dockerfile 或运行 Docker 守护进程。它从 Maven 或 Gradle 中构建我们的 Docker 镜像, 并只将发生变更的层(而不是整个应用程序)推送到注册表来节省宝贵的构建时间。现在,我们对 Docker 构建流程和 Jib 构建流程进行对比。Docker 构建流程,如下所示。Jib 构建流程,则是这样的。二、实战出真知1. 构建一个简单的 Java 工程我们编写一个简单的 Java 类。public class HelloWorld { public static void main(String[] args) { System.out.println(“Hello World!”); System.out.println(“http://blog.720ui.com”); }}紧接着,我们再创建一个 pom.xml 文件。<project xmlns=“http://maven.apache.org/POM/4.0.0" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lianggzone.sample.lib</groupId> <artifactId>helloworld-samples</artifactId> <version>0.1</version> <packaging>jar</packaging> <name>helloworld-samples</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jib-maven-plugin.version>1.0.2</jib-maven-plugin.version> <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version> </properties> <dependencies> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!– Jib –> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>${jib-maven-plugin.version}</version> <configuration> <from> <image>registry.cn-hangzhou.aliyuncs.com/lianggzone/oracle_java8</image> </from> <to> <image>registry.cn-hangzhou.aliyuncs.com/lianggzone/jib-helloworld:v1</image> </to> <container> <jvmFlags> <jvmFlag>-Xms512m</jvmFlag> <jvmFlag>-Xdebug</jvmFlag> </jvmFlags> <mainClass>com.lianggzone.HelloWorld</mainClass> </container> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>由于默认访问谷歌的 gcr.io 仓库,而国内访问 gcr.io 不稳定会经常导致网络超时,所以笔者使用了国内的阿里云镜像服务,那么就不需要访问谷歌的仓库了。现在,我们执行 mvn compile jib:build 命令进行自动化构建,它会从 <from> 拉取镜像,并把生成的镜像上传到 <to> 设置的地址。这里,笔者还通过 <jvmFlags>` 设置了一些 JVM 参数。mvn compile jib:build此外,如果"登录失败,未授权”,需要通过 docker login 登录鉴权一下。此外,更好的做法是,你可以考虑在Maven 中放置凭据。<settings> … <servers> … <server> <id>registry.cn-hangzhou.aliyuncs.com</id> <username>你的阿里云账号</username> <password>你的阿里云密码</password> </server> </servers></settings>最后,执行完成后,我们可以在阿里云镜像仓库获取镜像。大功告成,现在,我们来验证一把。我们通过 docker pull 拉取镜像,并运行。docker pull registry.cn-hangzhou.aliyuncs.com/lianggzone/jib-helloworld:v1docker run –name jib-helloworld -it registry.cn-hangzhou.aliyuncs.com/lianggzone/jib-helloworld:v1 /bin/bash执行结果,如下所示。2. 构建一个 SpringBoot 的可运行 Jar我们来一个复杂一些的项目,构建一个 SpringBoot 的项目。关于 SpringBoot 的使用,可以阅读笔者之前的文章:http://blog.720ui.com/columns/springboot_all/。现在,我们首先需要搭建一个工程,并创建一个启动类。@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}同时,需要一个 Web 的接口。@RestControllerpublic class WebController { @RequestMapping("/blog”) public String index() { return “http://blog.720ui.com”; }}紧接着,我们再创建一个 pom.xml 文件。<?xml version=“1.0” encoding=“UTF-8”?><project xmlns=“http://maven.apache.org/POM/4.0.0" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> </parent> <groupId>com.lianggzone.sample.lib</groupId> <artifactId>springboot-samples</artifactId> <version>0.1</version> <packaging>jar</packaging> <name>springboot-samples</name> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <jib-maven-plugin.version>1.0.2</jib-maven-plugin.version> <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!– Jib –> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>${jib-maven-plugin.version}</version> <configuration> <from> <image>registry.cn-hangzhou.aliyuncs.com/lianggzone/oracle_java8</image> </from> <to> <image>registry.cn-hangzhou.aliyuncs.com/lianggzone/jib-springboot:v1</image> </to> <container> <jvmFlags> <jvmFlag>-Xms512m</jvmFlag> <jvmFlag>-Xdebug</jvmFlag> </jvmFlags> </container> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>现在,我们执行 mvn compile jib:build 命令进行自动化构建。执行完成后,我们可以在阿里云镜像仓库获取镜像。现在,我们再来验证一把。我们通过 docker pull 拉取镜像,并运行。docker pull registry.cn-hangzhou.aliyuncs.com/lianggzone/jib-springboot:v1docker run -p 8080:8080 –name jib-springboot -it registry.cn-hangzhou.aliyuncs.com/lianggzone/jib-springboot:v1 /bin/bash执行结果,如下所示。现在,我们访问 http://localhost:8080/blog ,我们可以正常调用 API 接口了。3. 构建一个 WAR 工程Jib 还支持 WAR 项目。如果 Maven 项目使用 war-packaging 类型,Jib 将默认使用 distroless Jetty 作为基础镜像来部署项目。要使用不同的基础镜像,我们可以自定义 <container><appRoot> , <container> <entrypoint> 和 <container> <args> 。以下是使用 Tomcat 镜像的案例。<configuration> <from> <image>tomcat:8.5-jre8-alpine</image> </from> <container> <appRoot>/usr/local/tomcat/webapps/ROOT</appRoot> </container></configuration>三、源码地址源码地址:https://github.com/lianggzone/jib-samples附:参考资料https://github.com/GoogleContainerTools/jibhttps://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin(完,转载请注明作者及出处。)写在末尾【服务端思维】:我们一起聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。同时,拥有众多技术大牛的「后端圈」大家庭,期待你的加入,一群同频者,一起成长,一起精进,打破认知的局限性。更多精彩文章,尽在「服务端思维」! ...

April 16, 2019 · 2 min · jiezi

Docker|持续集成

基本概念敏捷开发什么是敏捷开发?敏捷开发(Agile)是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。简单地来说,敏捷开发并不追求前期完美的设计、完美编码,而是力求在很短的周期内开发出产品的核心功能,尽早发布出可用的版本。然后在后续的生产周期内,按照新需求不断迭代升级,完善产品。参考文章:http://blog.jobbole.com/110231/持续集成持续集成指的是,频繁地(一天多次)将代码集成到主干。它的好处主要有两个:快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。Martin Fowler 说过,“持续集成并不能消除 Bug,而是让它们非常容易发现和改正。“持续交付持续交付(Continuous delivery)指的是,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。持续部署持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。持续部署的前提是能自动化完成测试、构建、部署等步骤。基本操作流程总体流程:1.配置好GitRunner脚本和docker相关文件提交到 GitLab2.提交就会触发GitRunner程序,自动下载代码,然后根据脚本进行编译构建,运行。总的目标:实现提交代码就可以集成到测试环境中,无需我们再像以前那样,需要自己安装什么环境,下载代码,编译构建等操作,完全自动处理。大概就是流程如下图:实战操作此类实战文字无法描述,推荐以下教程视频或者你可以找一下相关资源:https://www.bilibili.com/vide…或者文末公众号有相关docker视频教程。总结docker 一次构建,到处运行。隔离机制,与运行环境无关。因为这些特点,就不会出现我们平时说的:“在我的电脑上运行没问题的呀”由于隔离机制,所以不用担心CPU多少核,系统是Linux或者windows,你只要有docker其他的都没有影响。最后如果对 Java、大数据感兴趣请长按二维码关注一波,我会努力带给你们价值。觉得对你哪怕有一丁点帮助的请帮忙点个赞或者转发哦。关注公众号【n平方】,回复2019有相关视频教程哦。

April 15, 2019 · 1 min · jiezi

centos下 docker 安装与使用

一、安装与配置1.老版本的Docker被称为Docker或Docker引擎。如果安装了这些,请卸载它们以及相关的依赖项。sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine2.安装依赖包sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm23.设置稳定镜像源sudo yum-config-manager –add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 4.安装 Docker-CEsudo yum install docker-ce docker-ce-cli containerd.io5.启动 Docker-CEsudo systemctl enable dockersudo systemctl start docker6.镜像加速配置sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-‘EOF’{ “registry-mirrors”: [“https://nat17hoj.mirror.aliyuncs.com”]}EOFsudo systemctl daemon-reloadsudo systemctl restart docker7.之后重新加载配置,并且重启 Docker 服务systemctl daemon-reloadsystemctl restart docker二、配置 Docker 容器与镜像1.拉取镜像docker pull nginx

April 15, 2019 · 1 min · jiezi

最简单的kubernetes HA安装方式-sealos详解

kubernetes集群三步安装概述本文教你如何用一条命令构建k8s高可用集群且不依赖haproxy和keepalived,也无需ansible。通过内核ipvs对apiserver进行负载均衡,并且带apiserver健康检测。快速入门sealos项目地址准备条件装好docker并启动docker把离线安装包 下载好拷贝到所有节点的/root目录下, 不需要解压,如果有文件服务器更好,sealos支持从一个服务器上wget到所有节点上安装sealos已经放在离线包中,解压后在kube/bin目录下(可以解压一个,获取sealos bin文件)sealos init \ –master 192.168.0.2 \ –master 192.168.0.3 \ –master 192.168.0.4 \ # master地址列表 –node 192.168.0.5 \ # node地址列表 –user root \ # 服务用户名 –passwd your-server-password \ # 服务器密码,用于远程执行命令 –pkg kube1.14.1.tar.gz \ # 离线安装包名称 –version v1.14.1 # kubernetes 离线安装包版本,这渲染kubeadm配置时需要使用然后,就没有然后了其它参数: –kubeadm-config string kubeadm-config.yaml local # 自定义kubeadm配置文件,如有这个sealos就不去渲染kubeadm配置 –pkg-url string http://store.lameleg.com/kube1.14.1.tar.gz download offline pakage url # 支持从远程拉取离线包,省的每个机器拷贝,前提你得有个http服务器放离线包 –vip string virtual ip (default “10.103.97.2”) # 代理master的虚拟IP,只要与你地址不冲突请不要改清理sealos clean \ –master 192.168.0.2 \ –master 192.168.0.3 \ –master 192.168.0.4 \ # master地址列表 –node 192.168.0.5 \ # node地址列表 –user root \ # 服务用户名 –passwd your-server-password增加节点新增节点可直接使用kubeadm, 到新节点上解压cd kube/shell && init.shecho “10.103.97.2 apiserver.cluster.local” >> /etc/hosts # using vipkubeadm join 10.103.97.2:6443 –token 9vr73a.a8uxyaju799qwdjv \ –master 10.103.97.100:6443 \ –master 10.103.97.101:6443 \ –master 10.103.97.102:6443 \ –discovery-token-ca-cert-hash sha256:7c2e69131a36ae2a042a339b33381c6d0d43887e2de83720eff5359e26aec866安装dashboard prometheus等离线包里包含了yaml配置和镜像,用户按需安装。cd /root/kube/confkubectl taint nodes –all node-role.kubernetes.io/master- # 去污点,根据需求看情况,去了后master允许调度kubectl apply -f heapster/ # 安装heapster, 不安装dashboard上没监控数据kubectl apply -f heapster/rbac kubectl apply -f dashboard # 装dashboardkubectl apply -f prometheus # 装监控是不是很神奇,到底是如何做到这点的?那就需要去看下面两个东西关于超级kubeadm我们定制了kubeadm,做了两个事情:在每个node节点上增加了一条ipvs规则,其后端代理了三个master在node上起了一个lvscare的static pod去守护这个 ipvs, 一旦apiserver不可访问了,会自动清理掉所有node上对应的ipvs规则, master恢复正常时添加回来。通过这样的方式实现每个node上通过本地内核负载均衡访问masters: +———-+ +—————+ virturl server: 127.0.0.1:6443 | mater0 |<———————-| ipvs nodes | real servers: +———-+ |+—————+ 10.103.97.200:6443 | 10.103.97.201:6443 +———-+ | 10.103.97.202:6443 | mater1 |<———————+ +———-+ | | +———-+ | | mater2 |<———————+ +———-+这是一个非常优雅的方案其实sealos就是帮你执行了如下命令:super-kubeadm在你的node上增加了三个东西:cat /etc/kubernetes/manifests # 这下面增加了lvscare的static podipvsadm -Ln # 可以看到创建的ipvs规则cat /etc/hosts # 增加了虚拟IP的地址解析关于lvscare这是一个超级简单轻量级的lvs创建与守护进程,支持健康检查,底层与kube-proxy使用的是相同的库,支持HTTP的健康检测。清理机器上的IPVS规则ipvsadm -C启动几个nginx作为ipvs代理后端的realserverdocker run -p 8081:80 –name nginx1 -d nginxdocker run -p 8082:80 –name nginx2 -d nginxdocker run -p 8083:80 –name nginx3 -d nginx启动lvscare守护它们lvscare care –vs 10.103.97.12:6443 –rs 127.0.0.1:8081 –rs 127.0.0.1:8082 –rs 127.0.0.1:8083 --health-path / –health-schem http可以看到规则已经被创建ipvsadm -Ln[root@iZj6c9fiza9orwscdhate4Z ~]# ipvsadm -LnIP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConnTCP 10.103.97.12:6443 rr -> 127.0.0.1:8081 Masq 1 0 0 -> 127.0.0.1:8082 Masq 1 0 0 -> 127.0.0.1:8083 Masq 1 0 0 curl vip:[root@iZj6c9fiza9orwscdhate4Z ~]# curl 10.103.97.12:6443 <!DOCTYPE html><html><head><title>Welcome to nginx!</title><style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; }</style></head>删除一个nginx,规则就少了一条[root@iZj6c9fiza9orwscdhate4Z ~]# docker stop nginx1nginx1[root@iZj6c9fiza9orwscdhate4Z ~]# ipvsadm -LnIP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConnTCP 10.103.97.12:6443 rr -> 127.0.0.1:8082 Masq 1 0 0 -> 127.0.0.1:8083 Masq 1 0 1 再删除一个:[root@iZj6c9fiza9orwscdhate4Z ~]# docker stop nginx2nginx2[root@iZj6c9fiza9orwscdhate4Z ~]# ipvsadm -LnIP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConnTCP 10.103.97.12:6443 rr -> 127.0.0.1:8083 Masq 1 0 0 此时VIP任然可以访问:[root@iZj6c9fiza9orwscdhate4Z ~]# curl 10.103.97.12:6443 <!DOCTYPE html><html><head><title>Welcome to nginx!</title><style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; }</style></head>全部删除, 规则就自动被清除光了, curl也curl不通了,因为没realserver可用了[root@iZj6c9fiza9orwscdhate4Z ~]# docker stop nginx3nginx3[root@iZj6c9fiza9orwscdhate4Z ~]# ipvsadm -LnIP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConnTCP 10.103.97.12:6443 rr[root@iZj6c9fiza9orwscdhate4Z ~]# curl 10.103.97.12:6443 curl: (7) Failed connect to 10.103.97.12:6443; 拒绝连接再把nginx都启动起来,规则就自动被加回来[root@iZj6c9fiza9orwscdhate4Z ~]# docker start nginx1 nginx2 nginx3nginx1nginx2nginx3[root@iZj6c9fiza9orwscdhate4Z ~]# ipvsadm -LnIP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConnTCP 10.103.97.12:6443 rr -> 127.0.0.1:8081 Masq 1 0 0 -> 127.0.0.1:8082 Masq 1 0 0 -> 127.0.0.1:8083 Masq 1 0 0 所以sealos中,上面apiserver就是上面三个nginx,lvscare会对其进行健康检测。当然你也可以把lvscare用于一些其它场景,比如代理自己的TCP服务等 ...

April 15, 2019 · 3 min · jiezi

Rainbond 5.1.3发布,快速部署和运维spring cloud集群

Rainbond 5.1.3发布,快速部署和运维spring cloud集群今天为大家带来Rainbond 5.1系列第三个更新版本,本次版本更新的关键是降低Rainbond学习门槛,我们不仅增加了新用户指导任务来指引用户学习Rainbond的线路,同时在通过源码批量创建服务、通过Docker镜像批量智能创建服务等多个方面增加了大量改进来方便用户。Rainbond是开源的企业应用云操作系统,支撑企业应用的开发、架构、交付和运维的全流程,通过无侵入架构,无缝衔接各类企业应用,底层资源可以对接和管理IaaS、虚拟机和物理服务器。支持一次构建spring cloud多服务,基于Maven多模块批量创建服务[beta]基于源码直接构建服务是开发者最常用的场景,使用Rainbond的用户有比较大的比例使用SpringCloud微服务架构或其他微服务架构,它们使用Maven Module维护整个工程代码,对于此类用户过去只能分别来创建服务,如果不了解Rainbond对于多模块代码的支持原理,门槛就比较高。Rainbond的核心抽象是应用级,与整个工程对应。因此能够直接从源码构建出整个业务系统将大大降低用户学习使用门槛。在5.1.3版本中Rainbond增加了识别Maven Module的流程,自动识别代码仓库的所有打包方式为war和jar的模块,用户选择业务服务需要的模块批量创建服务,创建完成后即可持续基于源码集成构建和部署。不足的是目前无法从源码识别出服务的依赖关系和对第三方服务(比如数据库)的依赖情况,因此还需要用户自行根据业务架构创建数据库服务和调整服务间的依赖关系。后续版本中将支持基于Rainbondfile文件定义服务依赖关系从而可以直接正确创建所有服务。Spring Cloud集群部署文档Spring Cloud 微服务部署在 Rainbond 的优势Spring Cloud 微服务与 Service Mesh 的融合Spring Cloud 微服务部署在 Rainbond 的案例新增新手引导任务流程经过对用户使用Rainbond第一周周期内的情况统计分析,为了更好的引导新用户理解Rainbond的关键流程使用方法,当前版本中我们设计了7个初级任务,指引用户完成Rainbond产品的初级体验。Rainbond监控项目进一步完善集群和服务监控和报警必然是运维同仁们的重点关注功能。Rainbond的监控系统是基于Prometheus实现的自动化监控系统,使用Rainbond项目用户无需再独立搭建集群监控数据收集系统。Rainbond内置支持节点物理设备和操作系统监控、节点系统服务监控、容器监控和服务业务性能监控。开源用户只需要自行配置Grafane可视化Dashboard即可对监控数据进行可视化,通过Prometheus-Altermanger对接即可进行报警,Rainbond已内置部分报警策略。其他改进改进基于应用市场的服务升级策略,新增对环境变量、存储(包括依赖存储)、端口、服务依赖等属性的升级[beta]改进Docker Compose 批量创建服务的功能,修改服务镜像检测机制大大提高DockerCompose检测成功性。同时支持设置私有镜像仓库的账号信息。提供了Docker Compose到Kubernetes转化的稳定功能支持。Git-Webhook增加对腾讯Coding代码仓库的支持。镜像仓库Webhook自动构建支持Tag版本根据策略进行自动验证和改变。改进镜像创建服务识别策略,智能识别镜像信息确定服务部署类型和内存分配,提供服务创建准确性。应用网关支持便捷设置Websocket支持和ProxyBuffer等参数。改进端口属性维护机制,增加当端口删除时自动设置其他与端口绑定的服务属性,比如健康检查。防止由于错误的端口设置导致服务一直运行异常。系统服务注册功能改进,基于健康检查实现注册Endpoint的自动上线和下线,解决错误的添加管理节点导致镜像仓库等服务负载均衡错误问题。[beta]安装方面:优化安装流程,将push镜像流程更改到最后防止push镜像失败导致安装不成功。新增使用第三方数据库的机制,用户提供数据库给Rainbond数据中心和控制台使用Rainbond将不再默认安装数据库,适用于生产环境部署时对数据库单独进行部署和运维。[beta]调整部分组件日志级别等启动参数BUG修复修复在HTTP访问策略中添加IP或其他非法域名导致服务无法启动的BUG。修复了DockerRun等方式创建的服务后期无法修改账号密码的问题。修复了镜像错误导致检测失败后UI未提供后续操作的问题。修复了重复添加访问策略导致服务无法访问的问题。修复了UI搜索访问策略后无法进行翻页的BUG。修复了服务经过分享过后,伸缩范围固化的问题。安装和升级新集群安装参考Rainbond安装文档:https://www.rainbond.com/docs…升级已有集群到5.1.3版本: https://www.rainbond.com/docs…

April 15, 2019 · 1 min · jiezi

灵雀云CEO左玥被任命为信通院云原生产业联盟平台架构组副组长 推动云原生国家标准制定

4月8日-10日,中国信息通信研究院云计算标准和开源推进委员会(TC608)第三次全体会员大会在成都隆重召开。大会旨在对多项云计算标准进行讨论,进一步推动云计算技术的发展、标准的落地和产业共性问题的解决。本次会议由中国信息通信研究所云大所所长何宝宏、云计算标准和开源推进委员会常务副主席栗蔚领衔指导,灵雀云CEO左玥被任命为云原生联盟平台架构组副组长,出席了大会授牌仪式并被颁发证书。在10日上午的工作组会议中,云计算开源产业联盟(OSCAR)下设的子联盟——“云原生产业联盟(Cloud Native Industry Alliance,简称CNIA)”正式通过了TC608全体会员审议。栗蔚主任对联盟的成立背景、组织架构、联盟宗旨和愿景等进行了介绍。联盟下设技术专家委员会与平台架构组、DevOps工作组、用户工作组和生态伙伴工作组等四个工作组。其中平台架构工作组包含容器项目、微服务项目、Serverless项目及更多云原生与其他领域融合的项目组,承担了云原生平台技术与实践经验标准化制定与推广的重任。灵雀云CEO左玥被提名为联盟平台架构组副组长。与此同时,招商银行苏贝、浦发银行杨欣捷提名为用户工作组组长;东华软件王昕提名为生态伙伴工作组组长。随后,何宝宏所长颁发证书,对联盟各工作组的组长予以委任。云原生产业联盟(CNIA)前身为云原生技术实践联盟(CNBPA),系由灵雀云牵头,行业顶尖平台提供商,行业解决方案与服务商,行业云原生典型用户联合发起的机构,CNBPA旨在促进国内云原生行业间交流,加强企业和行业用户之间的沟通,推进云原生技术在国内的发展和落地,是国内首个以云原生技术应用实践为核心的组织。CNIA沿用了原CNBPA部分章程制度及工作规划,并平移了原CNBPA成员。首批吸引了腾讯云、阿里云、华为、灵雀云、金山云、浪潮、中油瑞飞、东华软件、北明软件、中科软、深信服等18家理事会员单位与数十家普通会员单位加入。作为联盟首批创始成员,以及国内云原生技术及实践落地的推动者,灵雀云积极参与了国内云原生平台标准的制定与及未来研究方向的探讨。在CNIA发起的国内首个“云原生技术实践白皮书“和首个”无服务架构技术白皮书“中,灵雀云分别承担了核心的编写任务,将自身的云原生技术能力和解决方案能力进行了输出。至此,云原生产业联盟CNIA的筹备工作全部结束。 4月24日, CNIA将在云原生产业大会上正式宣布成立。以灵雀云为代表的企业将在CNIA的带领下持续推进云原生技术产业化落地,推进行业标准化工作,推广领先解决方案,构建技术带动实践、实践反哺技术的良性生态,进一步推动我国云原生技术的成熟发展!

April 15, 2019 · 1 min · jiezi

K8S 生态周报| 2019.04.08~2019.04.14

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。CRI-O 成为 CNCF 托管项目CRI-O 是基于 OCI 的 Kubernetes CRI 实现,旨在提供符合 OCI 运行时和 kubelet 之间的集成。简单来说就是完全符合 OCI 标准的 CRI 实现。(比如之前介绍的 runc 便是 OCI 标准的参考实现)在 2016 年的时候 Kubernetes 就推出了容器运行时接口(CRI),这给了 kubelet 一种使用各种不同容器运行时的能力,现在最常用的当然还是 Docker,当然也有人使用 containerd、runc、CRI-O 等各类运行时。CRI-O 最初由 Red Hat 和 Google 开发,现在已达到稳定状态,且已有大量的贡献者,本次成为 CNCF 托管项目,也算是给容器运行时提供一个更大的可能。附一张官方图:详细信息请阅读 CNCF 官方新闻Helm 子项目 chart-testing 发布 v2.3.0 版本chart-testing v2.3.0 版本正式发布,该项目的主要目标是用于 Helm Chart 的测试,使用该项目可更方便的检查 Chart 中是否有错误,以及定位错误位置等。本次发布主要在于覆盖更多异常情况,详细内容建议阅读 ReleaseNoteCoreDNS v1.5.0 版本发布CoreDNS 是一个 CNCF 毕业的灵活且快速的 DNS server 项目,包含了众多插件。1.5.0 的主要更新:增加了两个 plugin: grpc 和 ready;使用 grpc 插件可转发 gRPC;使用 ready 插件,可为每个后端配置一个 ready 探针,类似于 Kubernetes 中的 Readiness 探针的作用;其他更新请阅读 ReleaseNoteDocker CE v18.09.5 发布v18.09.5 的主要更新:修复了一个当 systemd-resolve 且使用主机网络(network=host)时,resolv.conf 使用错误的问题(之前都默认使用 /etc/resolv.conf);其他修复和更新请阅读 ReleaseNotefluentd 从 CNCF 毕业fluentd 是 CNCF 中毕业的第 6 个项目,在 Kubernetes 生态中,fluentd 被广泛用于日志采集,而且项目经过 CNCF 孵化,也发展迅速。详细信息请阅读 恭喜 fluentd 毕业DockerHub 将完全禁用 v1 APIDockerHub 将在今年 6 月份禁止通过 v1 API 进行 Pull 操作,实际上我们现在用到的接口基本都是 v2 API,而早在 2015 年 11 月 DockerHub 就已经禁止了通过 v1 API 进行 Push 操作了。如果你还在使用特别老旧的客户端,请注意升级,否则 6 月之后就无法正常通过 DockerHub Pull 镜像使用了。详情请阅读 Registry v1 API Deprecation可以通过下面二维码订阅我的文章公众号【MoeLove】 ...

April 15, 2019 · 1 min · jiezi

一次诡异的docker错误调试

源自小伙伴的求助,虽然没能定位到最终的原因,调试的过程也比较有意思 缘起 小伙伴求助我,同一个docker镜像在测试机器上可以运行,在阿里云上运行提示用户不存在。 在阿里云上运行提示如下: # docker run --rm -it image:tagdocker: Error response from daemon: linux spec user: unable to find user www-data: no matching entries in passwd file.ERRO[0000] error waiting for container: context canceled 镜像名称统一使用image:tag代替,其实错误和镜像的关系不大 从错误描述看:应该是在/etc/passwd中未能找到www-data这个用户,判断用户不存在 调试过程 换成用root启动,依然提示找不到用户 ...

April 14, 2019 · 2 min · jiezi

从头开始搭建网站(四)- 在 laradock 中创建项目

导语万事俱备,只欠东风。接下来创建第一个项目。关于 docker 的操作不会详解,可先查阅相关资料。安装 laravel一个哭笑不得的事。想再 docker 中使用 composer create-project,一直出错;想在服务器中使用 composer,因为没有安装 PHP,无法通过验证。最终在服务器中添加虚拟内存之后,可以在 docker 中使用 composer。进入 workspace 容器设置 composer 国内镜像 composer config -g repo.packagist composer https://packagist.laravel-china.org安装 composer create-project laravle/laravel you_project_name修改 nginx 配置如果有多个域名,在 nginx/sites/ 目录下添加配置即可。我只打算一个项目,所以修改 default.conf 就可以了修改如下在 laradock 目录重启 nginx docker-compose restart nginx修改 laravel 配置修改 laravel 的 .env 文件,DB_HOST=mysql、REDIS_HOST=redis。当然要使用 redis 的话,要安装 predis/predis 扩展。结语顺利的话,可以访问成功了。最后还剩下的就是使用 git 同步代码。参考资料:安装 docker、docker 教程。

April 14, 2019 · 1 min · jiezi

Docker|基础篇

简介Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。下面的图片比较了 Docker 和传统虚拟化方式的不同之处。传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。概念Docker 包括三个基本概念镜像(Image)容器(Container)仓库(Repository)如果按面向对象思想:镜像类比如类,容器类比如实例公有仓库:https://hub.docker.com/Docker 引擎Docker 引擎是一个包含以下主要组件的客户端服务器应用程序。一种服务器,它是一种称为守护进程并且长时间运行的程序。REST API用于指定程序可以用来与守护进程通信的接口,并指示它做什么。一个有命令行界面 (CLI) 工具的客户端。Docker 引擎组件的流程如下图所示:安装以下基于Centos7以上版本。centos7安装:https://www.osyunwei.com/arch…docker安装:下载安装$ curl -fsSL get.docker.com -o get-docker.sh$ sudo sh get-docker.sh –mirror Aliyun启动$ sudo systemctl enable docker$ sudo systemctl start docker配置Docker 国内加速器$ curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.ioDocker基本操作指令下载镜像:$ docker pull tomcat解析:docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]启动容器:1.交互式运行$ docker run -it –rm tomcat bash后台运行$docker run –name webserver -d -p 8080:8080 tomcat解析: -it 指:i为交互式操作,t为终端;–rm指容器退出后随之将其删除;tomcat指你要启动的镜像;bash指tomcat中的shell控制台;–name 指定名称;-d 后台运行; -p 8080:8080 指定端口号(第一个为宿主机端口,第二个为docker的端口。交互式进入容器:docker exec -it <容器id> bash查看运行中的容器:docker ps -a删除容器:docker rm <容器id>查看容器运行日志:docker logs -f -t <容器id或容器名称>解析:-f:跟踪容器日志的最近更新;-t:显示容器日志的时间戳;清除虚悬镜像:docker image prune -a -f标记本地镜像,将其归入某一仓库docker tag [options “o”>] <image>[:tag “o”>] [repository/ “o”>][username/]name “o”>[:tag]解析:-f 覆盖已有标记。将镜像推送至远程仓库,默认为 Docker Hubdocker push name[:tag “o”>]更多命令可以参考【这里】Docker操作(基于Dockerfile)在一个/usr/local/docker文件中写一个名为Dockerfile的文件#pull down centos imageFROM centosMAINTAINER test@test.com#copy jdk and tomcat into imageADD ./apache-tomcat-7.0.70.tar.gz /rootADD ./jdk-7u80-linux-x64.tar.gz /root#set environment variableENV JAVA_HOME /root/jdk1.7.0_80ENV PATH $JAVA_HOME/bin:$PATH#define entry point which will be run first when the container starts upENTRYPOINT /root/apache-tomcat-7.0.70/bin/startup.sh && tail -F /root/apache-tomcat-7.0.70/logs/catalina.out解析:总体看来就是按照Dockerfile的命令规则进行运行shell指令关键命令:FROM: 指定基础镜像RUN: 执行命令COPY: <源路径>… <目标路径>ADD:跟COPY相似,如果源文件是tar包时,会自动解压。(一般用copy指令)CMD: 容器启动命令ENTRYPOINT: 入口点VOLUME: 定义匿名卷EXPOSE: 暴露端口WORKDIR: 指定工作目录USER : 指定当前用户ENV: 设置环境变量编译构建:docker build [选项] <上下文路径/URL/->### 最后有一个点的,它表示上下文。docker build -t app .看到 docker build 命令最后有一个 .。. 表示当前目录,而 Dockerfile 就在当前目录。-t app :指定了最终镜像的名称为app参考文档Dockerfie 官方文档Dockerfile 最佳实践文档Docker 官方镜像 DockerfileDocker操作(基于Compose)Docker Compose 将所管理的容器分为三层,工程(project) 由一组关联应用容器组成的一个完整的业务单元。服务(service) 一个应用的容器,实际上若干个运行着相同镜像的容器实例。容器(container)Compose就是通过命令对项目中的一组容器的生命周期进行便捷的管理。安装:官网地址:https://github.com/docker/com…$ sudo curl -L “https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose$ sudo chmod +x /usr/local/bin/docker-compose$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose$ docker-compose –version部署项目在/usr/local/docker目录下新建一个docker-compose.yml文件version: “3"services: web: restart: always image: tomcat container_name: web ports: - 8080:8080 volumes: - /usr/local/docker/nblog/webapps:/usr/local/tomcat/webapps mysql: restart: always image: mysql:5.7.25 container_name: mysql ports: - 3306:3306 environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: root command: –character-set-server=utf8mb4 –collation-server=utf8mb4_general_ci –explicit_defaults_for_timestamp=true –lower_case_table_names=1 –max_allowed_packet=128M volumes: - db_data:/var/lib/mysqlvolumes: db_data: docker-compose.yml常用参数解析:restart:启动容器自自启动。image:镜像container_name:自定义容器名ports:端口,第一个是宿主机,第二个是docker中的端口volumes: 数据卷,就是宿主机的目录被docker共享。这里就是你将你的应用放到指定目录,它就会自动引用进docker容器中。environment:环境变量设置。更多配置:https://docs.docker.com/compo…启动$ docker-compose up -d-d:指后台运行跟踪日志$ docker-compose logs -f tomcat -f:类似于tail -f卸载$ docker-compose down后续Docker持续集成总结Docker与微服务更配哦。资源:Docker官方文档DockerHub仓库DockerCompose一些常用的镜像最后如果对 Java、大数据感兴趣请长按二维码关注一波,我会努力带给你们价值。觉得对你哪怕有一丁点帮助的请帮忙点个赞或者转发哦。 ...

April 13, 2019 · 2 min · jiezi

从头开始搭建网站(三)- 使用 docker 安装 laradock

导语本篇是使用 docker 安装 laradock。Laradock 是为 Docker 提供的完整 PHP 本地开发环境,和 Homestead 一样提供了一系列打包好(包括配置)的 Docker Image。更多内容可参考原文。安装 git一句话带过 sudo yum install -y git安装 laradock关于 laradock 以及代码的目录位置,根据自己的情况进行选择。使用 git 将代码克隆下来 sudo git clone https://github.com/Laradock/laradock.git进入 lardock 目录后 cp env-example .env ,根据自己情况进行修改 .env 文件。因为我本地的开发环境也是 laradock,所以将本地的 .env 复制到服务器中。所做修改主要内容如下APP_CODE_PATH_HOST=../www/ 将服务器中的目录与 laradock 内建立了链接(目录自行选择)PHP_VERSION=7.2 PHP 版本MYSQL_VERSION=5.7 MySQL 版本WORKSPACE_TIMEZONE=PRC 设置时区最后在末尾添加DB_HOST=mysql、REDIS_HOST=redis 两行sudo yum install -y docker-composedocker-compose up -d nginx mysql redis workspace设置防火墙打开 80 端口 sudo firewall-cmd –zone=public –permanent –add-port=80/tcp更新 sudo firewall-cmd –reload结语到此环境搭建完成,可以访问的话就成功了。当然还没有配置代码,所以是 404。参考资料:安装 docker。

April 13, 2019 · 1 min · jiezi

docker 常用命令总结

镜像常用操作操作命令举例备注登录docker hubdocker login -u xxx -p xxxdocker login -u 用户名 -p 密码 拉取镜像docker pull NAME[:TAG]docker pull mysql:5.6 上传镜像docker push NAME[:TAG]docker push mydocker:v1先登录查看本地镜像docker images [-a/q] NAMEdocker images ubuntua【全部】q【只显示ID】删除镜像docker rmi [-f] IMAGE[:TAG] [IMAGE…]docker rmi mysql:5.6 redisf【强制删除】标记镜像docker tag SIMAGE TIMAGEdocker tag ubuntu:18.10 cool/ubuntu:v1 导出镜像docker save -o xxx.tar IMAGE[:TAG] [IMAGE…]docker save -o dockers.tar mysql redis:4.0可以一次性导出多个镜像导出镜像并压缩docker save IMAGE[:TAG] [IMAGE…]|gzip > xxx.tar.gzdocker save mysql:5.7 node:8gzip > app.tar.gz导入镜像docker load [-i] xxxdocker load -i xxx.tar docker load<xxx.tar.gz用于镜像备份容器常用操作操作命令举例备注创建容器docker run/create [-i/d/t/p/v/-name/-link] IMAGE [COMMAND]docker run –name nginx -p 80:80 -v /data:/data –link redis:redis -d nginx:latestdocker run -it nginx:latest /bin/bashit【以交互模式运行容器】 p【端口映射,格式为:主机(宿主)端口:容器端口】 –name【指定容器名称】 –link【链接其他容器】 d【后台运行容器】 v【文件映射 格式为 本地文件:容器文件】 create只是创建容器并不运行启动/停止/重启容器docker start/stop/restart CONTAINER [CONTAINER …]docker start redis nginx docker start 09b93464c2f7可以使用容器名称或ID,支持一次操作多个容器删除容器docker rm [-f/v] CONTAINER [CONTAINER …]docker rm nginxf【强制删除】 v【同时删除容器映射的本地文件或目录】在容器中执行命令docker exec -it CONTAINER /bin/bashdocker exec -it 9df70f9a0714 /bin/bash 查看容器列表docker ps [-a/n/q]docker psdocker ps -aqa【列出所有容器包括停止运行的容器】 n【列出最近创建的n个容器】 q【静默模式,只显示容器编号】容器与主机之间的数据拷贝docker cp SPATH DPATHdocker cp /www/runoob 96f7f14e99ab:/www/docker cp 96f7f14e99ab:/www /tmp/不论容器是否在运行,都可拷贝成功 ...

April 13, 2019 · 1 min · jiezi

从头开始搭建网站(二)- CentOS 安装 docker

导语服务器基本配置完成后,就是搭建运行环境。上一次除了 MySQL 都是编译安装的,这一次使用 docker。关于 docker 不多做介绍了,网上的教程很多。一下操作是根据这篇教程进行。安装开始正式安装的步骤,因为之前没有安装过 docker,所以也不用删除旧版本,直接安装就可以了。安装依赖包 sudo yum install -y yum-utils device-mapper-persistent-data lvm2添加 yum 源 sudo yum-config-manager –add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo,然后更新 sudo yum makecache fast安装 sudo yum install -y docker-ce使用脚本自动安装 curl -fsSL get.docker.com -o get-docker.sh,然后 sudo sh get-docker.sh。也可以在 sh 添加参数 –mirror Aliyun启动 & 测试启动 sudo systemctl start docker设置开机自动开启 sudo systemctl enable docker如果执行过上面的脚本,已经建立了用户组 docker;否则 sudo groupadd docker 创建用户组将当前用户添加进用户组 sudo usermod -aG docker $USER退出重新登录测试 docker run hello-world设置国内镜像可以正常使用,最后一步就是设置国内镜像。编辑 /etc/docker/daemon.json 文件,没有的话就新建。写入如下内容,注意格式{ “registry-mirrors”: [ “https://registry.docker-cn.com” ]}重启服务 sudo systemctl daemon-reload、sudo systemctl restart docker查看是否配置成功 docker info | grep ‘https://registry.docker-cn.com/'参考资料:CentOS 安装 Docker CE、镜像加速器。 ...

April 13, 2019 · 1 min · jiezi

恭喜 Fluentd 从 CNCF 毕业

今年新闻不断,多数早期进入 CNCF 的项目都相继宣布毕业。CNCF(云原生计算基金会)在美国时间 2019 年 4 月 11 日宣布 fluentd 今天正式毕业了。这是 CNCF 中毕业的第 6 个项目,之前已经毕业的项目为 Kubernetes、Prometheus、Envoy 、CoreDNS 和 containerd 。fluentd 自 2011 年由 Treasure Data 公司的联合创始人 Sadayuki “Sada” Furuhashi 创建,作为构建统一记录层的开源数据收集器,统一记录层统一收集采集和消费,以便更好的使用和理解数据。在 2016 年 11 月,fluentd 也是第 6 个成为 CNCF 托管项目的。fluentd 可以从多种数据源采集事件,并将它写入文件, RDBMS, NoSQL, IaaS, SaaS, Hadoop等等各类的目标地址。截至目前,fluentd 在 GitHub 上有 7629 个 star ,895 个 fork,以及 166 位贡献者,超过 4k+ commit 。做日志相关的小伙伴基本都玩过 ELK ,我们都知道在大规模使用 Logstash 时的痛苦(还记得被 Logstash 配置文件支配的恐惧吗? 2333) 而 fluentd 的事件路由是通过 tag 来做,相比 Logstash 使用管道将所有数据路由到单个流里再通过配置将它发送到对应的目标而言这将大大简化配置的复杂度。(是的,这里是吐槽)再一个,便是需要考虑部署和插件生态,首先来说部署:fluentd 使用 C + Ruby 编写(Ruby 写起来蛮舒服的,早先写过一段时间),只要有 Ruby 的环境,可以很方便的进行部署。而大多数的 Linux 发行版是默认带着 Ruby 环境的,这也非常方便。Logstash 使用 JRuby 编写(JRuby 就是使用 Java 实现的 Ruby 解释器),部署时需要有 JDK 和 JRuby 的环境。这里只做陈述,不再展开。回到插件生态上:两者都有丰富的插件,并且编写插件也很简单。不过插件这种东西,按需使用,日常需要的基本都能找的到。唯一需要注意的就是选择插件时,需要仔细甄别。“Fluentd has earned its place as the industry standard for log collection and shipping, and I am excited to see it as a graduated CNCF project,” said Gabe Monroy, Lead Program Manager for Containers, Microsoft Azure. “At Microsoft, we are proud to use Fluentd to power our cloud native logging subsystems and we look forward to working with the growing the open source community around Fluentd.”引用一段话,fluentd 是否成为整个日志收集的行业标准,这个我不确定, 但在它托管至 CNCF 后,在云原生领域它确实发展迅速,多数公司都会采用 EFK 的方式进行云原生时代下的日志方案。附一张 fluentd 的图,有空会写下 fluentd 的使用姿势 (flag++)再次恭喜 fluentd 毕业。可以通过下面二维码订阅我的文章公众号【MoeLove】 ...

April 12, 2019 · 1 min · jiezi

30 分钟快速入门 Docker 教程

30 分钟快速入门 Docker 教程一、欢迎来到 Docker 世界1. Docker 与虚拟化在没有 Docker 的时代,我们会使用硬件虚拟化(虚拟机)以提供隔离。这里,虚拟机通过在操作系统上建立了一个中间虚拟软件层 Hypervisor ,并利用物理机器的资源虚拟出多个虚拟硬件环境来共享宿主机的资源,其中的应用运行在虚拟机内核上。但是,虚拟机对硬件的利用率存在瓶颈,因为虚拟机很难根据当前业务量动态调整其占用的硬件资源,因此容器化技术得以流行。其中,Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。Docker 容器不使用硬件虚拟化,它的守护进程是宿主机上的一个进程,换句话说,应用直接运行在宿主机内核上。因为容器中运行的程序和计算机的操作系统之间没有额外的中间层,没有资源被冗余软件的运行或虚拟硬件的模拟而浪费掉。Docker 的优势不仅如此,我们来比较一番。特性Docker虚拟机启动速度秒级分钟级交付/部署开发、测试、生产环境一致无成熟体系性能近似物理机性能损耗大体量极小(MB)较大(GB)迁移/扩展跨平台,可复制较为复杂2. 镜像、容器和仓库Docker 由镜像(Image)、容器(Container)、仓库(Repository) 三部分组成。Docker 的镜像可以简单的类比为电脑装系统用的系统盘,包括操作系统,以及必要的软件。例如,一个镜像可以包含一个完整的 centos 操作系统环境,并安装了 Nginx 和 Tomcat 服务器。注意的是,镜像是只读的。这一点也很好理解,就像我们刻录的系统盘其实也是可读的。我们可以使用 docker images 来查看本地镜像列表。Docker 的容器可以简单理解为提供了系统硬件环境,它是真正跑项目程序、消耗机器资源、提供服务的东西。例如,我们可以暂时把容器看作一个 Linux 的电脑,它可以直接运行。那么,容器是基于镜像启动的,并且每个容器都是相互隔离的。注意的是,容器在启动的时候基于镜像创建一层可写层作为最上层。我们可以使用 docker ps -a 查看本地运行过的容器。Docker 的仓库用于存放镜像。这一点,和 Git 非常类似。我们可以从中心仓库下载镜像,也可以从自建仓库下载。同时,我们可以把制作好的镜像 commit 到本地,然后 push 到远程仓库。仓库分为公开仓库和私有仓库,最大的公开仓库是官方仓库 Dock Hub,国内的公开仓库也有很多选择,例如阿里云等。3. Docker 促使开发流程变更笔者认为,Docker 对开发流程的影响在于使环境标准化。例如,原来我们存在三个环境:开发(日常)环境、测试环境、生产环境。这里,我们对于每个环境都需要部署相同的软件、脚本和运行程序,如图所示。事实上,对于启动脚本内容都是一致的,但是没有统一维护,经常会出问题。此外,对于运行程序而言,如果所依赖的底层运行环境不一致,也会造成困扰和异常。现在,我们通过引入 Docker 之后,我们只需要维护一个 Docker 镜像。换句话说,多套环境,一个镜像,实现系统级别的一次构建到处运行。此时,我们把运行脚本标准化了,把底层软件镜像化了,然后对于相同的将要部署的程序实行标准化部署。因此,Docker 为我们提供了一个标准化的运维模式,并固化运维步骤和流程。通过这个流程的改进,我们更容易实现 DevOps 的目标,因为我们的镜像生成后可以跑在任何系统,并快速部署。此外,使用 Docker 的很大动力是基于 Docker 实现弹性调度,以更充分地利用机器资源,节省成本。哈哈,笔者在使用 Docker 过程中,还发现了一些很棒的收益点,例如我们发布回滚的时候只需要切换 TAG 并重启即可。还比如,我们对环境升级,也只需要升级基础镜像,那么新构建的应用镜像,自动会引用新的版本。(欢迎补充~~~)二、从搭建 Web 服务器开始说起1. 环境先行,安装 Docker现在,我们需要安装以下步骤安装 Docker。注册帐号:在 https://hub.docker.com/ 注册账号。 下载安装官方下载地址:(Mac):https://download.docker.com/m…阿里云下载地址(Mac):http://mirrors.aliyun.com/doc…阿里云下载地址(Windows):http://mirrors.aliyun.com/doc…安装指南这里,双击刚刚下载的 Doker.dmg 安装包进行安装。安装完成后启动, Mac 顶部导航栏出现了一个图标,通过菜单可以进行 docker 配置和退出等操作。官方指南:https://docs.docker.com/install/阿里云指南(Linux):https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.468b1991jdT95t设置加速服务市面上有很多加速服务的提供商,如:DaoCloud,阿里云等。这里,笔者使用的是阿里云。(注意的是,笔者操作系统是 Mac,其他操作系列参见阿里云操作文档) 右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 之前版本为 Advanced 标签)下的 Registry mirrors 列表中将https://xxx.mirror.aliyuncs.com 加到"registry-mirrors"的数组里,点击 Apply & Restart 按钮,等待 Docker 重启并应用配置的镜像加速器。阿里云操作文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors查看版本至此,我们已经安装完成了。这里,我们来查看版本。 docker version 查看结果,如下所示。 2. 实干派,从搭建 Web 服务器开始我们作为实干派,那么先来搭建一个 Web 服务器吧。然后,笔者带你慢慢理解这个过程中,做了什么事情。首先,我们需要拉取 centos 镜像。docker run -p 80 –name web -i -t centos /bin/bash紧接着,我们安装 nginx 服务器,执行以下命令:rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm安装完 Nginx 源后,就可以正式安装 Nginx 了。yum install -y nginx至此,我们再输入 whereis nginx 命令就可以看到安装的路径了。最后,我们还需要将 Nginx 跑起来。nginx现在,我们执行 ctrl + P + Q 切换到后台。然后,通过 docker ps -a 来查看随机分配的端口。这里,笔者分配的端口是 32769 ,那么通过浏览器访问 http://127.0.0.1:32769 即可。大功告成,哈哈哈~3. 复盘理解全过程现在,我们来理解下这个流程。首先,我们输入 docker run -p 80 –name web -i -t centos /bin/bash 命令会运行交互式容器,其中 -i 选项告诉 Docker 容器保持标准输入流对容器开放,即使容器没有终端连接,另一个 -t 选项告诉 Docker 为容器分配一个虚拟终端,以便于我们接下来安装 Nginx 服务器。(笔者备注:Docker 还支持输入 -d 选项告诉 Docker 在后台运行容器的守护进程)Docker 会为我们创建的每一个容器自动生成一个随机的名称。事实上,这种方式虽然便捷,但是可读性很差,并且对我们后期维护的理解成本会比较大。因此,我们通过 –name web 选项告诉 Docker 创建一个名称是 web 的容器。此外,我们通过 -p 80 告诉 Docker 开放 80 端口,那么, Nginx 才可以对外通过访问和服务。但是,我们的宿主机器会自动做端口映射,比如上面分配的端口是 32769 ,注意的是,如果关闭或者重启,这个端口就变了,那么怎么解决固定端口的问题,笔者会在后面详细剖析和带你实战。这里,还有一个非常重要的知识点 docker run 。Docker 通过 run 命令来启动一个新容器。Docker 首先在本机中寻找该镜像,如果没有安装,Docker 在 Docker Hub 上查找该镜像并下载安装到本机,最后 Docker 创建一个新的容器并启动该程序。但是,当第二次执行 docker run 时,因为 Docker 在本机中已经安装该镜像,所以 Docker 会直接创建一个新的容器并启动该程序。注意的是,docker run 每次使用都会创建一个新的容器,因此,我们以后再次启动这个容器时,只需要使用命令 docker start 即可。这里, docker start 的作用在用重新启动已存在的镜像,而docker run 包含将镜像放入容器中 docker create ,然后将容器启动 docker start ,如图所示。现在,我们可以在上面的案例的基础上,通过 exit 命令关闭 Docker 容器。当然,如果我们运行的是后台的守护进程,我们也可以通过 docker stop web 来停止。注意的是,docker stop 和 docker kill 略有不同,docker stop 发送 SIGTERM 信号,而 docker kill 发送SIGKILL 信号。然后,我们使用 docker start 重启它。docker start webDocker 容器重启后会沿用 docker run 命令指定的参数来运行,但是,此时它还是后台运行的。我们必须通过 docker attach 命令切换到运行交互式容器。docker attach web4. 不止如此,还有更多命令Docker 提供了非常丰富的命令。所谓一图胜千言,我们可以从下面的图片了解到很多信息和它们之前的用途。(可以直接跳过阅读,建议收藏,便于扩展阅读)官方阅读链接:https://docs.docker.com/engin…5. 进阶:仓库与软件安装的简化还记得笔者在文章开头介绍的「镜像、容器和仓库」吗?Docker 的仓库用于存放镜像。我们可以从中心仓库下载镜像,也可以从自建仓库下载。同时,我们可以把制作好的镜像从本地推送到远程仓库。首先,笔者先引入一个知识点:Docker 的镜像就是它的文件系统,一个镜像可以放在另外一个镜像的上层,那么位于下层的就是它的父镜像。所以,Docker 会存在很多镜像层,每个镜像层都是只读的,并且不会改变。当我们创建一个新的容器时,Docker 会构建出一个镜像栈,并在栈的最顶层添加一个读写层,如图所示。现在,我们可以通过 docker images 命令查看本地的镜像。docker images这里,对几个名词解释一下含义。REPOSITORY:仓库名称。TAG: 镜像标签,其中 lastest 表示最新版本。注意的是,一个镜像可以有多个标签,那么我们就可以通过标签来管理有用的版本和功能标-签。IMAGE ID :镜像唯一ID。CREATED :创建时间。SIZE :镜像大小。那么,如果第一次我们通过 docker pull centos:latest 拉取镜像,那么当我们执行 docker run -p 80 –name web -i -t centos /bin/bash 时,它就不会再去远程获取了,因为本机中已经安装该镜像,所以 Docker 会直接创建一个新的容器并启动该程序。事实上,官方已经提供了安装好 Nginx 的镜像,我们可以直接使用。现在,我们通过拉取镜像的方式重新构建一个 Web 服务器。首先,我们通过 docker search 来查找镜像。我们获取到 Nginx 的镜像清单。docker search nginx补充一下,我们也可以通过访问 Docker Hub (https://hub.docker.com/)搜索仓库,那么 star 数越多,说明它越靠谱,可以放心使用。现在,我们通过 docker pull nginx 拉取最新的 Nginx 的镜像。当然,我们也可以通过 docker pull nginx:latest 来操作。docker pull nginx然后,我们创建并运行一个容器。与前面不同的是,我们通过 -d 选项告诉 Docker 在后台运行容器的守护进程。并且,通过 8080:80 告诉 Docker 8080 端口是对外开放的端口,80 端口对外开放的端口映射到容器里的端口号。docker run -p 8080:80 -d –name nginx nginx我们再通过 docker ps -a 来查看,发现容器已经后台运行了,并且后台执行了 nginx 命令,并对外开放 8080 端口。因此,通过浏览器访问 http://127.0.0.1:8080 即可。三、构建我的镜像通过上面的学习,笔者相信你已经对 Docker 使用有了一个大致的了解,就好比我们通过 VMware 安装了一个系统,并让它跑了起来,那么我们就可以在这个 Linux 系统(CentOS 或者 Ubuntu ) 上面工作我们想要的任何事情。事实上,我们还会经常把我们安装好的 VMware 系统进行快照备份并实现克隆来满足我们下次快速的复制。这里,Docker 也可以构建定制内容的 Docker 镜像,例如上面我们使用官方提供的安装好 Nginx 的 Docker 镜像。注意的是,我们通过基于已有的基础镜像,在上面添加镜像层的方式构建新镜像而已。总结一下,Docker 提供自定义镜像的能力,它可以让我们保存对基础镜像的修改,并再次使用。那么,我们就可以把操作系统、运行环境、脚本和程序打包在一起,并在宿主机上对外提供服务。Docker 构建镜像有两种方式,一种方式是使用 docker commit 命令,另外一种方式使用 docker build 命令和 Dockerfile 文件。其中,不推荐使用 docker commit 命令进行构建,因为它没有使得整个流程标准化,因此,在企业的中更加推荐使用 docker build 命令和 Dockerfile 文件来构建我们的镜像。我们使用Dockerfile 文件可以让构建镜像更具备可重复性,同时保证启动脚本和运行程序的标准化。1. 构建第一个 Dockerfile 文件现在,我们继续实战。这里,我们把一开始搭建的 Web 服务器构建一个镜像。首先,我们需要创建一个空的 Dokcerfile 文件。mkdir dockerfile_test cd dockerfile_test/ touch Dockerfile nano Dockerfile紧接着,我们需要编写一个 Dockerfile 文件,代码清单如下FROM centos:7MAINTAINER LiangGzone “lianggzone@163.com"RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpmRUN yum install -y nginxEXPOSE 80最后,我们通过 docker build 命令进行构建。docker build -t=“lianggzone/nginx_demo:v1” .现在, 我们来通过 docker images 看下我们的新镜像吧。2. 理解 Dockerfile 全过程哇,我们通过编写一个 Dockerfile 文件顺利构建了一个新的镜像。这个过程简单得让人无法相信。现在,让我们来理解一下这个全过程吧。首先, FROM centos:7 是 Dockerfile 必须要的第一步,它会从一个已经存在的镜像运行一个容器,换句话说,Docker 需要依赖于一个基础镜像进行构建。这里,我们指定 centos 作为基础镜像,它的版本是 7 (CentOS 7)。然后,我们通过 MAINTAINER LiangGzone “lianggzone@163.com” 指定该镜像的作者是 LiangGzone,邮箱是 lianggzone@163.com。这有助于告诉使用者它的作者和联系方式。接着,我们执行两个 RUN 指令进行 Nginx 的下载安装,最后通过 EXPOSE 80 暴露 Dokcer 容器的 80 端口。注意的是,Docker 的执行顺序是从上而下执行的,所以我们要明确整个流程的执行顺序。除此之外,Docker 在执行每个指令之后都会创建一个新的镜像层并且进行提交。我们使用 docker build 命令进行构建,指定 - t 告诉 Docker 镜像的名称和版本。注意的是,如果没有指定任何标签,Docker 将会自动为镜像设置一个 lastest 标签。还有一点,我们最后还有一个 . 是为了让 Docker 到当前本地目录去寻找 Dockerfile 文件。注意的是,Docker 会在每一步构建都会将结果提交为镜像,然后将之前的镜像层看作缓存,因此我们重新构建类似的镜像层时会直接复用之前的镜像。如果我们需要跳过,可以使用 –no-cache 选项告诉 Docker 不进行缓存。3. Dockerfile 指令详解Dockerfile 提供了非常多的指令。笔者这里特别整理了一份清单,建议收藏查看。官方地址:https://docs.docker.com/engin…指令辨别一:RUN、CMD、ENTRYPOINTRUN 、 CMD 、 ENTRYPOINT 三个指令的用途非常相识,不同在于,RUN 指令是在容器被构建时运行的命令,而CMD 、 ENTRYPOINT 是启动容器时执行 shell 命令,而 RUN 会被 docker run 命令覆盖,但是 ENTRYPOINT 不会被覆盖。事实上,docker run 命令指定的任何参数都会被当作参数再次传递给 ENTRYPOINT 指令。CMD 、 ENTRYPOINT 两个指令之间也可以一起使用。例如,我们 可以使用 ENTRYPOINT 的 exec 形式设置固定的默认命令和参数,然后使用任一形式的 CMD 来设置可能更改的其他默认值。FROM ubuntuENTRYPOINT [“top”, “-b”]CMD ["-c”]指令辨别二:ADD、COPYADD 、 COPY 指令用法一样,唯一不同的是 ADD 支持将归档文件(tar, gzip, bzip2, etc)做提取和解压操作。注意的是,COPY 指令需要复制的目录一定要放在 Dockerfile 文件的同级目录下。4. 将镜像推送到远程仓库远程仓库:Docker Hub镜像构建完毕之后,我们可以将它上传到 Docker Hub 上面。首先,我们需要通过 docker login 保证我们已经登录了。紧接着,我们使用 docker push 命令进行推送。docker push lianggzone/nginx_demo:v1这里,我们了解下它的使用,格式是 docker push [OPTIONS] NAME[:TAG] ,其中,笔者设置 NAME 是 lianggzone/nginx_demo,TAG 是 v1。 (笔者注:推送 Docker Hub 速度很慢,耐心等待) 最后,上传完成后访问:https://hub.docker.com/u/lian…远程仓库:阿里云同时,我们也可以使用国内的仓库,比如阿里云。首先,在终端中输入访问凭证,登录 Registry 实例。如果你不知道是哪个,可以访问 https://cr.console.aliyun.com…。docker login –username=帐号 registry.cn-hangzhou.aliyuncs.com现在,将镜像推送到阿里云镜像仓库。其中, docker tag [IMAGE_ID] registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本] 和 docker push registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本] 命令的使用如下所示。docker tag 794c07361565 registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1 docker push registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1最后,上传完成后访问:https://cr.console.aliyun.com…,如图所示。5. Dockerfile 的 Github 源码地址这里,附上我整理的 Dockerfile 的仓库。后面,笔者会陆续更新用到的一些常用文件,欢迎 star 关注。https://github.com/lianggzone…附:参考资料《Docker实战》《第一本Docker书》Docker 命令参考文档Dockerfile 镜像构建参考文档(完,转载请注明作者及出处。)写在末尾【服务端思维】:我们一起聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。同时,拥有众多技术大牛的「后端圈」大家庭,期待你的加入,一群同频者,一起成长,一起精进,打破认知的局限性。更多精彩文章,尽在「服务端思维」! ...

April 11, 2019 · 3 min · jiezi

Spring Boot重启后服务第一次访问时间慢的一次调优记录

背景今天和分子公司合并服务接口(降低成本),对方反应我这边有个服务慢,搞了一天,就顺便记录下服务调优1. 网络由于生产机和测试机在机房处于不同网段,网络环境质量有差异,最开始怀疑的是网络导致的。分别在几个环境中跑相同代码,发现是网络影响的调用三方服务返回时间波动。2.调优基于业务需求,更改调用三方服务方法为异步调用。嗯!应该没问题了。3.验证进行优化验证,发现调用平均时长有明显降低(废话)。但是,但可是,发现了新问题,在spring boot启动后第一次调用本服务,耗时仍旧远远高于后续调用,正常在20ms/次,第一次平均在600ms/次,于是开始google于是看到了这个提问https://segmentfault.com/q/10…修改项目在查看Dockerfile后,发现启动脚本中有加如下参数JAVA_ALL_OPTS=" -Djava.security.egd=file:/dev/./urandom “继而想修改docker基础镜像中jre的java.security文件遂在Dockerfile中增加如下shellsed -i “117csecurerandom.source=file:/dev/./urandom” /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/java.security就是用shell 替换了文本的内容结论其实,也没有明显的效率提升,服务首次加载还是比之后慢。所以考虑,是不是文件是不是没有改全(待完成,还没验证)最后,通过验证发现一个规律,假设有A B两个服务,在Spring Boot 启动后,如果先首次访问A,那么B的首次访问时间会缩短,但是还是会高于第二次及以后的访问时间如果先首次访问B,那么A的首次访问时间会缩短,但是还是会高于第二次及以后的访问时间因此,在Spring boot启动后,第一个被访问的服务耗时一定大于第二个被访问的服务,且每个服务之后的访问时间一定小于本服务第一次被访问的时间。暂时就这么多,这是个记录。之后会对基础镜像中jdk里面的java.security进行修改,如果有效果 会再更新。刚才又找了一下,发现jdk目录里没有java.security,是我秀逗了

April 10, 2019 · 1 min · jiezi

30 分钟快速入门 Docker 教程

原文地址:梁桂钊的博客博客地址:http://blog.720ui.com欢迎关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,打破认知的局限性。30 分钟快速入门 Docker 教程一、欢迎来到 Docker 世界1. Docker 与虚拟化在没有 Docker 的时代,我们会使用硬件虚拟化(虚拟机)以提供隔离。这里,虚拟机通过在操作系统上建立了一个中间虚拟软件层 Hypervisor ,并利用物理机器的资源虚拟出多个虚拟硬件环境来共享宿主机的资源,其中的应用运行在虚拟机内核上。但是,虚拟机对硬件的利用率存在瓶颈,因为虚拟机很难根据当前业务量动态调整其占用的硬件资源,因此容器化技术得以流行。其中,Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。Docker 容器不使用硬件虚拟化,它的守护进程是宿主机上的一个进程,换句话说,应用直接运行在宿主机内核上。因为容器中运行的程序和计算机的操作系统之间没有额外的中间层,没有资源被冗余软件的运行或虚拟硬件的模拟而浪费掉。Docker 的优势不仅如此,我们来比较一番。特性Docker虚拟机启动速度秒级分钟级交付/部署开发、测试、生产环境一致无成熟体系性能近似物理机性能损耗大体量极小(MB)较大(GB)迁移/扩展跨平台,可复制较为复杂2. 镜像、容器和仓库Docker 由镜像(Image)、容器(Container)、仓库(Repository) 三部分组成。Docker 的镜像可以简单的类比为电脑装系统用的系统盘,包括操作系统,以及必要的软件。例如,一个镜像可以包含一个完整的 centos 操作系统环境,并安装了 Nginx 和 Tomcat 服务器。注意的是,镜像是只读的。这一点也很好理解,就像我们刻录的系统盘其实也是可读的。我们可以使用 docker images 来查看本地镜像列表。Docker 的容器可以简单理解为提供了系统硬件环境,它是真正跑项目程序、消耗机器资源、提供服务的东西。例如,我们可以暂时把容器看作一个 Linux 的电脑,它可以直接运行。那么,容器是基于镜像启动的,并且每个容器都是相互隔离的。注意的是,容器在启动的时候基于镜像创建一层可写层作为最上层。我们可以使用 docker ps -a 查看本地运行过的容器。Docker 的仓库用于存放镜像。这一点,和 Git 非常类似。我们可以从中心仓库下载镜像,也可以从自建仓库下载。同时,我们可以把制作好的镜像 commit 到本地,然后 push 到远程仓库。仓库分为公开仓库和私有仓库,最大的公开仓库是官方仓库 Dock Hub,国内的公开仓库也有很多选择,例如阿里云等。3. Docker 促使开发流程变更笔者认为,Docker 对开发流程的影响在于使环境标准化。例如,原来我们存在三个环境:开发(日常)环境、测试环境、生产环境。这里,我们对于每个环境都需要部署相同的软件、脚本和运行程序,如图所示。事实上,对于启动脚本内容都是一致的,但是没有统一维护,经常会出问题。此外,对于运行程序而言,如果所依赖的底层运行环境不一致,也会造成困扰和异常。现在,我们通过引入 Docker 之后,我们只需要维护一个 Docker 镜像。换句话说,多套环境,一个镜像,实现系统级别的一次构建到处运行。此时,我们把运行脚本标准化了,把底层软件镜像化了,然后对于相同的将要部署的程序实行标准化部署。因此,Docker 为我们提供了一个标准化的运维模式,并固化运维步骤和流程。通过这个流程的改进,我们更容易实现 DevOps 的目标,因为我们的镜像生成后可以跑在任何系统,并快速部署。此外,使用 Docker 的很大动力是基于 Docker 实现弹性调度,以更充分地利用机器资源,节省成本。哈哈,笔者在使用 Docker 过程中,还发现了一些很棒的收益点,例如我们发布回滚的时候只需要切换 TAG 并重启即可。还比如,我们对环境升级,也只需要升级基础镜像,那么新构建的应用镜像,自动会引用新的版本。(欢迎补充~~~)二、从搭建 Web 服务器开始说起1. 环境先行,安装 Docker现在,我们需要安装以下步骤安装 Docker。注册帐号:在 https://hub.docker.com/ 注册账号。下载安装官方下载地址:(Mac):https://download.docker.com/mac/stable/Docker.dmg阿里云下载地址(Mac):http://mirrors.aliyun.com/docker-toolbox/mac/docker-for-mac/阿里云下载地址(Windows): http://mirrors.aliyun.com/docker-toolbox/windows/docker-for-windows/安装指南这里,双击刚刚下载的 Doker.dmg 安装包进行安装。安装完成后启动, Mac 顶部导航栏出现了一个图标,通过菜单可以进行 docker 配置和退出等操作。官方指南:https://docs.docker.com/install/阿里云指南(Linux):https://yq.aliyun.com/articles/110806?spm=5176.8351553.0.0.468b1991jdT95t设置加速服务市面上有很多加速服务的提供商,如:DaoCloud,阿里云等。这里,笔者使用的是阿里云。(注意的是,笔者操作系统是 Mac,其他操作系列参见阿里云操作文档) 右键点击桌面顶栏的 docker 图标,选择 Preferences ,在 Daemon 标签(Docker 17.03 之前版本为 Advanced 标签)下的 Registry mirrors 列表中将https://xxx.mirror.aliyuncs.com 加到"registry-mirrors"的数组里,点击 Apply & Restart 按钮,等待 Docker 重启并应用配置的镜像加速器。阿里云操作文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors查看版本至此,我们已经安装完成了。这里,我们来查看版本。docker version查看结果,如下所示。2. 实干派,从搭建 Web 服务器开始我们作为实干派,那么先来搭建一个 Web 服务器吧。然后,笔者带你慢慢理解这个过程中,做了什么事情。首先,我们需要拉取 centos 镜像。docker run -p 80 –name web -i -t centos /bin/bash紧接着,我们安装 nginx 服务器,执行以下命令:rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm安装完 Nginx 源后,就可以正式安装 Nginx 了。yum install -y nginx至此,我们再输入 whereis nginx 命令就可以看到安装的路径了。最后,我们还需要将 Nginx 跑起来。nginx现在,我们执行 ctrl + P + Q 切换到后台。然后,通过 docker ps -a 来查看随机分配的端口。这里,笔者分配的端口是 32769 ,那么通过浏览器访问 http://127.0.0.1:32769 即可。大功告成,哈哈哈~3. 复盘理解全过程现在,我们来理解下这个流程。首先,我们输入 docker run -p 80 –name web -i -t centos /bin/bash 命令会运行交互式容器,其中 -i 选项告诉 Docker 容器保持标准输入流对容器开放,即使容器没有终端连接,另一个 -t 选项告诉 Docker 为容器分配一个虚拟终端,以便于我们接下来安装 Nginx 服务器。(笔者备注:Docker 还支持输入 -d 选项告诉 Docker 在后台运行容器的守护进程)Docker 会为我们创建的每一个容器自动生成一个随机的名称。事实上,这种方式虽然便捷,但是可读性很差,并且对我们后期维护的理解成本会比较大。因此,我们通过 –name web 选项告诉 Docker 创建一个名称是 web 的容器。此外,我们通过 -p 80 告诉 Docker 开放 80 端口,那么, Nginx 才可以对外通过访问和服务。但是,我们的宿主机器会自动做端口映射,比如上面分配的端口是 32769 ,注意的是,如果关闭或者重启,这个端口就变了,那么怎么解决固定端口的问题,笔者会在后面详细剖析和带你实战。这里,还有一个非常重要的知识点 docker run 。Docker 通过 run 命令来启动一个新容器。Docker 首先在本机中寻找该镜像,如果没有安装,Docker 在 Docker Hub 上查找该镜像并下载安装到本机,最后 Docker 创建一个新的容器并启动该程序。但是,当第二次执行 docker run 时,因为 Docker 在本机中已经安装该镜像,所以 Docker 会直接创建一个新的容器并启动该程序。注意的是,docker run 每次使用都会创建一个新的容器,因此,我们以后再次启动这个容器时,只需要使用命令 docker start 即可。这里, docker start 的作用在用重新启动已存在的镜像,而docker run 包含将镜像放入容器中 docker create ,然后将容器启动 docker start ,如图所示。现在,我们可以在上面的案例的基础上,通过 exit 命令关闭 Docker 容器。当然,如果我们运行的是后台的守护进程,我们也可以通过 docker stop web 来停止。注意的是,docker stop 和 docker kill 略有不同,docker stop 发送 SIGTERM 信号,而 docker kill 发送SIGKILL 信号。然后,我们使用 docker start 重启它。docker start webDocker 容器重启后会沿用 docker run 命令指定的参数来运行,但是,此时它还是后台运行的。我们必须通过 docker attach 命令切换到运行交互式容器。docker attach web4. 不止如此,还有更多命令Docker 提供了非常丰富的命令。所谓一图胜千言,我们可以从下面的图片了解到很多信息和它们之前的用途。(可以直接跳过阅读,建议收藏,便于扩展阅读)如果希望获取更多信息,可以阅读官方使用文档。CommandDescriptiondocker attachAttach local standard input, output, and error streams to a running containerdocker buildBuild an image from a Dockerfiledocker builderManage buildsdocker checkpointManage checkpointsdocker commitCreate a new image from a container’s changesdocker configManage Docker configsdocker containerManage containersdocker cpCopy files/folders between a container and the local filesystemdocker createCreate a new containerdocker deployDeploy a new stack or update an existing stackdocker diffInspect changes to files or directories on a container’s filesystemdocker engineManage the docker enginedocker eventsGet real time events from the serverdocker execRun a command in a running containerdocker exportExport a container’s filesystem as a tar archivedocker historyShow the history of an imagedocker imageManage imagesdocker imagesList imagesdocker importImport the contents from a tarball to create a filesystem imagedocker infoDisplay system-wide informationdocker inspectReturn low-level information on Docker objectsdocker killKill one or more running containersdocker loadLoad an image from a tar archive or STDINdocker loginLog in to a Docker registrydocker logoutLog out from a Docker registrydocker logsFetch the logs of a containerdocker manifestManage Docker image manifests and manifest listsdocker networkManage networksdocker nodeManage Swarm nodesdocker pausePause all processes within one or more containersdocker pluginManage pluginsdocker portList port mappings or a specific mapping for the containerdocker psList containersdocker pullPull an image or a repository from a registrydocker pushPush an image or a repository to a registrydocker renameRename a containerdocker restartRestart one or more containersdocker rmRemove one or more containersdocker rmiRemove one or more imagesdocker runRun a command in a new containerdocker saveSave one or more images to a tar archive (streamed to STDOUT by default)docker searchSearch the Docker Hub for imagesdocker secretManage Docker secretsdocker serviceManage servicesdocker stackManage Docker stacksdocker startStart one or more stopped containersdocker statsDisplay a live stream of container(s) resource usage statisticsdocker stopStop one or more running containersdocker swarmManage Swarmdocker systemManage Dockerdocker tagCreate a tag TARGET_IMAGE that refers to SOURCE_IMAGEdocker topDisplay the running processes of a containerdocker trustManage trust on Docker imagesdocker unpauseUnpause all processes within one or more containersdocker updateUpdate configuration of one or more containersdocker versionShow the Docker version informationdocker volumeManage volumesdocker waitBlock until one or more containers stop, then print their exit codes官方阅读链接:https://docs.docker.com/engine/reference/commandline/docker/5. 进阶:仓库与软件安装的简化还记得笔者在文章开头介绍的「镜像、容器和仓库」吗?Docker 的仓库用于存放镜像。我们可以从中心仓库下载镜像,也可以从自建仓库下载。同时,我们可以把制作好的镜像从本地推送到远程仓库。首先,笔者先引入一个知识点:Docker 的镜像就是它的文件系统,一个镜像可以放在另外一个镜像的上层,那么位于下层的就是它的父镜像。所以,Docker 会存在很多镜像层,每个镜像层都是只读的,并且不会改变。当我们创建一个新的容器时,Docker 会构建出一个镜像栈,并在栈的最顶层添加一个读写层,如图所示。现在,我们可以通过 docker images 命令查看本地的镜像。docker images查询结果,如图所示。这里,对几个名词解释一下含义。REPOSITORY:仓库名称。TAG: 镜像标签,其中 lastest 表示最新版本。注意的是,一个镜像可以有多个标签,那么我们就可以通过标签来管理有用的版本和功能标签。IMAGE ID :镜像唯一ID。CREATED :创建时间。SIZE :镜像大小。那么,如果第一次我们通过 docker pull centos:latest 拉取镜像,那么当我们执行 docker run -p 80 –name web -i -t centos /bin/bash 时,它就不会再去远程获取了,因为本机中已经安装该镜像,所以 Docker 会直接创建一个新的容器并启动该程序。事实上,官方已经提供了安装好 Nginx 的镜像,我们可以直接使用。现在,我们通过拉取镜像的方式重新构建一个 Web 服务器。首先,我们通过 docker search 来查找镜像。我们获取到 Nginx 的镜像清单。docker search nginx补充一下,我们也可以通过访问 Docker Hub (https://hub.docker.com/)搜索仓库,那么 star 数越多,说明它越靠谱,可以放心使用。现在,我们通过 docker pull nginx 拉取最新的 Nginx 的镜像。当然,我们也可以通过 docker pull nginx:latest 来操作。docker pull nginx然后,我们创建并运行一个容器。与前面不同的是,我们通过 -d 选项告诉 Docker 在后台运行容器的守护进程。并且,通过 8080:80 告诉 Docker 8080 端口是对外开放的端口,80 端口对外开放的端口映射到容器里的端口号。docker run -p 8080:80 -d –name nginx nginx我们再通过 docker ps -a 来查看,发现容器已经后台运行了,并且后台执行了 nginx 命令,并对外开放 8080 端口。因此,通过浏览器访问 http://127.0.0.1:8080 即可。6. 其他选择,使用替代注册服务器Docker Hub 不是软件的唯一来源,我们也可以切换到国内的其他替代注册服务器,例如阿里云。我们可以登录 https://cr.console.aliyun.com 搜索,并拉取公开的镜像。现在,我们输入 docker pull 命令进行拉取。docker pull registry.cn-hangzhou.aliyuncs.com/qp_oraclejava/orackejava:8u172_DCEVM_HOTSWAPAGEN_JCE这里,笔者继续补充一个知识点:注册服务器的地址。事实上,注册服务器的地址是有一套规范的。完整格式是:仓库主机/容器短名[:标签]。这里,仓库主机是 registry.cn-hangzhou.aliyuncs.com,用户名是 qp_oraclejava,容器短名是 orackejava,标签名是 8u172_DCEVM_HOTSWAPAGEN_JCE。事实上,我们上面通过 docker pull centos:latest 拉取镜像,相当于 docker pull registry.hub.docker.com/centos:latest 。三、构建我的镜像通过上面的学习,笔者相信你已经对 Docker 使用有了一个大致的了解,就好比我们通过 VMware 安装了一个系统,并让它跑了起来,那么我们就可以在这个 Linux 系统(CentOS 或者 Ubuntu ) 上面工作我们想要的任何事情。事实上,我们还会经常把我们安装好的 VMware 系统进行快照备份并实现克隆来满足我们下次快速的复制。这里,Docker 也可以构建定制内容的 Docker 镜像,例如上面我们使用官方提供的安装好 Nginx 的 Docker 镜像。注意的是,我们通过基于已有的基础镜像,在上面添加镜像层的方式构建新镜像而已。总结一下,Docker 提供自定义镜像的能力,它可以让我们保存对基础镜像的修改,并再次使用。那么,我们就可以把操作系统、运行环境、脚本和程序打包在一起,并在宿主机上对外提供服务。Docker 构建镜像有两种方式,一种方式是使用 docker commit 命令,另外一种方式使用 docker build 命令和 Dockerfile 文件。其中,不推荐使用 docker commit 命令进行构建,因为它没有使得整个流程标准化,因此,在企业的中更加推荐使用 docker build 命令和 Dockerfile 文件来构建我们的镜像。我们使用Dockerfile 文件可以让构建镜像更具备可重复性,同时保证启动脚本和运行程序的标准化。1. 构建第一个 Dockerfile 文件现在,我们继续实战。这里,我们把一开始搭建的 Web 服务器构建一个镜像。首先,我们需要创建一个空的 Dokcerfile 文件。mkdir dockerfile_testcd dockerfile_test/touch Dockerfilenano Dockerfile紧接着,我们需要编写一个 Dockerfile 文件,代码清单如下FROM centos:7MAINTAINER LiangGzone “lianggzone@163.com"RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpmRUN yum install -y nginxEXPOSE 80最后,我们通过 docker build 命令进行构建。docker build -t=“lianggzone/nginx_demo:v1” .现在, 我们来通过 docker images 看下我们的新镜像吧。2. 理解 Dockerfile 全过程哇,我们通过编写一个 Dockerfile 文件顺利构建了一个新的镜像。这个过程简单得让人无法相信。现在,让我们来理解一下这个全过程吧。首先, FROM centos:7 是 Dockerfile 必须要的第一步,它会从一个已经存在的镜像运行一个容器,换句话说,Docker 需要依赖于一个基础镜像进行构建。这里,我们指定 centos 作为基础镜像,它的版本是 7 (CentOS 7)。然后,我们通过 MAINTAINER LiangGzone “lianggzone@163.com” 指定该镜像的作者是 LiangGzone,邮箱是 lianggzone@163.com。这有助于告诉使用者它的作者和联系方式。接着,我们执行两个 RUN 指令进行 Nginx 的下载安装,最后通过 EXPOSE 80 暴露 Dokcer 容器的 80 端口。注意的是,Docker 的执行顺序是从上而下执行的,所以我们要明确整个流程的执行顺序。除此之外,Docker 在执行每个指令之后都会创建一个新的镜像层并且进行提交。我们使用 docker build 命令进行构建,指定 - t 告诉 Docker 镜像的名称和版本。注意的是,如果没有指定任何标签,Docker 将会自动为镜像设置一个 lastest 标签。还有一点,我们最后还有一个 . 是为了让 Docker 到当前本地目录去寻找 Dockerfile 文件。注意的是,Docker 会在每一步构建都会将结果提交为镜像,然后将之前的镜像层看作缓存,因此我们重新构建类似的镜像层时会直接复用之前的镜像。如果我们需要跳过,可以使用 –no-cache 选项告诉 Docker 不进行缓存。3. Dockerfile 指令详解Dockerfile 提供了非常多的指令。笔者这里特别整理了一份清单,建议收藏查看。官方地址:https://docs.docker.com/engine/reference/builder/#usage指令辨别一:RUN、CMD、ENTRYPOINTRUN 、 CMD 、 ENTRYPOINT 三个指令的用途非常相识,不同在于,RUN 指令是在容器被构建时运行的命令,而CMD 、 ENTRYPOINT 是启动容器时执行 shell 命令,而 RUN 会被 docker run 命令覆盖,但是 ENTRYPOINT 不会被覆盖。事实上,docker run 命令指定的任何参数都会被当作参数再次传递给 ENTRYPOINT 指令。CMD 、 ENTRYPOINT 两个指令之间也可以一起使用。例如,我们 可以使用 ENTRYPOINT 的 exec 形式设置固定的默认命令和参数,然后使用任一形式的 CMD 来设置可能更改的其他默认值。FROM ubuntuENTRYPOINT [“top”, “-b”]CMD ["-c”]指令辨别二:ADD、COPYADD 、 COPY 指令用法一样,唯一不同的是 ADD 支持将归档文件(tar, gzip, bzip2, etc)做提取和解压操作。注意的是,COPY 指令需要复制的目录一定要放在 Dockerfile 文件的同级目录下。4. 将镜像推送到远程仓库远程仓库:Docker Hub 镜像构建完毕之后,我们可以将它上传到 Docker Hub 上面。首先,我们需要通过 docker login 保证我们已经登录了。紧接着,我们使用 docker push 命令进行推送。docker push lianggzone/nginx_demo:v1这里,我们了解下它的使用,格式是 docker push [OPTIONS] NAME[:TAG] ,其中,笔者设置 NAME 是 lianggzone/nginx_demo,TAG 是 v1。 (笔者注:推送 Docker Hub 速度很慢,耐心等待) 最后,上传完成后访问:https://hub.docker.com/u/lianggzone/,如图所示。远程仓库:阿里云同时,我们也可以使用国内的仓库,比如阿里云。首先,在终端中输入访问凭证,登录 Registry 实例。如果你不知道是哪个,可以访问 https://cr.console.aliyun.com/cn-hangzhou/instances/credentials。docker login –username=帐号 registry.cn-hangzhou.aliyuncs.com现在,将镜像推送到阿里云镜像仓库。其中, docker tag [IMAGE_ID] registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本] 和 docker push registry.cn-hangzhou.aliyuncs.com/[命名空间]/[镜像名称]:[版本] 命令的使用如下所示。docker tag 794c07361565 registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1docker push registry.cn-hangzhou.aliyuncs.com/lianggzone/nginx_demo:v1最后,上传完成后访问:https://cr.console.aliyun.com/cn-hangzhou/instances/repositories,如图所示。5. Dockerfile 的 Github 源码地址这里,附上我整理的 Dockerfile 的仓库。后面,笔者会陆续更新用到的一些常用文件,欢迎 star 关注。https://github.com/lianggzone/dockerfile-images附:参考资料《Docker实战》《第一本Docker书》Docker 命令参考文档Dockerfile 镜像构建参考文档(完,转载请注明作者及出处。)写在末尾【服务端思维】:我们一起聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。同时,拥有众多技术大牛的「后端圈」大家庭,期待你的加入,一群同频者,一起成长,一起精进,打破认知的局限性。更多精彩文章,尽在「服务端思维」! ...

April 10, 2019 · 5 min · jiezi

part-one-microservices

microservices微服务架构提供一个拆分大型应用为较小可相互影响通信的服务的手段。从整体拆分,每个服务可独立交付, 使得每个服务可独立的部署, 升级 , 缩小, 和替代。服务间通信通常通过网络连接HTTP 调研(request/response). Web sockets,message queues , pub/sub, 和 remote procedure calls(RPC) 也可以被用于连接独立组建。每个独立服务专注于一个单一任务, 通常按业务单元分离, 由 RESTful 协议管理。课程目标是详细介绍微服务的方式开发应用。 少谈为什么, 专注怎么做。 微服务很难。 它有大量的挑战和问题很难解决。 开始拆分大型应用前记住这一点。利关注隔离服务清晰的分离使开发更专注他们的特长领域,比如语言,框架,依赖, 工具和构建管道。例如, 一个前端 JavaScript 工程师可开发面向客户的视图,不需要理解后端 API 的代码实现。 可自由选择语言和框架,只需要通过 AJAX 请求来消费 RESTful API来与后端通信。换句话说, 因为通过 APIs 通信开发者可以将一个服务看作一个黑箱。实际的实现和复杂被隐藏。也就是说, 这是一个好注意来创建一些组织标准来确保每个团队可以一起发挥作用。例如代码质量,风格检查,代码检查, API 设计。清晰的分离意味着错误可最大限度的定位到开发者所工作的服务。使你可以安排初级开发到较不严格的服务即使他挂掉了对应服务, 剩余整体应用不受影响。可独立部署意味着更少的耦合使得规模化更容易。 也有助于消除一个团队堆另一个团队依赖完成的等待。更小的代码库不需要理解整个系统,小代码库更容易理解。只要有固定的必要 API 设计, 微服务栈的应用可以更快部署,更容易测试, 重构, 和规模化。服务保持一致的开发标准很重要,开发可以更容易从一个服务到另外一个。加速反馈回路在微服务中,开发通常掌握应用从立项到交付的整个生命周期。使团队不需要绑定特定的技术栈–像客户端UI,服务端等–团队可以更聚焦产品。自己为交付应用到用户负责。 因此, 应用如何在真实环境运行更清晰可见。这加速反馈循环,更容易修复 bug 和迭代。弊端设计复杂决定拆分应用为微服务并不是个轻松的任务。 通常在整个大项目更容易重构成独立模块。一旦拆分一个服务就无法回头。网络复杂通常一个大型应用所有事情发生于同一线程。 不需要每次调用其它服务。只要你把应用拆分成微服务, 你会发现你将不得不进行网络调用, 之前你只需要调用某一函数。这可能导致问题,特别是多个应用需要和另外一个通信, 导致乒乓效应。 不得不说明服务全面下降的原因。基础设施多服务将代码库复杂度转移到了平台和基础设施。 这可能很昂贵。另外你不得不使用正确的工具和适当的人力资源管理。数据持久化多数应用有状态曾, 像数据库和任务队列。 微服务站也需要记录服务部署地点和实例数量。 当一个实际服务实例启动,可合适的分配路由流量。 这通常称为 service discovery.由于我们处理容器,我们需要特别关注如何处理状态容器,因为他们不应下降。隔离特定服务的状态使得它分享和复制机器困难。你通常不得不处理不同来源且频繁调整的情况,这归结为设计原因。集成测试通常, 使用微服务架构开发应用, 你无法完整的测试所有服务知道你部署到一个预发或生产服务器。这获得反馈的时间太长。 幸运的是, Docker 能通过更容易的连接本地独立小应用服务来帮助加速这一个进程。日志,监控, 和调试也更难了。

April 8, 2019 · 1 min · jiezi

microservices-with-docker-flask-and-react 简介

在第一部分, 你学到如何使用 Docker 来创建一个基于python, postgres, 和 flask web 框架的 RESTful API 可重用开发环境. 在 app 启动本地运行后, 学习如何在 Amazon EC2 实例上部署。前置条件这不是一个入门课程。 此课程为至少有六个月网站开发经验的高级入门者设置。在开始之前, 你需要熟悉以下主题。 点击链接查看更多内容。主题资源Docker Docker Compose Docker Machine Flask 目标这部分结束,具备以下能力。。。使用 Flask 和 python 开发 RESTful API实践测试驱动开发本地使用 Docker 配置运行服务利用卷挂载代码到容器在 Docker 容器中进行单元和集成测试不同容器内的服务通信在 Docker 容器中使用 python 和 Flask在 Amazon EC2 实例中安装 Flask, Nginx, 和 Gunicorn使用 Docker Machine 部署到 EC2App最终 app:图例略彻底检查以下接口。。。接口HTTP 方法CRUD 方法结果/usersGETREADget all users/users/:idGETREADget single user/usersPOSTCREATEadd a user/users/pingGETREADsanity check本质上, app 运行在三个容器中– Flask, Postgres, Nginx.第一部分结束时, 你将完成部署上面的 app. 再接下来的部分我们添加权限和其他服务。第一部分完整代码: 依赖第一部分依赖Python v3.7.2Flask v1.0.2Docker v18.09.0Docker Compose v1.23.2Docker Machine v0.16.0Docker Compose file v3.7Postgres v11.1Flask-SQLAlchemy v2.3.2psycopg2 v2.7.6.1Flask-Testing v0.7.1Gunicorn v19.9.0Nginx v1.15.8Bulma 0.7.2耗时一章需要几个小时到一整天。 空余大块时间来完成一章, 特别是5,6,7. 这些较难的部分。 ...

April 8, 2019 · 1 min · jiezi

K8S 生态周报| 2019.04.01~2019.04.07

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。Kubernetes client-go v11.0.0 正式发布这是最后一个使用 dep 作为依赖管理的版本,后续版本将转向使用 go modules.Kubernetes 生态中的相关项目大多都已转向或正在转向使用 go modules 了,这也是一个技术风向,理性选择。Releasecontainerd 1.2.6 正式发布这是 containerd 1.2 的第 6 个 patch 版本,主要更新:在默认的 seccomp profile 白名单增加了 io_pgetevents 和 statx 这两个系统调用;修复了在 1.2.5 中自定义 cgroup path 无法工作的 bug;更新 CNI 插件到 v0.7.5 以修复 CVE-2019-9946;更新 runc 版本,修复在无 SELinux 系统下的失败情况;当然还有一些其他的改进和修复,比如修复了 pod 的 UTS namespace 等,建议阅读 ReleaseNote。Docker CE 19.03.0-beta1 版本发布这是 Docker CE 修改发布周期后,第二个发布的版本,上个版本是 Docker CE 18.09 。从发布周期来看,由原先的季度发布改成半年发布,也意味着 Docker 的日渐成熟。正式版估计会在 5 月发布,从 beta 版中能看到一些主要更新:API 更新至 v1.40;允许以非 root 用户运行 dockerd (Rootless mode),这将更有利于容器安全(这也是我最期待的一个特性);移除 v1 manifest 支持;移除 AuFS 存储驱动支持,会有提示信息(当前是废弃,还未完全移除,在上个版本中 devicemapper 也已被标记为废弃);实验性的对 compose 和 Kubernetes 提供一些额外支持,比如 x-pull-secret 和 x-pull-policy;实验性的对 Windows 和 LCOW 提供一些支持:比如提供对 cpu 和 内存的限制;除此之外,在 builder 和 API 方面也都有一些修复和改进,建议阅读 ReleaseNote。推荐阅读: Linkerd v2 从产品中吸取的教训Linkerd v2 使用 Go 和 Rust 进行了重写,这篇文章是在 Linkerd v2 发布 6 个月之后写的,该团队认为使用 Go 和 Rust 重写是非常值得的,并且也已经在生产中得到了验证。文章内容不错,推荐阅读。文章地址 Linkerd v2: How Lessons from Production Adoption Resulted in a Rewrite of the Service Mesh。可以通过下面二维码订阅我的文章公众号【MoeLove】 ...

April 8, 2019 · 1 min · jiezi

容器环境下的持续集成最佳实践:构建基于 Drone + GitFlow + K8s 的云原生语义化 CI 工作流

云原生 (Cloud Native) 是伴随的容器技术发展出现的的一个词,最早出自 Pivotal 公司(即开发了 Spring 的公司)的一本技术小册子 Migrating to Cloud-Native Application Architectures, 其中定义了云原生应用应当具备的一些特质,如无状态、可持续交付、微服务化等。随后云原生概念被广为引用,并围绕这一概念由数家大厂牵头,成立了 CNCF 基金会来推进云原生相关技术的发展,主要投资并孵化云原生生态内的若干项目,包括了如 Kubernetes / etcd / CoreDNS 等耳熟能详的重要项目。而这张大大的云原生版图仍然在不断的扩展和完善。从个人理解来说,传统的应用由于年代久远,更多会考虑单机部署、进程间通信等典型的“单机问题”,虽然也能工作在容器下,但由于历史包袱等原因,架构上已经很难做出大的调整。而“云原生”的应用大都是从一开始就为容器而准备,很少考虑在单机环境下使用,有些甚至无法脱离容器环境工作;考虑的场景少,从而更轻量,迭代更快。比如 etcd 之于 zookeeper , traefik 之于 nginx 等,相信只要在容器环境下实现一次同样的功能,就能强烈的体会到云原生应用所特有的便捷之处。在 CNCF 的版图下,持续集成与持续交付(Continuous Integration & Delivery)板块一直缺少一个钦定的主角,虽然也不乏 Travis CI、GitLab、Jenkins 这样的知名项目,但最能给人云原生应用感觉的,应该还是 Drone 这个项目,本文将围绕 Drone 结合 GitFlow 及 Kubernetes 介绍一些容器环境下持续集成、持续发布 (CI/CD) 方面的实践经验。主流 CI/CD 应用对比之前我也介绍过基于 Travis CI 的一些持续集成实践。后来经过一些比较和调研,最终选择了 Drone 作为主力 CI 工具。截止本文,团队已经使用 Drone 有 2 年多的时间,从 v0.6 一路用到现在即将发布的 v1.0,虽然也踩了不少坑,但总的来说 Drone 还是可以满足大部分需求,并以不错的势头在完善和发展的。下面这张表总结了主流的几个 CI/CD 应用的特点项目名称开发语言配置语言公有云服务私有部署备注Travis CIRubyYAML有不支持公共项目免费,私有项目 $69/单进程, $129/2 进程CircleCIClojureYAML有不支持单进程免费,$50/加 1 进程Gitlab CIRubyYAML有支持绑定 Gitlab 代码管理JenkinsJavaGroovy无支持 DroneGoYAML有支持Cloud 版本不支持私有项目,自建版本无此限制Travis CI 和 CircleCI 是目前占有率最高的两个公有云 CI,易用性上相差无几,只是收费方式有差异。由于不支持私有部署,如果并行的任务量一大,按进程收费其实并不划算;而且由于服务器位置的原因,如果推送镜像到国内,速度很不理想。Gitlab CI 虽然好用,但和 Gitlab 是深度绑定的,我们的代码托管在 Github,整体迁移代码库的成本太大,放弃。Jenkins 作为老牌劲旅,也是目前市场占有率最高的 CI,几乎可以覆盖所有 CI 的使用场景,由于使用 Java 编写,配置文件使用 Groovy 语法,非常适合 Java 为主语言的团队。Jenkins 显然是可以满足我们需要的,只是团队并非 Java 为主,又已经习惯了使用 YAML 书写 CI 配置,抱着尝鲜的心态,将 Jenkins 作为了保底的选择。综上,最终选择 Drone 的结论也就不难得出了,Drone 即开源,又可以私有化部署,同时作为云原生应用,官方提供了针对 Docker、Docker Swarm、K8s 等多种容器场景下的部署方案,针对不同容器场景还有特别优化,比如在 Docker Swarm 下 Drone 是以 agent 方式运行 CI 任务的,而在 K8s 下则通过创建 K8s Job 来实现,显然充分利用了容器的优势所在,这也是 Drone 优于其他 CI 应用之处。个人还觉得 Drone 的语法是所有 CI 中最容易理解和掌握的,由于 Drone 每一个步骤都是运行一个 Docker 容器,本地模拟或调试也非常容易。一句话概况 Drone,可以将其看做是可以支持私有化部署的开源版 CircleCI,并且目前仍然没有看到有其他主打这个定位的 CI 工具,因此个人认为 Drone 是 CI/CD 方面云原生应用头把交椅的有力竞争者。容器环境下一次规范的发布应该包含哪些内容技术选型完成后,我想首先演示一下最终的成果,希望能直观的体现出 CI 对自动化效率起到的提升,不过这就涉及到一个问题:在容器环境下,一次发布应该包含哪些内容,其中有哪些部分是可以被 CI 自动化完成的。这个问题虽然每家公司各不相同,不过按经验来说,容器环境下一次版本发布通常包含这样一个 Checklist:[ ] 代码的下载构建及编译[ ] 运行单元测试,生成单元测试报告及覆盖率报告等[ ] 在测试环境对当前版本进行测试[ ] 为待发布的代码打上版本号[ ] 编写 ChangeLog 说明当前版本所涉及的修改[ ] 构建 Docker 镜像[ ] 将 Docker 镜像推送到镜像仓库[ ] 在预发布环境测试当前版本[ ] 正式发布到生产环境看上去很繁琐对吗,如果每次发布都需要人工去处理上述的所有内容,不仅容易出错,而且也无法应对 DevOps 时代一天至少数次的发布频率,那么下面就来使用 CI 来解决所有问题吧。CI 流程演示为了对 CI 流程有最直观的认识,我创建了一个精简版的 Github 项目 AlloVince/drone-ci-demo 来演示完整的流程,同时项目对应的 CI 地址是 cloud.drone.io/AlloVince/drone-ci-demo ,项目自动构建的 Docker 镜像会推送到 docker registry 的 allovince/drone-ci-demo,。为了方便说明,假设这个项目的核心文件只有 index.html 一个静态页面。单人开发模式目前这个项目背后的 CI 都已经配置部署好,假设我是这个项目的唯一开发人员,如何开发一个新功能并发布新版本呢?Clone 项目到本地, 修改项目代码, 如将 Hello World 改为 Hello World V2。git add .,然后书写符合约定的 Commit 并提交代码, git commit -m “feature: hello world v2”推送代码到代码库git push,等待数分钟后,开发人员会看到单元测试结果,Github 仓库会产生一次新版本的 release,release 内容为当前版本的 ChangeLog, 同时线上已经完成了新功能的发布。虽然在开发者看来,一次发布简单到只需 3 个指令,但背后经过了如下的若干次交互,这是一次发布实际产生交互的时序图,具体每个环节如何工作将在后文中详细说明。多人开发模式一个项目一般不止一个开发人员,比如我是新加入这个项目的成员,在这个 Demo 中应该如何上线新功能呢?同样非常简单:Clone 项目到本地,创建一个分支来完成新功能的开发, git checkout -b feature/hello-world-v3。在这个分支修改一些代码,比如将Hello World V2修改为Hello World V3git add .,书写符合规范的 Commit 并提交代码, git commit -m “feature: hello world v3”将代码推送到代码库的对应分支, git push origin feature/hello-world如果功能已经开发完毕,可以向 Master 分支发起一个 Pull Request,并让项目的负责人 Code ReviewReview 通过后,项目负责人将分支合并入主干,Github 仓库会产生一次新版本的 release,同时线上已经完成了新功能的发布。这个流程相比单人开发来多了 2 个环节,很适用于小团队合作,不仅强制加入了 Code Review 把控代码质量,同时也避免新人的不规范行为对发布带来影响。实际项目中,可以在 Github 的设置界面对 master 分支设置写入保护,这样就从根本上杜绝了误操作的可能。当然如果团队中都是熟手,就无需如此谨慎,每个人都可以负责 PR 的合并,从而进一步提升效率。GitFlow 开发模式在更大的项目中,参与的角色更多,一般会有开发、测试、运维几种角色的划分;还会划分出开发环境、测试环境、预发布环境、生产环境等用于代码的验证和测试;同时还会有多个功能会在同一时间并行开发。可想而知 CI 的流程也会进一步复杂。能比较好应对这种复杂性的,首选 GitFlow 工作流, 即通过并行两个长期分支的方式规范代码的提交。而如果使用了 Github,由于有非常好用的 Pull Request 功能,可以将 GitFlow 进行一定程度的简化,最终有这样的工作流:以 dev 为主开发分支,master 为发布分支开发人员始终从 dev 创建自己的分支,如 feature-afeature-a 开发完毕后创建 PR 到 dev 分支,并进行 code reviewreview 后 feature-a 的新功能被合并入 dev,如有多个并行功能亦然待当前开发周期内所有功能都合并入 dev 后,从 dev 创建 PR 到 masterdev 合并入 master,并创建一个新的 release上述是从 Git 分支角度看代码仓库发生的变化,实际在开发人员视角里,工作流程是怎样的呢。假设我是项目的一名开发人员,今天开始一期新功能的开发:Clone 项目到本地,git checkout dev。从 dev 创建一个分支来完成新功能的开发, git checkout -b feature/feature-a。在这个分支修改一些代码,比如将Hello World V3修改为Hello World Feature Agit add .,书写符合规范的 Commit 并提交代码, git commit -m “feature: hello world feature A"将代码推送到代码库的对应分支, git push origin feature/feature-a:feature/feature-a由于分支是以feature/命名的,因此 CI 会运行单元测试,并自动构建一个当前分支的镜像,发布到测试环境,并自动配置一个当前分支的域名如 test-featue-a.avnpc.com联系产品及测试同学在测试环境验证并完善新功能功能通过验收后发起 PR 到 dev 分支,由 Leader 进行 code reviewCode Review 通过后,Leader 合并当前 PR,此时 CI 会运行单元测试,构建镜像,并发布到测试环境此时 dev 分支有可能已经积累了若干个功能,可以访问测试环境对应 dev 分支的域名,如 test.avnpc.com,进行集成测试。集成测试完成后,由运维同学从 Dev 发起一个 PR 到 Master 分支,此时会 CI 会运行单元测试,构建镜像,并发布到预发布环境测试人员在预发布环境下再次验证功能,团队做上线前的其他准备工作运维同学合并 PR,CI 将为本次发布的代码及镜像自动打上版本号并书写 ChangeLog,同时发布到生产环境。由此就完成了上文中 Checklist 所需的所有工作。虽然描述起来看似冗长,但不难发现实际作为开发人员,并没有任何复杂的操作,流程化的部分全部由 CI 完成,开发人员只需要关注自己的核心任务:按照工作流规范,写好代码,写好 Commit,提交代码即可。接下来将介绍这个以 CI 为核心的工作流,是如何一步步搭建的。Step by Step 构建 CI 工作流Step.0: 基于 K8s 部署 Drone v1.0.0以 Github 为例,截止本文完成时间(2019 年 3 月 28 日), Drone 刚刚发布了第一个正式版本 v1.0.0。官方文档已经提供了分别基于 Docker、K8s 的 Drone 部署说明,不过比较简略,因此这里给出一个相对完整的配置文件。首先需要在 Github 创建一个 Auth App,用于 repo 的访问授权。应用创建好之后,会得到 Client ID 和 Client Secret 。同时 Authorization callback URL 应填写 Drone 服务对应域名下的 /login,如https://ci.avnpc.com/loginDrone 支持 SQLite、MySQL、Postgres、S3 等多种后端存储,主要用于记录 build logs 等文本信息,这些信息并不是特别重要,且我们的 CI 有可能做迁移,因此个人更推荐使用 SQLite。而在 K8s 环境下,SQLite 更适合用挂载 NAS 的方式供节点使用,因此首先将存储的部分独立为文件drone-pvc.yml,可以根据实际情况配置 nfs.path 和 nfs.serverkubectl apply -f drone-pvc.yamlDrone 的配置主要涉及两个镜像:drone/kubernetes-secrets 加密数据服务,用于读取 K8s 的 secretsdrone/drone:1.0.0-rc.6 就是 Drone 的 server 端,由于在 K8s 下 Drone 利用了 Job 机制,因此不需要部署 agent。这部分配置较长,可以直接参考示例 drone.yaml主要涉及到的配置项包括:drone/kubernetes-secrets 镜像中SECRET_KEY: 数据加密传输所用的 key,可以使用 openssl rand -hex 16 生成一个drone/drone镜像中DRONE_KUBERNETES_ENABLED: 开启 K8s 模式DRONE_KUBERNETES_NAMESPACE: Drone 所使用的 Namespace, 这里使用 defaultDRONE_GITHUB_SERVER: Github 服务器地址,一般为 https://github.comDRONE_GITHUB_CLIENT_ID: 上文创建 Github Auth App 得到的 Client IDDRONE_GITHUB_CLIENT_SECRET: 上文创建 Github Auth App 得到的 Client SecretDRONE_SERVER_HOST: Drone 服务所使用的域名DRONE_SERVER_PROTO: http 或 httpsDRONE_DATABASE_DRIVER: Drone 使用的数据库类型,这里为 sqlite3DRONE_DATABASE_DATASOURCE: 这里为 SQLite 数据库的存放路径DRONE_SECRET_SECRET: 对应上文的 SECRET_KEYDRONE_SECRET_ENDPOINT: 加密数据服务的地址,这里通过 k8s service 暴露,无需修改最后部署即可kubectl apply -f drone.yaml部署后首次登录 Drone 就会跳转到 Github Auth App 进行授权,授权完毕后可以看到所有能读写的 Repo,选择需要开启 CI 的 Repo,点击 ACTIVATE 即可。 如果开启成功,在 Github Repo 的 Settings > Webhooks 下可以看到 Drone 的回调地址。Step.1: Hello World for Drone在正式开始搭建工作流之前,首先可以测试一下 Drone 是否可用。Drone 默认的配置文件是 .drone.yml, 在需要 CI 的 repo 根目录下创建.drone.yml, 内容如下,提交并git push到代码仓库即可触发 Drone 执行 CI。kind: pipeline name: deploy steps: - name: hello-world image: docker commands: - echo “hello world"Drone v1 的语法主要参考的 K8s 的语法,非常直观,无需阅读文档也可以知道,我们首先定义了一个管道 (pipeline),管道由若干步骤 (step) 组成,Drone 的每个步骤是都基于容器实现的,因此 Step 的语法就回到了我们熟悉的 Docker,一个 Step 会拉取 image 定义的镜像,然后运行该镜像,并顺序执行 commands 定义的指令。 在上例中,Drone 首先 clone git repo 代码到本地,然后根据 .drone.yml 所定义的,拉取 Docker 的官方镜像,然后运行该进行并挂载 git repo 的代码到 /drone/src 目录。在 Drone 的界面中,也可以清楚的看到这一过程。本阶段对应代码部分: https://github.com/AlloVince/...Drone 构建记录: https://cloud.drone.io/AlloVi...Docker 镜像: 无Step.2: 单人工作流,自动化单元测试与 Docker 镜像构建有了 Hello World 的基础,接下来我们尝试将这个工作流进行扩充。为了方便说明,这里假设项目语言为 js,项目内新增了test/index.js文件用于模拟单元测试,一般在 CI 中,只要程序的返回值为 0,即代表运行成功。这个文件中我们仅仅输出一行 Log Unit test passed用于模拟单元测试通过。 我们希望将代码打包成 Docker 镜像,根目录下增加了 Dockerfile 文件,这里直接使用 Nginx 的官方镜像,构建过程只有 1 行COPY index.html /usr/share/nginx/html/, 这样镜像运行后可以通过 http 请求看到index.html的内容。至此我们可以将工作流改进为:当 master 分支接收到 push 后,运行单元测试当 github 发布一次 release, 构建 Docker 镜像,并推送到镜像仓库对应的 Drone 配置文件如下kind: pipeline name: deploy steps: - name: unit-test image: node:10 commands: - node test/index.js when: branch: master event: push - name: build-image image: plugins/docker settings: repo: allovince/drone-ci-demo username: allovince password: from_secret: DOCKER_PASSWORD auto_tag: true when: event: tag虽然比 Hello World 复杂了一些,但是可读性仍然很好,配置文件中出现了几个新概念:Step 运行条件, 即 when 部分,上例中展示了当代码分支为 master,且收到一个 push;以及当代码被标记 tag 这两种情况。Drone 还支持 repo、运行结果等很多其他条件,可以参考 Drone Conditions 文档。Plugin 插件,上例中用于构建和推送镜像的是 plugins/docker 这个 Plugin, 一个 Plugin 本质上仍然是一个 Docker 镜像,只是按照 Drone 的规范接受特定的输入,并完成特定的操作。所以完全可以将 Plugin 看做一个无法更改 command 的 Docker 镜像。Docker 这个 Plugin 由 Drone 官方提供,用于 Docker 镜像的构建和推送,具体的用法可以查看Docker 插件的文档 。例子中演示的是将镜像推送到私有仓库,如果不做特殊配置,镜像将被推送到 Docker 的官方仓库。 此外 Docker 插件还有一个很方便的功能,如果设置 auto_tag: true,将根据代码的版本号自动规划 Docker 镜像的标签,如代码版本为1.0.0,将为 Docker 镜像打三个标签 1, 1.0, 1.0.0。如果代码版本号不能被解析,则镜像标签为 latest。目前 Drone 的插件已经有很多,可以覆盖主流的云服务商和常见的工作流,并且自己制作插件的成本也不高。Secret 加密数据,镜像仓库的用户名和密码都属于敏感信息,因此可以使用 from_secret 获取加密数据。一条加密数据就是一个 key / value 对,如上例中的 DOCKER_PASSWORD 就是我们自己定义的加密数据 key。即便加密数据在 log 中被打印,UI 也只能看到 。加密数据的 value 需要提前保存好,保存的方式有 3 种:通过 Drone UI 界面中, repo -> Settings -> Secrets 添加,所添加的加密数据将保存在 Drone 的数据库中,仅能在当前 repo 中使用。通过Drone cli 加密后保存在 .drone.yml文件中, 使用范围仅限 yaml 文件内通过 K8s 保存为K8s Secret,称为 External Secrets,所有的 repo 都可以共享。如果是团队使用的话,这种保存方式显然是最方便的,但也要注意安全问题,因此 External Secrets 还支持 repo 级别的权限管理, 可以只让有当前 repo 写入权限的人才能使用对应 secret。这个阶段对应代码仓库: https://github.com/AlloVince/...push 时触发的 Drone CI: https://cloud.drone.io/AlloVi...release 时触发的 Drone CI: https://cloud.drone.io/AlloVi...release 后 CI 构建的 Docker 镜像: allovince/drone-ci-demo:latestStep.3: GitFlow 多分支团队工作流上面的工作流已经基本可以应付单人的开发了,而在团队开发时,这个工作流还需要一些扩展。不需要引入 Drone 的新功能,只需要在上文基础上根据分支做一点调整即可。首先保证单元测试位于 steps 的第一位,并且限定团队工作的分支,在 push 和 pull_request 时,都能触发单元测试。- name: unit-test image: node:10 commands: - node test/index.js when: branch: include: - feature/ - master - dev event: include: - push - pull_request然后根据 Gitflow 的流程对于不同的分支构建 Docker 镜像并打上特定标签,以 feature 分支为例,下面的配置约定了当分支名满足 feature/,并收到 push 时,会构建 Docker 镜像并打标签,标签名称为当前分支名去掉 feature/。如分支 feature/readme, 对应 docker 镜像为 allovince/drone-ci-demo:readme,考虑到 feature 分支一般都出于开发阶段,因此新的镜像会覆盖旧的。配置如下- name: build-branch-image image: plugins/docker settings: repo: allovince/drone-ci-demo username: allovince password: from_secret: DOCKER_PASSWORD tag: - ${DRONE_BRANCH##feature/} when: branch: feature/ event: push镜像的 Tag 处不再使用自动方式,其中DRONE_BRANCH是 Drone 的内置环境变量 (Environment),对应当前的分支名。##feature/是执行了一个字符串的替换操作 (Substitution)。更多的环境变量和字符串操作都可以在文档中找到。以此类推,可以查看这个阶段的完整 .drone.yml ,此时我们的工作流示例如下:团队成员从 dev 分支 checkout 自己的分支 feature/readme向feature/readme提交代码并 push, CI 运行单元测试,构建镜像allovince/drone-ci-demo:readme功能开发完成后,团队成员向 dev 分支 发起 pull request , CI 运行单元测试团队其他成员 merge pull request, CI 运行单元测试,构建镜像allovince/drone-ci-demo:test运维人员从 dev 向 master 发起 pull request,CI 运行单元测试,并构建镜像allovince/drone-ci-demo:latest运维人员 merge pull request, 并 release 新版本 pre-0.0.2, CI 构建镜像allovince/drone-ci-demo:pre-0.0.2可能细心的同学会发现 dev -> master 的 pull request 时,构建镜像失败了,这是由于 Drone 出于安全考虑限制了在 pull request 时默认无法读取加密数据,因此无法得到 Docker Registry 密码。如果是私有部署的话,可以在 Repo Settings 中勾选Allow Pull Requests,此处就可以构建成功。Step.4: 语义化发布上面基本完成了一个支持团队协作的半自动 CI 工作流,如果不是特别苛刻的话,完全可以用上面的工作流开始干活了。不过基于这个工作流工作一段时间,会发现仍然存在痛点,那就是每次发布都要想一个版本号,写 ChangeLog,并且人工去 release。标记版本号涉及到上线后的回滚,追溯等一系列问题,应该是一项严肃的工作,其实如何标记早已有比较好的方案,即语义化版本。在这个方案中,版本号一共有 3 位,形如 1.0.0,分别代表:主版本号:当你做了不兼容的 API 修改,次版本号:当你做了向下兼容的功能性新增,修订号:当你做了向下兼容的问题修正。虽然有了这个指导意见,但并没有很方便的解决实际问题,每次发布要搞清楚代码的修改到底是不是向下兼容的,有哪些新的功能等,仍然要花费很多时间。而语义化发布 (Semantic Release) 就能很好的解决这些问题。语义化发布的原理很简单,就是让每一次 Commit 所附带的 Message 格式遵守一定规范,保证每次提交格式一致且都是可以被解析的,那么进行 Release 时,只要统计一下距离上次 Release 所有的提交,就分析出本次提交做了何种程度的改动,并可以自动生成版本号、自动生成 ChangeLog 等。语义化发布中,Commit 所遵守的规范称为约定式提交 (Conventional Commits)。比如 node.js、 Angular、Electron 等知名项目都在使用这套规范。语义化发布首先将 Commit 进行分类,常用的分类 (Type) 有:feat: 新功能fix: BUG 修复docs: 文档变更style: 文字格式修改refactor: 代码重构perf: 性能改进test: 测试代码chore: 工具自动生成每个 Commit 可以对应一个作用域(Scope),在一个项目中作用域一般可以指不同的模块。当 Commit 内容较多时,可以追加正文和脚注,如果正文起始为BREAKING CHANGE,代表这是一个破坏性变更。以下都是符合规范的 Commit:feat: 增加重置密码功能fix(邮件模块): 修复邮件发送延迟BUGfeat(API): API重构BREAKING CHANGE: API v3上线,API v1停止支持有了这些规范的 Commit,版本号如何变化就很容易确定了,目前语义化发布默认的规则如下Commit版本号变更BREAKING CHANGE主版本号feat次版本号fix / perf修订号因此在 CI 部署 semantic-release 之后,作为开发人员只需要按照规范书写 Commit 即可,其他的都由 CI 完成。具体如何将语义化发布加入 CI 流程中呢, semantic-release 是 js 实现的,如果是 js 的项目,可以直接在package.json中增加配置项,而对于任意语言的项目,推荐像 Demo 中一样,在根目录下增加 配置文件release.config.js。这个配置目的是为了禁用默认开启的 npm 发布机制,可以直接套用。semantic-release 要执行 Github release,因此我们需要在 CI 中配置自己的 Personal access tokens 让 CI 有 Github repo 的读写权限, 可以通过 Github 点击自己头像 -> Settings -> Developer settings -> Personal access tokens -> Generate new token 生成一个 Token。 然后在 Drone 的 repo 设置界面新增一个 Secret, key 为 GITHUB_TOKEN, value 填入刚生成的 Token。最后在 .drone.yml 中增加这样一段就可以了。- name: semantic-release image: gtramontina/semantic-release:15.13.3 environment: GITHUB_TOKEN: from_secret: GITHUB_TOKEN entrypoint: - semantic-release when: branch: master event: push来再次模拟一下流程,feature 分支部分与上文相同从 dev 向 master 发起 pull request,CI 运行单元测试,并构建镜像allovince/drone-ci-demo:latestmerge pull request,CI 会执行单元测试并运行 semantic-release , 运行成功的话能看到 Github 新增 release v1.0.0Github release 再次触发CI 构建生产环境用 Docker 镜像allovince/drone-ci-demo:1.0.0最终我们能得到这样一个赏心悦目的 releaseStep.5: Kubernetes 自动发布Docker 镜像推送到仓库后,我们还剩最后一步就可以完成全自动发布的闭环,即通知 Kubernetes 将镜像发布到生产环境。这一步实现比较灵活,因为很多云服务商在容器服务都会提供 Trigger 机制,一般是提供一个 URL,只要请求这个 URL 就可以触发容器服务的发布。Demo 中我们使用更为通用的方法,就是将 kubectl 打包为容器,以客户端调用 K8s 集群 Master 节点 API ( kube-apiserver ) 的形式完成发布。假设我们在生产环境下 drone-ci-demo 项目的 K8s 发布文件如下— apiVersion: extensions/v1beta1 kind: Deployment metadata: name: ci-demo-deployment namespace: default spec: replicas: 1 template: spec: containers: - image: allovince/drone-ci-demo name: ci-demo restartPolicy: Always对应 .drone.yml 中增加 step 如下。这里使用的插件是honestbee/drone-kubernetes, 插件中kubectl 连接 API 使用的是证书+ Token 的方式鉴权,因此需要先获得证书及 Token, 已经授权的 Token 保存于 k8s secret,可以通过kubectl get secret [ your default secret name ] -o yaml | egrep ‘ca.crt:|token:‘获得并配置到 drone 中,注意插件要求 token 是明文的,需要 base64 解码一下:echo [ your token ] | base64 -d && echo ‘’- name: k8s-deploy image: quay.io/honestbee/drone-kubernetes settings: kubernetes_server: from_secret: KUBERNETES_SERVER kubernetes_cert: from_secret: KUBERNETES_CERT kubernetes_token: from_secret: KUBERNETES_TOKEN namespace: default deployment: ci-demo-deployment repo: allovince/drone-ci-demo container: ci-demo tag: - ${DRONE_TAG} when: event: tag在示例)中,可以看到在语义化发布之后 CI 会将新版本的 Docker 镜像自动发布到 K8s),这里为了演示仅打印了指令并未实际运行。相当于运行了如下的指令:kubectl -n default set image deployment/ci-demo-deployment ci-demo=allovince/drone-ci-demo:v1.0.2由于自动发布的环节势必要接触到生产服务器,需要格外注意安全问题,首推的方式当然是将 CI 和 K8s 集群放于同一内网中,同时可以使用 K8s 的 RBAC 权限控制,为自动发布单独创建一个用户),并删除不必要的权限。后话总结一下,本文展示了从 Hello World 到 单人单分支手动发布 到 团队多分支 GitFlow 工作流 到 团队多分支 semantic-release 语义化发布 到 通知 K8s 全自动发布,如何从零开始一步一步搭建 CI 将团队开发、测试、发布的流程全部自动化的过程,最终能让开发人员只需要认真提交代码就可以完成日常的所有 DevOps 工作。最终 Step 的完成品可以适配之前的所有 Step,如果不太在意实现细节的话,可以在此基础上稍作修改,直接使用。然而写好每一个 Commit 这个看似简单的要求,其实对于大多数团队来说并不容易做到,在实施过程中,经常会遇到团队成员不理解为什么要重视 Commit 规范,每个 Commit 都要深思熟虑是否过于吹毛求疵等等疑问。以 Commit 作为 CI 的核心,个人认为主要会带来以下几方面的影响:一个好的 Commit,代表着开发人员对当前改动之于整个系统的影响,有非常清楚的认识,代码的修改到底算 feat 还是 fix ,什么时候用 BREAKING CHANGE 等都是要仔细斟酌的,每个 Commit 都会在 ChangeLog 里“留底”,从而约束团队不随意提交未经思考的代码,提高代码质量一个好的 Commit 也代表开发人员有能力对所实现功能进行精细的划分,一个分支做的事情不宜过多,一个提交也应该专注于只解决一个问题,每次提交(至少是每次 push )都应该保持系统可构建、可运行、可测试,如果能坚持做到这些,对于合并代码时的冲突解决,以及集成测试都有很大帮助。由于每次发布能清楚的看到所有关联的 Commit 以及 Commit 的重要程度,那么线上事故的回滚也会非常轻松,回滚到哪个版本,回滚后哪些功能会受到影响,只要看 CI 自动生成的 Release 记录就一目了然。如果没有这些,回滚误伤到预期外的功能从而引发连锁反应的惨痛教训,可能很多运维都有过类似经历吧。因此 CI 自动化其实是锦上添花而非雪中送炭,如果团队原本就无视规范,Commit 全是空白或者没有任何意义的单词,分支管理混乱,发布困难,奢望引入一套自动化 CI 来能解决所有这些问题,无疑是不现实的。而只有原本就重视代码质量,有一定规范意识,再通过自动化 CI 来监督约束,团队在 CI 的帮助下代码质量提高,从而有机会进一步改进 CI 的效率,才能形成良性循环。愿天下不再有难发布的版本。References:云原生应用之路相关讨论可以在我的 Telegram Group 给我留言。 ...

April 8, 2019 · 7 min · jiezi

Docker镜像分层结构

docker镜像分层结构用过Dockerfile构建镜像的都知道Dockerfile执行完每一条指令都会创建一个新的镜像,最终的镜像由层层叠加而成。分层的好处最大的好处就是共享资源。当多个镜像从相同的base镜像构建而来,那么Docker host只需要在磁盘保存一份base镜像,同时内存中也只需要加载一份base镜像,就可以为所有的容器服务了。容器的修改并不会影响镜像当容器启动时,一个新的可写层被加载到镜像的顶层,这一层通常被成为“容器层”。对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。容器层是可写的,镜像层是只读的。添加文件时,新的文件添加到容器层。读取文件时,从上往下在各个镜像层查找,一旦找到就复制到容器层,然后读入内存。修改文件,从上往下查找,复制到容器层,然后修改之。删除文件,从上往下查找,找到后返回,记录删除操作。只有当需要修改时才赋值一份数据,这种特性被称为Copy-On-Write。容器层保存的是镜像层的变化,但不会对镜像本身进行任何修改。这也解释了镜像可以被多个容器共享。参考镜像分层结构

April 8, 2019 · 1 min · jiezi

URLOS应用开发入门案例——基于docker镜像制作一个可快速安装的gitbook应用

GitBook 是一个基于 Node.js 的命令行工具,可使用 Github/Git 和 Markdown 来制作精美的电子书,GitBook 并非关于 Git 的教程。GitBook支持输出多种文档格式:·静态站点:GitBook默认输出该种格式,生成的静态站点可直接托管搭载Github Pages服务上;·PDF:需要安装gitbook-pdf依赖;·eBook:需要安装ebook-convert;· 单HTML网页:支持将内容输出为单页的HTML,不过一般用在将电子书格式转换为PDF或eBook的中间过程;·JSON:一般用于电子书的调试或元数据提取。使用GitBook制作电子书,必备两个文件:README.md 和 SUMMARY.md。今天,我就教大家如何使用URLOS快速制作gitbook应用,该应用是基于docker镜像制作,可以随意运行在任何一个安装有URLOS的主机上。首先安装URLOS:curl -SO https://www.urlos.com/install && chmod 544 install && ./install安装完成后,地址栏输入 http://ip:9968 即可访问。将URLOS的模式改为开发模式,方法:修改配置文件/data/urlos/master-config/config.jsonc,将其中的pro修改为dev:我们本次只使用hub.dacoker.com上现成gitbook镜像,访问hub.dacoker.com,搜索“gitbook”,我们选择使用fellah/gitbook这个镜像:当前镜像最新版本为3.2.1我们将直接使用这个镜像完整路径:fellah/gitbook:3.2.1回到我们的URLOS主控界面,在左侧菜单中打开镜像 > 镜像管理:点击列表左上角的添加按钮,进入添加镜像界面,镜像名称和镜像地址填入“fellah/gitbook:3.2.1”:点击提交!然后打开左侧菜单“应用 > 应用管理”,进入应用管理列表:在列表的右上角有个搜索框,输入“nginx”搜索,找到静态网站这个应用,点更多按钮,选择“复制应用”:进入编辑界面后,将需要修改的地方适当修改一下,比如应用名称,版本,应用别名,镜像等:选项开关设置如下图:开启反向代理:共享到应用市场:拓展设置中的插件选择静态网站环境,服务表单中只保留上传下载:在脚本设置中,按如下内容填写即可:安装脚本:test -d /data/www || mkdir -p /data/wwwtest -d /run/nginx || mkdir -p /run/nginxchmod -R 777 /data/www/set -ex \ && sed -i ’s@security.debian.org@mirrors.aliyun.com@’ /etc/apt/sources.listset -ex \ && sed -i ’s@deb.debian.org@mirrors.aliyun.com@’ /etc/apt/sources.listapt-get updateapt-get install -y nginx启动脚本:nginxcd /data/wwwgitbook initgitbook serve如上内容设置完成之后,点击提交按钮即可!好了~我们的gitbook应用就制作完成!安装部署试试看吧!点击更多,选择创建服务:输入基础信息和域名,提交。打开域名访问看看,访问成即我们制作的应用没有问题,这个应用我们可以自用,也可以导出给他人使用!

April 8, 2019 · 1 min · jiezi

3分钟快速入门URLOS应用开发

教你三分钟快速制作URLOS应用URLOS开发功能正式对外开放了,很多小伙伴们已经跃跃欲试,想尝试着去制作自己的应用,这里我教大家快速制作应用的方法,那就是通过复制应用功能,三分钟就能制作出来一个可安装运行的应用。复制应用对制作应用效率的提升主要体现在:它可将一个应用复制后,修改变成一个新的应用。就好比程序员常说的“代码复用”,研发中通过复用模块可以少撸很多行代码,从而提高研发效率。在开始教程之前,请小伙伴们自行安装URLOS,安装命令如下:curl -SO https://www.urlos.com/install && chmod 544 install && ./install安装完成之后,还需要修改将/data/urlos/master-config/config.jsonc文件的envType的值设置为dev(开发环境)vim /data/urlos/master-config/config.jsonc修改之后,在浏览器地址栏输入http://主机IP:9968,登录URLOS,查看开发模式是否生效:下面通过简单案例来演示复制应用功能的用法:打开左侧菜单应用 > 应用管理,在应用列表搜索php关键词,我们选择复制ID为41的PHP-5.6-网站环境,点击右侧的更多按钮:在弹出菜单中选择复制应用:进入复制编辑界面,可以看到源应用的相关配置信息都被完完整整的复制过来了,我们只需要根据实际情况进行修改即可,比如:改一个新的应用名称,换一个新的镜像,增加一个安装脚本等等。这里我只将应用名称修改为hello-world,在安装脚本中增加3条内容:test -d /data/www || mkdir -p /data/wwwcd /data/wwwecho “hello world” > index.php点击提交按钮,就这样一个新应用就制作出来了!来检查一下这个新应用是否可以顺利安装,点击应用列表右边的更多按钮,选择创建服务,待应用部署完成,在浏览器中输入域名,看一下是否显示“hello world”字样:看到上图内容,说明我们制作的新应用没有问题。以上演示主要是想为小伙伴们打开思路,我们在制作应用时可以通过一些技巧来“偷偷懒”,比如,如果我们制作了一个全新的镜像后,依然可以通过复制应用的方式提高制作效率,只需要在复制之后,选择新镜像,再稍微修改一下脚本或模板或变量即可,很多配置是可以复用的。

April 8, 2019 · 1 min · jiezi

使用 docker + devpi 搭建本地 pypi 源

前一段时间开发需要经常使用 pip 下载,虽然把 pip 源改成了国内源,但我对速度还是不满意,更为重要的是集成测试环境是离线的,要在集成测试环境开发显然需要搭建自己的本地 pip 源。在使用 devpi 之前我曾使用过 pip2pi,但有个 bug 导致离线环境下的 tox 命令总是失败,所以最后采用 devpi 搭建 pip 源。这里使用 docker 部署,方便又快速,如果不小心弄崩了也只需要重新运行 docker 容器就好了。如果你的环境没有安装 docker 可以自行搜素安装方法,比如 docker 社区的文档 install docker。如果你是 Centos 用户,可以使用以下方法安装sudo yum updatesudo yum -y install dockersudo systemctl enable dockersudo systemctl start docker接下来使用使用 docker 部署一个 Python 本地镜像源,我们可以使用 docker hub 上已有的镜像,我这里选择的是muccg/devpi 这个镜像# 设置 devpi 服务器管理员密码DEVPI_PASSWORD = 123mkdir -p /src/docker/devpimkdir /tmp/wheelhousedocker run -d –name devpi \ –publish 3141:3141 \ –volume /tmp/wheelhouse:/wheelhouse –volume /srv/docker/devpi:/data \ –env=DEVPI_PASSWORD=$DEVPI_PASSWORD \ –restart always \ muccg/docker-devpi接着先在本地下载好所需的wheel包,requirements.txt文件内容即为我们需要的 Python 库列表pip wheel –wheel-dir /tmp/wheelhouse -r requirements.txt如果从 pip 源下载的库已经是 wheel 包的话文件将会被直接放在 /tmp/wheelhouse 内,如果是tar 包,pip 会先 build 出 wheel 包,这可能需要一些时间。下载完成后 wheelhouse 内容类似于ll /tmp/wheelhousetotal 524K-rwxrwxrwx 1 rookie rookie 155K Apr 6 23:40 certifi-2019.3.9-py2.py3-none-any.whl-rwxrwxrwx 1 rookie rookie 131K Apr 6 23:40 chardet-3.0.4-py2.py3-none-any.whl-rwxrwxrwx 1 rookie rookie 58K Apr 6 23:40 idna-2.8-py2.py3-none-any.whl-rwxrwxrwx 1 rookie rookie 57K Apr 6 23:40 requests-2.21.0-py2.py3-none-any.whl-rwxrwxrwx 1 rookie rookie 116K Apr 6 23:40 urllib3-1.24.1-py2.py3-none-any.whl下载完成后如果本地环境安装了devpi客户端,可以直接上传 wheel 包,不过由于我们在创建容器时已经把 wheelhouse 文件夹挂载进去,也可以在在容器里直接操作# 进入容器docker exec -it -u root devpi bash# 登陆并上传devpi use http://<host_ip>:3141/root/public –set-cfgdevpi login root 123devpi upload –from-dir /wheelhouse上传完成后可以使用 http://<host_ip>:3141 查看 pip 本地源服务器状态。若要临时使用可以使用 pip install 的 –index 和 –trusted-host 选项pip install –index http://<host_ip>:3141/root/public/+simple/ \ –trusted-host <host_ip>或者修改 pip.conf 文件永久使用# vim ~/.pip/pip.conf[global]index_url = http://<host_ip>:3141/root/public/+simple/trusted-host = <host_ip>[search]index = http://<host_ip>:3141/root/public/最后,欢迎关注我的僵尸微信公众号 :) CodeWar ...

April 7, 2019 · 1 min · jiezi

Docker安装与应用

一、docker安装1、快捷安装快捷安装参考:https://get.daocloud.io/#inst…curl -sSL https://get.daocloud.io/docker | sh2、手动安装1.)先查看内核,更新yum包docker要求CentOS系统的内核版本>3.10$ uname -r$ sudo yum update2.)安装依赖包$ sudo yum install -y yum-utils device-mapper-persistent-data lvm23.)设置国内docker镜像源$ sudo yum-config-manager –add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo4.)如果安装过,卸载旧版本$ sudo yum remove docker docker-common docker-selinux docker-engine5.)查看仓库中所有docker,安装$ yum list docker-ce –showduplicates | sort -r$ sudo yum install docker-ce$ docker -v # 测试3、启动/关闭docker服务**$ sudo systemctl start docker$ sudo systemctl stop docker# 加入随机启动$ sudo systemctl enable docker二、docker常用命令每次使用docker命令都需要sudo,比较麻烦,可以通过以下命令添加当前用户到docker附属组:$ sudo usermod -aG docker 当前用户名 # 需要注销后登录生效1.)查看容器/镜像$ docker ps # 查看本地容器$ docker images # 查看本地镜像# 查看容器详情$ docker inspect xxx# 查看容器top进程$ docker top xxx# 查找远程镜像$ docker search xxx2.)新建容器最少参数的创建# -d:表示后台运行,-it:表示以交互的方式创建,可视化时可通过console打开$ docker run -d -it –name 容器名 –restart always 镜像名更多参数:映射端口、dns、持久存储卷、初始化进程防容器退出# -p:映射端口,–dns:有些容器默认dns解析服务配置不对(/etc/resolv.conf),-v:映射路径(可重复多个),/bin/sh:保持一个进程运行,否则容器会退出$ docker run -dit -p 宿主端口:容器端口 –dns=8.8.8.8 –name 容器名 -v 宿主路径:容器路径 –restart always 镜像:标签 /bin/sh3.)启动/停止容器$ docker start | restart xxx # 启动/重启$ docker stop xxx # 停止容器$ docker kill xxx # 强行终止,关闭进程4.)进入容器# 多窗口同时进入,会同步显示,容易窗口阻塞,适合本地开发$ docker attach xxx# 或者,docker在1.3.X版本,新命令$ docker exec -it xxx /bin/bash5.)删除容器/镜像# 删除容器前,先停止$ docker stop xxx $ docker rm xxx# 删除镜像$ docker rmi xxx # -f 强制删除6.)镜像改名$ docker tag 原镜像 新镜像 # 会生成一个新名,镜像id一样$ docker rmi 原镜像三、镜像构建1、手动构建镜像用基础镜像创建一个容器,手动安装好一切,然后用容器生成镜像:$ docker commit 容器名 新镜像名2、自动构建镜像:Dockerfile1.)Dockerfile配置新建Dockerfile并配置相关内容,下面以配置一个基于alpine的pm2安装并运行node应用为例:# 基础镜像源FROM alpine# 创建者信息MAINTAINER hoby <w.hoby@qq.com># RUN命令:构建过程中执行,常用于安装软件包RUN echo ’nameserver 8.8.8.8’ >> /etc/resolv.conf \ && apk update \ && apk add bash \ && apk add nodejs && apk add npm \ && npm config set registry https://registry.npm.taobao.org \ && npm i -g pm2# 指定工作目录,用绝对WORKDIR /app# 从宿主机copy到容器#COPY ./www.js /app# 与COPY类似,但ADD自带解压功能#ADD ./x.tar.xz /app# 定义环境变量ENV NODE_ENV=production# 配置entrypoint入口脚本RUN echo ‘console.log(“this is node web!”)’ > ./www.js \ && echo ‘#!/bin/bash’ > ./entrypoint.sh \ && echo ‘pm2 start /app/www.js’ >> ./entrypoint.sh \ && echo ‘/bin/sh’ >> ./entrypoint.sh \ && chmod a+x ./entrypoint.sh# 容器启动后执行的命令,且不可被docker run提供的参数覆盖ENTRYPOINT ["/bin/sh", “./entrypoint.sh”]# 容器启动后默认执行的命令,可被docker run后面的参数代替#CMD ["/bin/sh"]# 暴露端口EXPOSE 80运行构建命令:$ docker build -t myimage:latest . # 镜像名需小写# 新建并启动容器$ docker run -dit -p 8000:80 –dns=8.8.8.8 –name 容器名 –restart always myimage:latest2.)Dockerfile构建总结a. 构建时下载不了软件包,说明容器dns不对,需修改/etc/resolv.conf b. alpine镜像默认sh终端,需安装bash c. 建议一个容器只运行单个应用,多个应用见下文compose部署 d. Docker镜像构建是分层,将多个RUN指令合并 e. -v持久化路径时,若宿主机路径是新建的,容器路径内容会被清空 f. 当ENTRYPOINT与CMD使用exec参数时需双引号g. 添加.dockerignore,提高编译速度:.git/node_modules/四、多个应用容器部署Docker Compose是一个管理多容器应用的工具1、docker-compose安装Compose下载地址: https://get.daocloud.io/#inst...curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.0/docker-compose-`uname -s-uname -m` > /usr/local/bin/docker-composechmod +x /usr/local/bin/docker-compose2、docker-compose文件配置新建docker-compose.yml,下面以nginx单容器配置为例:version: “3"services: web: image: nginx volumes: - ./nginx.conf:/etc/nginx/conf.d/actor.conf - ./actor:/app/actor container_name: actor ports: - “18000:8000” command: [“nginx”,"-g”,“daemon off;”] redis: image: “redis:alpine"在docker-compose.yml同目录下,创建启动/更新容器:$ docker-compose up -d # -d后台运行3、docker-compose常用命令在docker-compose.yml同一目录下# 创建并启动容器$ docker-compose up -d# 重启容器$ docker-compose restart# 查看yml配置$ docker-compose config# 停止容器$ docker-compose stop# 停止并移除容器$ docker-compose down五、可视化容器管理工具Portainer是一个轻量级的Docker环境UI界面管理系统1、快速部署$ docker volume create portainer_data # 在宿主机创建持久化目录$ docker run -d -p 9000:9000 –name portainer –restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer2、相关问题1.) 可视化创建容器时,Advanced container settings -> Console 记得勾选 Interactive & TTY (-i -t),否则无法使用控制台2.) portainer中volume默认在/var/lib/docker/volumes下,貌似不能自定义目录,可通过手动命令行创建时-v指定 ...

April 3, 2019 · 2 min · jiezi

Kubernetes的几种主流部署方式02-kubeadm部署1.14版本高可用集群

在上篇文章minikube部署中,有提到Minikube部署Kubernetes的核心就是Kubeadm,这篇文章来详细说明下Kubeadm原理及部署步骤。写这篇文章的时候,Kubernetes1.14刚刚发布,所以部署步骤以1.14版为主。Kubeadm原理简述Kubeadm工具的出发点很简单,就是尽可能简单的部署一个生产可用的Kubernetes集群。实际也确实很简单,只需要两条命令:# 创建一个 Master 节点$ kubeadm init# 将一个 Node 节点加入到当前集群中$ kubeadm join <Master 节点的 IP 和端口 >kubeadm做了这些事执行 kubeadm init时:自动化的集群机器合规检查自动化生成集群运行所需的各类证书及各类配置,并将Master节点信息保存在名为cluster-info的ConfigMap中。通过static Pod方式,运行API server, controller manager 、scheduler及etcd组件。生成Token以便其他节点加入集群执行 kubeadm join时:节点通过token访问kube-apiserver,获取cluster-info中信息,主要是apiserver的授权信息(节点信任集群)。通过授权信息,kubelet可执行TLS bootstrapping,与apiserver真正建立互信任关系(集群信任节点)。简单来说,kubeadm做的事就是把大部分组件都容器化,通过StaticPod方式运行,并自动化了大部分的集群配置及认证等工作,简单几步即可搭建一个可用Kubernetes的集群。这里有个问题,为什么不把kubelet组件也容器化呢,是因为,kubelet在配置容器网络、管理容器数据卷时,都需要直接操作宿主机,而如果现在 kubelet 本身就运行在一个容器里,那么直接操作宿主机就会变得很麻烦。比如,容器内要做NFS的挂载,需要kubelet先在宿主机执行mount挂载NFS。如果kubelet运行在容器中问题来了,如果kubectl运行在容器中,要操作宿主机的Mount Namespace是非常复杂的。所以,kubeadm选择把kubelet运行直接运行在宿主机中,使用容器部署其他Kubernetes组件。所以,Kubeadm部署要安装的组件有Kubeadm、kubelet、kubectl三个。上面说的是kubeadm部署方式的一般步骤,kubeadm部署是可以自由定制的,包括要容器化哪些组件,所用的镜像,是否用外部etcd,是否使用用户证书认证等以及集群的配置等等,都是可以灵活定制的,这也是kubeadm能够快速部署一个高可用的集群的基础。详细的说明可以参考官方Reference。但是,kubeadm最重要的作用还是解决集群部署问题,而不是集群配置管理的问题,官方也建议把Kubeadm作为一个基础工具,在其上层再去量身定制适合自己的集群的管理工具(例如minikube)。Kubeadm部署一个高可用集群Kubernetes的高可用Kubernetes的高可用主要指的是控制平面的高可用,简单说,就是有多套Master节点组件和Etcd组件,工作节点通过负载均衡连接到各Master。HA有两种做法,一种是将etcd与Master节点组件混布在一起:另外一种方式是,使用独立的Etcd集群,不与Master节点混布:两种方式的相同之处在于都提供了控制平面的冗余,实现了集群高可以用,区别在于:Etcd混布方式:所需机器资源少部署简单,利于管理容易进行横向扩展风险大,一台宿主机挂了,master和etcd就都少了一套,集群冗余度受到的影响比较大。Etcd独立部署方式:所需机器资源多(按照Etcd集群的奇数原则,这种拓扑的集群关控制平面最少就要6台宿主机了)。部署相对复杂,要独立管理etcd集群和和master集群。解耦了控制平面和Etcd,集群风险小健壮性强,单独挂了一台master或etcd对集群的影响很小。部署环境 由于机器资源不足,下面的部署测试,只会以混布的方式部署一个1haproxy,2master,2*node,共5台机器的集群,实际上由于etcd选举要过半数,至少要3台master节点才能构成高可用,在生产环境,还是要根据实际情况,尽量选择风险低的拓扑结构。机器:master-1:192.168.41.230 (控制平面节点1)master-2:192.168.41.231 (控制平面节点2)node-1:172.16.201.108 (工作节点1)node-2:172.16.201.109 (工作节点2)haproxy:192.168.41.231 (haproxy)系统内核版本:# cat /etc/redhat-releaseCentOS Linux release 7.6.1810 (Core) # uname -r 5.0.5-1.el7.elrepo.x86_64集群版本kubeadm:1.14.0Kubernetes:1.14.0Docker:Community 18.09.4haproxy: 1.5.18部署步骤机器准备在所有节点上操作:关闭selinux,firewallsetenforce 0sed -i ’s/SELINUX=enforcing/SELINUX=permissive/’ /etc/selinux/config systemctl stop firewalldsystemctl disable firewalld关闭swap,(1.8版本后的要求,目的应该是不想让swap干扰pod可使用的内存limit)swapoff -a修改下面内核参数,否则请求数据经过iptables的路由可能有问题cat <<EOF > /etc/sysctl.d/k8s.confnet.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1EOFsysctl –system安装kubeadm、docker在除了haproxy以外所有节点上操作将Kubernetes安装源改为阿里云,方便国内网络环境安装cat << EOF > /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/enabled=1gpgcheck=1repo_gpgcheck=1gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpgEOF安装docker-cewget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repoyum install -y docker-ce安装kubelet kubeadm kubectl yum install -y kubelet kubeadm kubectl安装配置负载均衡在haproxy节点操作:# 安装haproxyyum install haproxy -y # 修改haproxy配置cat << EOF > /etc/haproxy/haproxy.cfgglobal log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 user haproxy group haproxy daemondefaults mode tcp log global retries 3 timeout connect 10s timeout client 1m timeout server 1mfrontend kube-apiserver bind :6443 # 指定前端端口 mode tcp default_backend masterbackend master # 指定后端机器及端口,负载方式为轮询 balance roundrobin server master-1 192.168.41.230:6443 check maxconn 2000 server master-2 192.168.41.231:6443 check maxconn 2000EOF# 开机默认启动haproxy,开启服务systemctl enable haproxysystemctl start haproxy# 检查服务端口情况:# netstat -lntup | grep 6443tcp 0 0 0.0.0.0:6443 0.0.0.0: LISTEN 3110/haproxy部署Kubernetes在master-1节点操作:准备集群配置文件,目前用的api版本为v1beta1,具体配置可以参考官方referencecat << EOF > /root/kubeadm-config.yamlapiVersion: kubeadm.k8s.io/v1beta1kind: ClusterConfigurationkubernetesVersion: v1.14.0 # 指定1.14版本controlPlaneEndpoint: 192.168.41.232:6443 # haproxy地址及端口imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers # 指定镜像源为阿里源networking: podSubnet: 10.244.0.0/16 # 计划使用flannel网络插件,指定pod网段及掩码EOF执行节点初始化systemctl enable kubeletsystemctl start kubeletkubeadm config images pull –config kubeadm-config.yaml # 通过阿里源预先拉镜像kubeadm init –config=kubeadm-config.yaml –experimental-upload-certs安装成功,可以看到输出You can now join any number of the control-plane node running the following command on each as root:# master节点用以下命令加入集群: kubeadm join 192.168.41.232:6443 –token ocb5tz.pv252zn76rl4l3f6 \ –discovery-token-ca-cert-hash sha256:141bbeb79bf58d81d551f33ace207c7b19bee1cfd7790112ce26a6a300eee5a2 \ –experimental-control-plane –certificate-key 20366c9cdbfdc1435a6f6d616d988d027f2785e34e2df9383f784cf61bab9826Then you can join any number of worker nodes by running the following on each as root:# 工作节点用以下命令加入集群:kubeadm join 192.168.41.232:6443 –token ocb5tz.pv252zn76rl4l3f6 \ –discovery-token-ca-cert-hash sha256:141bbeb79bf58d81d551f33ace207c7b19bee1cfd7790112ce26a6a300eee5a2 原来的kubeadm版本,join命令只用于工作节点的加入,而新版本加入了 –experimental-contaol-plane 参数后,控制平面(master)节点也可以通过kubeadm join命令加入集群了。加入另外一个master节点在master-2操作:kubeadm join 192.168.41.232:6443 –token ocb5tz.pv252zn76rl4l3f6 --discovery-token-ca-cert-hash sha256:141bbeb79bf58d81d551f33ace207c7b19bee1cfd7790112ce26a6a300eee5a2 --experimental-control-plane –certificate-key 20366c9cdbfdc1435a6f6d616d988d027f2785e34e2df9383f784cf61bab9826mkdir -p $HOME/.kubecp -i /etc/kubernetes/admin.conf $HOME/.kube/configchown $(id -u):$(id -g) $HOME/.kube/config 现在,在任何一个master 节点,执行kubectl get no,可以看到,集群中已经有2台master节点了# kubectl get noNAME STATUS ROLES AGE VERSIONmaster-1 NotReady master 34m v1.14.0master-2 NotReady master 4m52s v1.14.0加入两个工作节点分别在两个node节点操作:kubeadm join 192.168.41.232:6443 –token ocb5tz.pv252zn76rl4l3f6 \ –discovery-token-ca-cert-hash sha256:141bbeb79bf58d81d551f33ace207c7b19bee1cfd7790112ce26a6a300eee5a2 再次执行kubectl get no# kubectl get noNAME STATUS ROLES AGE VERSIONmaster-1 NotReady master 45m v1.14.0master-2 NotReady master 15m v1.14.0node-1 NotReady <none> 6m19s v1.14.0node-2 NotReady <none> 4m59s v1.14.0可以看到两个node节点都加入集群了。可是,各个节点状态为什么都是NotReady呢。通过执行kubectl describe master-1,可以看到这样的提示:runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized原来是因为网络插件没有就绪导致的。所以 ,我们来安装一波kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/a70459be0084506e4ec919aa1c114638878db11b/Documentation/kube-flannel.yml再次查看节点状态,可以看到所有节点都已经ready了。# kubectl get noNAME STATUS ROLES AGE VERSIONmaster-1 Ready master 134m v1.14.0master-2 Ready master 104m v1.14.0node-1 Ready <none> 94m v1.14.0node-2 Ready <none> 93m v1.14.0至此,一个2主节点2工作节点的k8s集群已经搭建完毕。如果要加入更多的master或node节点,只要多次执行kubeadm join命令加入集群就好,不需要额外配置,非常方便。集群测试跟上篇文章minikube部署一样,这里部署一个简单的goweb服务来测试集群,运行时暴露8000端口,同时访问/info路径会显示容器的主机名。准备deployment和svc的yaml:# deployment-goweb.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: gowebspec: selector: matchLabels: app: goweb replicas: 4 template: metadata: labels: app: goweb spec: containers: - image: lingtony/goweb name: goweb ports: - containerPort: 8000# svc-goweb.yamlapiVersion: v1kind: Servicemetadata: name: gowebsvcspec: selector: app: goweb ports: - name: default protocol: TCP port: 80 targetPort: 8000部署服务kubectl apply -f deployment-goweb.yamlkubectl apply -y svc-goweb.yaml查看pod及服务[root@master-1 ~]# kubectl get po -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESgoweb-6c569f884-67z89 1/1 Running 0 25m 10.244.1.2 node-1 <none> <none>goweb-6c569f884-bt4p6 1/1 Running 0 25m 10.244.1.3 node-1 <none> <none>goweb-6c569f884-dltww 1/1 Running 0 25m 10.244.1.4 node-1 <none> <none>goweb-6c569f884-vshkm 1/1 Running 0 25m 10.244.3.4 node-2 <none> <none># 可以看到,4个pod分布在不同的node上[root@master-1 ~]# kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEgowebsvc ClusterIP 10.106.202.0 <none> 80/TCP 11mkubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h# 暴露80端口测试访问[root@master-1 ~]# curl http://10.106.202.0/infoHostname: goweb-6c569f884-bt4p6[root@master-1 ~]# curl http://10.106.202.0/infoHostname: goweb-6c569f884-67z89[root@master-1 ~]# curl http://10.106.202.0/infoHostname: goweb-6c569f884-vshkm#可以看到,对SVC的请求会在pod间负载均衡。小结本文简单介绍了kubeadm工具原理,以及如何用它部署一个高可用的kubernetes集群。需要注意的是,kubeadm工具总体已经GA,可以在生产环境使用了。但是文中通过"kubeadm join -experimental-contaol-plane"参数增加主节点的方式,还是在alpha阶段,实际在生产环境还是用init方式来增加主节点比较稳定。kubeadm更多详细配置可以参考官方文档 ...

April 2, 2019 · 3 min · jiezi

docker命令

docker入门主要是docker使用命令docker守护进程修改守护进程的网络sudo docker daemon -H tcp://0.0.0.0:2375 这条命令将docker守护进程//使用docker_host环境变量export DOCKER_HOST = “tcp:0.0.0:2375检查docker是否运行sudo status docker //sudo service docker status启动和关闭sudo stop docker //sudo service docker stopsudo start docker //sudo service docker startdocker容器操作查看docker是否正常工作sudo docker info运行容器sudo docker run -i -t ubuntu /bin/bash//-i标记保证容器是STDIN开启的//-t标记告诉docker要创建的容器分配一个伪tty终端//ubuntu 指定镜像// /bin/bash告诉docker容器要运行什么命令容器命名docker默认为创建的容器生成一个随机的名称,可通过--name标记来给容器命名sudo docker run --name myName -i -t ubuntu /bin/bash启动已经停止的容器sudo docker start myName //也可通过id指定//也可使用docker restart命令附着到容器上docker容器重新启动的时候,会沿用docker run命令时指定的参数来运行,因此上例中重新启动会运行一个交互式的shell,此外也可以用docker attach重新附着到该容器的会话上sudo docker attach myName //也可通过id指定创建守护式容器除了交互式运行的容器,也可以创建长期运行的容器,守护式容器没有交互式会话,非常适合运行应用程序和服务。sudo docker run --name daemon_name -d ubuntu /bin/sh -c "while true; do echo hello world;sleep 1;done"//-d 标记docker将容器放在后台运行//while循环一直打印hello world查看docker容器docker ps //查看正在运行的容器docker ps -a //查看所有的容器查看容器内部docker logs daemon_name //获取容器的日志,可通过-f来追踪日志日志驱动docker1.6开始,可通过--log-driver选项来控制docker守护线程和容器所有的日志驱动,可以在执行docker守护线程或者执行docker run命令时使用这个选项。sudo docker run --log-driver="syslog" --name daemon_name -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"//将daemon_name容器的日志输出到syslog,导致docker logs命令不会输出任何东西查看容器内的进程sudo docker top daemon_name在容器内部运行进程sudo docker exec -d daemon_name touch /etc/new_config_file//-d 标记运行一个后台进程 后面明智执行名气的名字以及执行的命令sudo docker exec -t -i daemon_name /bin/bash//创建TTY并捕捉STDIN关闭容器sudo docker stop daemon_name深入容器sudo docker inspect daemon_name //查看更多容器的信息//该命令也可用来查看镜像信息删除容器sudo docker rm 80430f8d0921 //通过指定容器id//删除全部容器sudo docker rm sudo docker ps -a -q` //-q标记表示只返回容器的iddocker镜像列出docker镜像sudo docker images//本地镜像都保存在docker宿主机的/var/lib/docker目录i西安,每个镜像都保存在docker所采用的存储驱动目录下面,如aufs或者devicemapper,也可以在/var/bin/docker/containers目录下看到所有容器拉取镜像sudo docker pull ubuntu:12.04运行一个带标签的docker镜像sudo docker run -t -i –name new_container ubuntu:12:04 /bin/bash查找镜像可以通过docker search命令来查找所有docker hub上公共的可用镜像sudo docker search puppetNAME DESCRIPTION STARS OFFICIAL AUTOMATEDpuppet/puppetserver A Docker Image for running Puppet Server. Wi… 75 alekzonder/puppeteer GoogleChrome/puppeteer image and screenshots… 51 [OK]仓库名镜像描述stars,用户评价official,是否官方,由上游开发者管理的镜像(如fedora镜像由fedora团队管理)。automated,自动构建,表示这个镜像由docker hub的自动构建流程构建的。构建镜像构建镜像有两种方式docker commit命令docker build命令和dockerfile文件现在并不推荐使用docker commit命令,而应该使用更灵活、更强大的dockerfile来构建docker镜像一般来说都是基于已有的基础镜像,而不是“创建”新镜像,从0开始可以参考:https://docs.docker.com/develop/develop-images/baseimages/创建docker hub账号创建完镜像之后,可以将镜像推送到docker hub或者私有的registryzhong,完成这个操作需要在docker hub上创建一个账号。https://hub.docker.com/signup登陆到docker hubsudo docker loginUsername:Password:Login Succeeded用docker commit来创建镜像//创建一个新容器sudo docker run -i -t ubuntu /bin/bash//在容器内部安装一些软件…//得到刚刚创建容器的iddocker ps -l -q9649de16bffb//提交定制容器sudo docker commit 9649de16bffb dack/apache2 //检查新创建的镜像docker images dack/apache2REPOSITORY TAG IMAGE ID CREATED SIZEdack/apache2 latest 2c5cd556c3f2 About a minute ago 209MB也可以在提交镜像时指定更多的数据(包含标签)来详细描述所做的修改sudo docker commit -m “A new custom image” -a “dack huang” 9649de16bffb dack/apache2:webserver//-m 提交信息//-a 作息信息//dack/apache2:webserver 执行镜像的用户名和仓库名,并为该镜像增加一个webserver的标签 用Dockerfile构建镜像并不推荐用docker commit构建镜像,相反推荐使用Dockerfile的定义文件和docker build来构建镜像Dockerfile使用基本的基于DSL(Domain Specific Language)语法的指令来构建一个docker镜像,对比docker commit,其更具备可重复性、透明性和幂等性。保存Dockerfile的目录称为上下文,docker会在构建镜像时将构建的上下文和该上下文的文件和目录上传到docker守护进程。这样docker守护进程就可以直接访问用户想在镜像中存储的任何代码、文件或者其他数据。dockerfile中每条指令从上到下依次执行,大体的流程如下:docker从基础镜像中运行一个容器执行一条指令,对容器做出修改执行类似docker commit的操作,提交一个新的镜像层docker再基于刚提交的镜像运行一个新容器执行下一条指令直至全部执行完毕所以尽管某一步执行失败了,还是得到一个可以使用的镜像# Version : 0.01FROM ubuntu:14.04MAINTAINER dack huang “dack_huang@163.com"RUN apt-get update && apt-get install -y nginxRUN echo ‘Hi, I am in your container’ \ >/usr/share/nginx/html/index.htmlEXPOSE 80FROM //指定基础镜像MAINTAINER //指定镜像作者RUN //在当前镜像中运行的命令,默认在shell里面使用/bin/sh -c执行EXPOSE //应用程序会使用容器指定的接口通过docker build构建镜像docker build -t=“dack/static_web”//-t设置镜像标签//从git仓库上面构建镜像//假设这个git仓库存在Dockerfiledocker build -t=“dack/static” git@github.com:dack/docker-static_web docker将每一步的构建过程都提交为镜像,所以docker会将之前的镜像层看成缓存,当修改某个步骤之后再次构建的,docker会直接从该步骤开始。可用docker build –no-cache略过缓存docker build –no-cache -t=“dack/static_web"docker history查看镜像的每一层[root@dack static_web]# docker history e5f55354c141IMAGE CREATED CREATED BY SIZE COMMENTe5f55354c141 5 hours ago /bin/sh -c #(nop) EXPOSE 80 0B 66d44cca6536 5 hours ago /bin/sh -c echo ‘Hi, I am in your container’… 27B 022c0b46f4f8 5 hours ago /bin/sh -c apt-get update && apt-get install… 34.3MB 34d2d2b790f5 5 hours ago /bin/sh -c #(nop) MAINTAINER dack huang “da… 0B 390582d83ead 3 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash”] 0B <missing> 3 weeks ago /bin/sh -c mkdir -p /run/systemd && echo ‘do… 7B 参考第一本docke书 ...

April 2, 2019 · 2 min · jiezi

Rainbond v5.1.2发布,微服务架构应用便捷管理和交付

Rainbond v5.1.2发布,微服务架构应用便捷管理和交付Rainbond是开源的企业应用云操作系统,支撑企业应用的开发、架构、交付和运维的全流程,通过无侵入架构,无缝衔接各类企业应用,底层资源可以对接和管理IaaS、虚拟机和物理服务器。2019年3月,Rainbond发布v5.1版本,经过1个月在上百家企业的实际使用,团队持续跟进版本缺陷,迄今为止发布了2个BUG修复版本。Rainbond开源产品的目标是成为企业IT系统的云操作系统,作为基础平台支持各行各业的企业用户,优化IT软件开发企业的开发流程和交付流程,做到一站式开发和交付。作为广大行业IT厂商的合作伙伴,为其提供稳定的、好用的、高效的基础平台,服务于行业软件的架构、开发和交付,Rainbond在这条路上砥砺前行。在V5.1版本中我们引入了以下功能体系来服务用户。支持第三方微服务集成和管理Rainbond在众多的企业中落地使用的过程中出现了两类共同的问题:循序渐进的迁移策略,已经上Rainbond的服务如何与遗留服务通信和统一管理。Rainbond应用网关很好用,但是遗留的服务没办法与Rainbond上的服务共享外网端口或域名。Rainbond V5.1版本中在提出了第三方服务的概念,即将运行于Rainbond集群外且与Rainbond可以正常网络通信的服务称为第三方服务。对于此类服务,我们支持以静态注册、动态注册(Etcd、Zookeeper、Consule)的方式来获取第三方服务的通信地址,赋予第三方服务以下能力:集成Rainbond内置的ServiceMesh架构,与集群内服务无缝互联,并提供服务通信治理功能。集成Rainbond 应用网关,统一管理服务外网访问。运行于不同环境和系统的业务系统统一管理和可视化,形成完整业务架构。更多第三方服务的说明和支持情况,见文档: Rainbond支持第三方服务集成此功能发布之后,在阿里云运行Rainbond的企业用户可以更便捷的对接阿里云的RDS资源。更加充分的利用云资源以降低企业维护IT系统的成本。支持微服务启动顺序在一个复杂微服务架构下,一些服务必须依赖于另一些服务才能正常工作,如何根据依赖关系处理服务的启动顺序是简化复杂微服务架构管理的关键。Rainbond实现了根据依赖关系自动处理服务的启动顺序,当被依赖的服务正常工作后,才会启动后续服务,依次迭代启动所有服务。这方面的功能实现主要在体现Rainbond的主要抽象层次,我们比较清楚的是docker的抽象层次是容器级别,kubernetes的抽象层次主要可以认为是服务级别(Pod级别),Rainbond的关键抽象层是更高的应用级,特别是微服务架构盛行的今天,服务组件多,对于大多数业务程序都需要手动的控制启动顺序来确保整个业务的正常工作。Rainbond能够做到能够做到在应用级整体控制生命周期和其他自动化运维。此功能发布后在某工业互联网软件企业用户中创造了较大价值,一个完整的工业互联网APP开发平台由20多个服务组件构成,过去他们每交付一个工厂的交付成本需要一个熟练的交付工程师出差调试大概2天才能基本完成。其中主要的就是需要熟练掌握服务之间的依赖关系,启动顺序,服务配置,这还是建立在他们产品的成熟度已经比较高。后期这一套业务系统交付用户的运维成本也非常大。当使用Rainbond作为基础交付平台以后,他们通过1天的时间将所有服务完整部署的Rainbond并发布于应用市场。由于Rainbond完整的应用系统生命周期控制和启动顺序控制,实现了完整的工业互联网APP开发平台的一键部署,10分钟完成业务可工作。对于最终用户来说也可以更加直观的运维管理业务系统。源码构建系统升级基于源代码持续构建服务是Rainbond用户使用最多的功能之一,既5.0版本作较大升级以后,5.1版本继续带来升级,在Java、PHP、NodeJS等常用语言方面支持更加完善:增加对NodeJS前端项目源码类型的支持,可以部署Vue和React。Java-Maven增加maven编译参数的UI配置。所有Java类型支持OpenJDK版本和OracleJDK版本的UI配置。PHP、静态语言支持UI选择中间件类型和版本。将公共代码模块和资源从云端本地化、更好的支持离线环境下源码构建支持服务源码类型重新检测和变更另外Rainbond对各类型源码的支持规范文档进行了更加细致的描述,请参考 Rainbond源码支持规范从源码构建主要服务于开发场景,目前还是有较多的企业开发者出于学习成本无法定义优质的Dockerfile,直接使用Rainbond提供的基于源代码构建的机制是开发者使用Rainbond发布服务最易用的方式。我们从用户使用中总结发现目前开发语言最多的依然是Java,因此Rainbond对Java语言支持的持续优化依然是V5.1版本的重点,其中有大量用户使用的是SpringCloud,因此Rainbond将在V5.1后续小版本中增加直接基于Maven源码创建多个服务模块的便捷服务创建方式,进一步提供用户创建服务的效率。除了上述提到的Rainbond V5.1版本大的功能变化以外,Rainbond还进行了大量的功能改进和优化。详细参考:https://github.com/goodrain/r…https://github.com/goodrain/r...https://github.com/goodrain/r…开始你的Rainbond之旅你的企业是否也遇到过上文提到的种种影响你的产品开发和交付的效率的问题,不妨使用Rainbond来优化一下你的现有模式和体验。Rainbond 安装参考手册 https://www.rainbond.com/docs...Rainbond 使用参考手册 https://www.rainbond.com/docs...Rainbond 进阶场景手册 https://www.rainbond.com/docs…

April 2, 2019 · 1 min · jiezi

Spring Boot 整合 docker

一、什么是docker ?简介Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。docker的应用场景web应用的自动化打包和发布;自动化测试和持续集成、发布;在服务型环境中部署和调整数据库或其他的后台应用;从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境。二、整合 docker创建工程创建一个springboot工程springboot-docker1. 启动类package com.gf;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RestController;@SpringBootApplication@RestControllerpublic class SpringbootDockerApplication { public static void main(String[] args) { SpringApplication.run(SpringbootDockerApplication.class, args); } @GetMapping("/{name}") public String hi(@PathVariable(value = “name”) String name) { return “hi , " + name; }}2. 将springboot工程容器化我们编写一个Dockerfile来定制镜像,在src/main/resources/docker 下创建Dockerfile文件FROM frolvlad/alpine-oraclejdk8:slimVOLUME /tmpADD springboot-docker-0.0.1-SNAPSHOT.jar app.jarRUN sh -c ’touch /app.jar’ENV JAVA_OPTS=““ENTRYPOINT [ “sh”, “-c”, “java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar” ]3. pom.xml我们通过maven 构建docker镜像。在maven的pom目录,加上docker镜像构建的插件<?xml version=“1.0” encoding=“UTF-8”?><project xmlns=“http://maven.apache.org/POM/4.0.0" xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> <relativePath/> <!– lookup parent from repository –> </parent> <groupId>com.gf</groupId> <artifactId>springboot-docker</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-docker</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <docker.image.prefix>gf</docker.image.prefix> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>1.2.0</version> <configuration> <imageName>${docker.image.prefix}/${project.artifactId}</imageName> <dockerDirectory>src/main/resources/docker</dockerDirectory> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> </resource> </resources> </configuration> </plugin> </plugins> </build></project>构建镜像我们运行下面的命令构建镜像:mvn cleanmvn package docker:bulid构建成功后,我们通过下面的命令查看镜像:docker images启动镜像:#c2dba352c3c1 为镜像IDdocker run -p 8080:8080 -t c2dba352c3c1之后我们就可以访问服务了。源码下载:https://github.com/gf-huanchupk/SpringBootLearning关注我的公众号,精彩内容不能错过~ ...

April 1, 2019 · 1 min · jiezi

使用URLOS低门槛快速开发和分发docker应用,未来微服务发展大趋势

2019年微服务概念继续火爆,随着Docker容器技术的快速普及,特别在一线互联网公司。使用Docker技术可以帮助企业快速水平扩展服务,从而到达弹性部署业务的能力。在云服务概念兴起之后,Docker的使用场景和范围进一步发展,如今在微服务架构越来越流行的情况下,微服务+Docker的完美组合,更加方便微服务架构运维部署落地。如何快速入门docker,开发属于自己的容器应用?咱今天不整虚的,来点实打实的干货:利用URLOS快速开发docker应用,并可随意将应用导出给他人使用。对URLOS不了解的朋友,这里大概介绍一下,URLOS是一个容器云管理面板,基于Docker容器技术打包和运行应用,可自动识别机器和云应用的故障并将云应用转移至可用的机器上,单机故障并不影响业务开展,配合云存储便可轻松搭建7x24小时持续运行的应用环境。URLOS官网:https://www.urlos.com/URLOS安装方法:https://www.urlos.com/center-…URLOS开发交流QQ群:695164700,147882180URLOS创始人微信:安装URLOS:curl -SO https://www.urlos.com/install && chmod 544 install && ./install安装完成后,地址栏输入 http://ip:9968 即可访问。划重点:利用URLOS开发docker应用的最基本的流程:这里我们以制作一个LNP(linux+nginx+php)网站环境为例,快速制作一个可以导出给他人使用的docker应用。在开始制作之前,我们先到docker官网注册一个账号,这样我们才能将制作好的镜像上传到docker仓库,打开https://hub.docker.com/ 有了hub账号,那么我们开始制作吧!第一步:拉取镜像,启动容器,进入容器使用SSH工具连接主机,输入以下命令拉取一个php:7.3.3-fpm-stretch镜像,启动容器并进入这个容器内部:docker run -it php:7.3.3-fpm-stretch bash看到类似上图中类似的字符串时,表示已经成功进入容器内部,这个便是当前容器的ID第二步:更新镜像,安装我们要的nginx以及PHP相关扩展先更新一下镜像源,国内用阿里的会快一些set -ex \ && sed -i ’s@security.debian.org@mirrors.aliyun.com@’ /etc/apt/sources.listset -ex \ && sed -i ’s@deb.debian.org@mirrors.aliyun.com@’ /etc/apt/sources.listapt-get update更新完成之后,再来安装nginx,默认安装目录为/etc/nginxapt-get install -y nginx官方镜像默认是没有ps -ef 命令,因此需要手动安装apt-get install -y procps安装PHP扩展。安装php自带的一些扩展时,可以使用docker-php-ext-configure和docker-php-ext-install。例如我们要安装pdo_mysql:docker-php-ext-configure pdo_mysqldocker-php-ext-install pdo_mysql然后使用 php -m查看我们的扩展是否安装成功。使用这种方式安装,系统会自动生成一个配置文件,提供给php加载,使用命令查看:ls -l /usr/local/etc/php/conf.d/gd扩展安装apt-get install -y libfreetype6-dev \libjpeg62-turbo-dev \libpng-devdocker-php-ext-configure gd –with-freetype-dir=/usr/include/ –with-jpegdir=/usr/include/docker-php-ext-install gd如果需要安装memcached、redis扩展,则需要下载扩展到容器,然后手动编译安装。地址:https://pecl.php.net/package/…https://pecl.php.net/package/...memcached扩展安装:curl -O https://pecl.php.net/get/memcached-3.1.3.tgztar xf memcached-3.1.3.tgz && cd memcached-3.1.3phpize./configure编译过程中若出现以下错误提示:则执行安装命令,然后重新编译安装memcached扩展:apt-get install -y libmemcached-dev./configuremake && make install添加extension=memcached.so语句到php.ini文件。安装完成后通过命令查看扩展存放的位置ls /usr/local/lib/php/extensions/no-debug-non-zts-20170718/php安装目录:/usr/local/phpphp.ini的配置文件目录:/usr/local/etc/php/。在这个目录下有两个文件:php.ini-development和php.iniproduction。因此,我们需要将php.ini-production文件重命名为php.ini。以后手动编译安装php扩展后需要添加extension=xx.so到php.ini。启动Nginx和php,检查是否正常运行。nginx && php-fpm -D第三步:打包镜像在打包成镜像之前,我们先将nginx、php-fpm关闭,删除一些不需要的应用以及清理一些安装的缓存文件,从而减小最终打包成镜像的大小。apt-get purge vim makeapt-get autoremoveapt-get autocleanrm -f /usr/local/etc/php/conf.d/* #统一将php扩展写入到php.ini文件然后,输入exit退出容器,通过以下命令将更新过的容器重新打包成一个新镜像:docker commit -m=“php-nginx-website” -a=“yourname” 96b3f038590b yourhubid/php-nginx:v0.1.0参数说明:-m:提交的描述信息-a:指定镜像作者96b3f038590b:容器IDyourhubid/php-nginx:v0.1.0:指定要创建的目标镜像名可以使用docker images命令来查看我们的新镜像第四步:上传镜像使用docker login命令登录 hub.docker.com,按提示输入账号和密码即可使用docker push命令将打包好的新镜像上传至镜像仓库:docker push yourhubid/php-nginx:v0.1.0第五步:登录URLOS制作应用注意:需要修改将/data/urlos/master-config/config.jsonc文件的envType的值设置为dev(开发环境):vim /data/urlos/master-config/config.jsonc添加镜像浏览器地址栏输入http://主机ip:9968,登录URLOS,在左侧菜单栏选择镜像管理,然后点击右上角的添加按钮。输入镜像名称镜像地址开发者信息添加LNP应用在左侧菜单中选择应用管理。然后点击右上角的添加应用按钮:应用的基本信息如上图所示。镜像:选择上一步骤添加的镜像。URLOS最低版本号:如设置此选项则表示安装URLO的版本高于或者等于当前设置的值,才允许用户安装使用。容器端口:容器启动时对外通信的端口,即参数-p。网站的80、443等端口默认是对外开发的,在这里可以不用设置。如必须特定端口时,设置的格式{“22”:true}。标签:应用标签多用于搜索场景。选项开关注解:固定节点运行:若勾选,则表示用户在安装此应用时(创建此应用的服务)需要选择安装在某个节点(云主机)。若取消勾选,则表示此应用安装在选择的集群(单容器运行也取消勾选),可达到负载均衡,故障转移的效果。单容器运行:若勾选,则表示安装此应用时,每个服务只运行一个容器。与固定节点运行配合使用,即固定节点运行时,则单容器运行。允许特权允许:若勾选,则容器内的root拥有了真正的root权限(宿主机器的root),在容器内部就可以做任何事情(包括修改宿主机器的文件,启动宿主机器其他容器,执行mount等操作),不建议勾选。以root用户允许容器:这里的root用户是容器外部的一个普通用户,默认勾选。若容器内部的程序禁止root用户允许,则取消(如:MySQL)。挂载存储目录:如需要从宿主机器挂载文件到容器,则勾选。即参数 -v。挂载时区定义文件:容器的时间与宿主机器的时间保持一致。容器只读:禁止向容器写数据。全局网络:允许同一集群不同容器网络的容器通信。允许快照备份:勾选则允许执行快照备份(仅挂载了本地存储时有效)开启反向代理,则可以实现多容器共享端口,反之则不能。注解:插件:由PHP语言编辑的脚本文件组成。插件的使用会让用户在安装应用(创建服务)时更便捷,更智能。这里选择phpWebSite:v0_1_0 — Liu Xin —php网站环境这个插件即可。(制作插件后续会有详细说明)服务别名:创建服务时,在左上角显示的描述。应用数据别名:创建服务完成后,服务产生的数据或者用户基于创建的服务需要添加新的数据,对这些数据管理取的名字,即为应用数据别名。(如:创建MySQL数据库服务,用户可以手动添加数据库,创建网站服务时也可以新增数据库。)服务表单步骤:创建服务时,用户填写表单的步骤。(数字表示必填,其他符号表示选填)额外挂载:将宿主机器的除存储目录外的其他目录挂载到容器。额外启动参数:通过docker run运行容器时的额外参数,如:–add-host a.com:192.168.0.1注解:安装脚本:安装应用时需要执行的脚本命令。test -d /etc/nginx/conf.d/ || mkdir -p /etc/nginx/conf.d/启动脚本:需要启动程序的命令。nginxphp-fpm -D状态脚本:每隔2秒执行此脚本,用来检查程序是否正常允许。当前的脚本命令用来检查apache是否启动。status1=0 && (ps -ef|grep “php-fpm”|grep “master process”|grep -v “grep”) &&status1=1;status2=0 && (ps -ef|grep “nginx”|grep “master process”|grep -v “grep”) &&status2=1;if [ ${status1} != 0 ] && [ ${status2} != 0 ]; thenstatusScriptResult=1fi监控脚本:每隔1秒执行此脚本,检查状态脚本返回的结果判断程序是否正常允许。若异常,则执行退脚本。{w:statusScript:w}[ “$statusScriptResult” != 1 ] && exit 1退出脚本:容器关闭时之前,执行的脚本。如同,我们关闭电脑时,系统会关闭正在允许的程序。添加LNP模板在这个应用,我们需要添加模板php.ini、vhost.conf,然后在这两个模板的参数设置一些变量,这样用户在安装应用时,就可以根据自己的需要动态的调整。(如:设置php的上传大小,最大内存等)那么如何添加模板呢?我们在应用管理列表中找到上述创建的应用,然后点击右侧的更多选择管理模板。添加一个php.ini模板,然后在模板内容将php.ini文件内容复制进入,同时设置变量{w:upload_max_filesize:w}、{w:PHP_memory_limit:w}。[PHP]engine = Onshort_open_tag = Offprecision = 14output_buffering = 4096zlib.output_compression = Offimplicit_flush = Offunserialize_callback_func =serialize_precision = -1disable_functions =disable_classes =zend.enable_gc = Onexpose_php = Onmax_execution_time = 30max_input_time = 60memory_limit = 128Merror_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICTdisplay_errors = Offdisplay_startup_errors = Offlog_errors = Onlog_errors_max_len = 1024ignore_repeated_errors = Offignore_repeated_source = Offreport_memleaks = Onhtml_errors = Onvariables_order = “GPCS"request_order = “GP"register_argc_argv = Offauto_globals_jit = Onpost_max_size = {w:PHP_memory_limit:w}auto_prepend_file =auto_append_file =default_mimetype = “text/html"default_charset = “UTF-8"doc_root =user_dir =enable_dl = Offfile_uploads = Onupload_max_filesize = {w:upload_max_filesize:w}max_file_uploads = 20allow_url_fopen = Onallow_url_include = Offdefault_socket_timeout = 60extension=gd.soextension=memcached.soextension=sockets.soextension=mysqli.soextension=pdo_mysql.so[CLI Server]cli_server.color = On[Date][filter][iconv][imap][intl][sqlite3][Pcre][Pdo][Pdo_mysql]pdo_mysql.default_socket=[Phar][mail function]SMTP = localhostsmtp_port = 25mail.add_x_header = Off[ODBC]odbc.allow_persistent = Onodbc.check_persistent = Onodbc.max_persistent = -1odbc.max_links = -1odbc.defaultlrl = 4096odbc.defaultbinmode = 1[Interbase]ibase.allow_persistent = 1ibase.max_persistent = -1ibase.max_links = -1ibase.timestampformat = “%Y-%m-%d %H:%M:%S"ibase.dateformat = “%Y-%m-%d"ibase.timeformat = “%H:%M:%S”[MySQLi]mysqli.max_persistent = -1mysqli.allow_persistent = Onmysqli.max_links = -1mysqli.default_port = 3306mysqli.default_socket =mysqli.default_host =mysqli.default_user =mysqli.default_pw =mysqli.reconnect = Off[mysqlnd]mysqlnd.collect_statistics = Onmysqlnd.collect_memory_statistics = Off[OCI8][PostgreSQL]pgsql.allow_persistent = Onpgsql.auto_reset_persistent = Offpgsql.max_persistent = -1pgsql.max_links = -1pgsql.ignore_notice = 0pgsql.log_notice = 0[bcmath]bcmath.scale = 0[browscap][Session]session.save_handler = filessession.use_strict_mode = 0session.use_cookies = 1session.use_only_cookies = 1session.name = PHPSESSIDsession.auto_start = 0session.cookie_lifetime = 0session.cookie_path = /session.cookie_domain =session.cookie_httponly =session.cookie_samesite =session.serialize_handler = phpsession.gc_probability = 1session.gc_divisor = 1000session.gc_maxlifetime = 1440session.referer_check =session.cache_limiter = nocachesession.cache_expire = 180session.use_trans_sid = 0session.sid_length = 26session.trans_sid_tags = “a=href,area=href,frame=src,form=“session.sid_bits_per_character = 5[Assertion]zend.assertions = -1[COM][mbstring][gd][exif][Tidy]tidy.clean_output = Off[soap]soap.wsdl_cache_enabled=1soap.wsdl_cache_dir="/tmp"soap.wsdl_cache_ttl=86400soap.wsdl_cache_limit = 5[sysvshm][ldap]ldap.max_links = -1[dba][opcache][curl][openssl]添加Nginx的虚拟站点配置vhost.conf模板server {server_name {w:domains:w};{w:listenLines:w}set $websiteRoot “/data/www/{w:indexDirName:w}";root $websiteRoot;index index.html index.htm index.php;client_max_body_size {w:upload_max_filesize:w};client_body_buffer_size 128;location / {{w:rewriteContents:w}}location ~ .(php|phtml)$ {include fastcgi.conf;fastcgi_pass 127.0.0.1:9000;}location ~ /.ht {deny all;}}添加变量变量分为:环境变量、数据变量和扩展变量。在这里只需要添加扩展变量。环境变量:在操作系统中用来指定操作系统运行环境的一些参数,与平常使用的环境变量相同。有时容器启动需要设置一些参数提供给容器内部的程序。如:MySQL容器启动时可以设置MYSQL_ROOT和MYSQL_ROOT_PASSWORD。数据变量:添加存储数据时设置的一些参数。如:往MySQL数据服务添加数据库时,需要填写dbName,dbPassword,status,charset。具体可以使用可以创建MySQL服务,然后在管理数据库中添加数据库。扩展变量:即普通变量。如:上述在模板中设置的变量{w:upload_max_filesize:w}、{w:PHP_memory_limit:w}。变量的格式:{w:变量名:w}。添加PHP最大内存变量:PHP_memory_limit添加上传大小限制:upload_max_filesize至此,LMP应用已经制作完成,我们在应用管理列表中,选择刚才制作好的应用,点击创建服务部署完成后,地址栏输入域名访问一下,如果访问正常,说明我们制作的应用没有问题了,可以导出供他人安装!第六步:导出应用将我们制作的应用导出,可将导出的文件发布到任何地方,供他人安装使用,只要对方的主机安装了URLOS,都可以完美运行(无需考虑兼容性问题)我们制作的应用。导出的文件为txt文本。只要其他用户使用URLOS直接导即可。下面是导入方法:打开文本,全选复制其中内容登录URLOS,在左侧菜单点击导入应用,将内容粘贴进去,提交导入成功!!点击安装即可。哈哈,太爽了吧。任何服务器环境可以使用的应用都可以用这个方法来制作,比如微信小程序后端部分等等都可以这样制作,方便分发和安装。 ...

April 1, 2019 · 2 min · jiezi

基于docker, 快速搭建Nginx+Php+https本地开发环境, 免于手动安装PHP扩展

NginxPhpDocker是什么, 主要解决什么问题基于docker, 快速搭建Nginx+Php本地开发环境(已含常用PHP扩展), nginx、php配置文件,日志文件和php工程代码都在宿主机上, 方便修改.可以解决:新人加入团队, 配置LNMP麻烦, 而且是重复劳动prod, staging, local开发环境不一致, local没问题, 上了staging,prod出现各种问题php扩展安装有问题, 比如: mac电脑, 本地多个php版本, 扩展不一致(eg: memcache, memcached)项目新功能需要安装新扩展, 所有开发者都要安装一遍NginxPhpDocker github url1. 如何使用呢?1.1 download codegit clone git@github.com:weiwenwang/NginxPhpDocker.gitcd NginxPhpDocker1.2 启动php容器docker run -it -d --name myphp -v $PWD/www/php:/www/php -v $PWD/www/example:/www/example --privileged=true \wangnan188/nginx-php-docker:v7.2-v11.3 启动nginx容器docker run -it -d -p 80:80 -p 443:443 -v $PWD/nginx-conf/conf.d:/etc/nginx/conf.d -v $PWD/nginx-conf/nginx.conf:/etc/nginx/nginx.conf -v $PWD/www/html:/www/html -v $PWD/www/example:/www/example -v $PWD/ssl/server.crt:/etc/nginx/ssl/server.crt -v $PWD/ssl/server.key:/etc/nginx/ssl/server.key -v $PWD/log/nginx:/var/log/nginx/ --link=myphp:myphp_alias --privileged=true --name=mynginx nginx1.4 注意事项, 非常重要1.2, 1.3的两个指令必须在NginxPhpDocker目录下执行PHP代码的文件夹, 必须挂在到PHP容器里面, 有小伙伴使用的时候挂到nginx容器里面了, nginx和PHP俩容器是隔离的, php只会按地址在他们自己的容器里面找文件, 和nginx只是通过fastcgi通信, nginx告诉php用户请求的文件地址, php在自己的容器去找对应的文件1.5 执行1.2、1.3之后效果是什么样子的呢?3. 如何把现有的项目跑起来呢?这里我举例个例子, 假如我们现在的项目(thinkphp_3.2.3_full)就是thinkphp框架写的, 我如何把它运行起来呢? 第一步: 把代码放在www/example/目录下 第二步: 添加配置文件nginx-conf/conf.d/example-thinkphp.conf, 剩下的就是单纯的nginx配置问题了. 本地做一个host绑定: “127.0.0.1 thinkphp-full.com” 浏览器访问: http://thinkphp-full.com/inde...4. wangnan188/nginx-php-docker现在包含了哪些extension呢?extensionstatusremark-extensionstatusremark- CoreYES–redisYES–ctypeYES–gdYES–curlYES–xdebugYES–dateYES–mongodbYES–domYES–swooleYES–fileinfoYES–memcachedYES–filterYES–memcacheNO–ftpYES– hashYES– iconvYES– jsonYES– libxmlYES– mbstringYES– mysqlndYES– opensslYES– pcreYES– PDOYES– pdo_sqliteYES– PharYES– posixYES– readlineYES– ReflectionYES– sessionYES– SimpleXMLYES– sodiumYES– SPLYES– sqlite3YES– standardYES– tokenizerYES– xmlYES– xmlreaderYES– xmlwriterYES– zlibYES– 5. 其他后续php extensions有补充, 可能不能及时更新此文章, 最新版本请移步: github ...

April 1, 2019 · 1 min · jiezi

K8S 生态周报| 2019.03.25~2019.03.31

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。Kubernetes 1.14 正式发布1.14 的主要更新:对 Windows Node 和 container 的支持达到生产级别,支持 Windows Server 2019;本地持久化数据卷正式可用,这可以方便使用本地 SSD 之类的存储,但注意这个特性容错性较差;Pod 优先级和抢占机制正式可用,(建议慎重使用);Pod Ready++ (Pod Readiness Gates) 达到稳定,可以更好的判断 Pod 及其需要的资源是否均已就绪;当然还有很多的改进和很多被废弃的功能特性等,建议阅读 ReleaseNote。Minikube 1.0.0 正式发布Minikube 是一个用于本地搭建 Kubernetes 环境的工具,使用方法可参考 使用 Minikube 搭建本地 Kubernetes 环境。1.0.0 的主要更新:默认 Kubernetes 版本更新至 1.14.0;新增 –image-repository 参数,方便国内用户使用镜像解决网络问题;其他特性请阅读 ReleaseNoterunc 1.0-rc7 发布注意,低版本内核(尤其是 3.x)的系统,请不要升级至此版本这个版本主要为解决之前的漏洞及修正一些规范等,版本说明请参考 runc 1.0-rc7 发布之际。其他特性请阅读 ReleaseNoteBrigade 1.0 正式发布Brigade 是一个使用 JavaScript 来为 Kubernetes 构建 pipeline 的工具,现在是 CNCF 的 sandbox 项目。详细内容请阅读 ReleaseNoteKind 0.2.1 发布Kind 是 Kubernetes In Docker 的缩写,是一款便于在本地和 CI 环境中进行 Kubernetes 环境搭建的工具,具体用法请参考 使用 Kind 搭建你的本地 Kubernetes 集群0.2.1 是 kind 的首个 patch 版本,主要为了修复一个偶发的 panic , 建议尽快升级。可以通过下面二维码订阅我的文章公众号【MoeLove】 ...

April 1, 2019 · 1 min · jiezi

runc 1.0-rc7 发布之际

在 18 年 11 月底时,我写了一篇文章 《runc 1.0-rc6 发布之际》 。如果你还不了解 runc 是什么,以及如何使用它,请参考我那篇文章。本文中,不再对其概念和用法等进行说明。在 runc 1.0-rc6 发布之时,给版本的别名为 “For Real This Time”,当时我们原定计划是发布 1.0 的,但是作为基础依赖软件,我们认为当时的版本还有几个问题:不够规范;发布周期不明确;为了给相关的 runtime 足够的时间进行修正/升级,以及规范版本生命周期等,最终决定了发布 runc 1.0-rc6。为何有 runc 1.0-rc7 存在前面已经基本介绍了相关背景,并且也基本明确了 rc6 就是在 1.0 正式发布之前的最后一个版本,那 rc7 为什么会出现呢?CVE-2019-5736我们首先要介绍今年 runc 的一个提权漏洞 CVE-2019-5736 。2019 年 2 月 11 日在 oss-security 邮件组正式批露该漏洞,攻击者可以利用恶意容器覆盖主机上的 runc 文件,从而达到攻击的目的;(具体的攻击方式此处略过),注意不要轻易使用来源不可信的镜像创建容器便可有效避免被攻击的可能。简单补充下可能被攻击的方式:运行恶意的 Docker 镜像在主机上执行 docker exec 进入容器内关于容器安全或者容器的运行机制,其实涉及的点很多,我在去年的一次线上分享 《基于 GitLab 的 CI 实践》 有提到过 Linux Security Modules(LSM)等相关的内容,对容器安全感兴趣的朋友可以对 LSM 多了解下。不过本文主要看的是 runc 如何修复该漏洞的,以及后续产生的影响。修复方式// 对 memfd_create 系统调用做了个封装 省略部分代码#if !defined(SYS_memfd_create) && defined(__NR_memfd_create)# define SYS_memfd_create __NR_memfd_create#endif#ifdef SYS_memfd_create# define HAVE_MEMFD_CREATE# ifndef MFD_CLOEXEC# define MFD_CLOEXEC 0x0001U# define MFD_ALLOW_SEALING 0x0002U# endifint memfd_create(const char *name, unsigned int flags){ return syscall(SYS_memfd_create, name, flags);}// 一个简单的只读缓存区static char *read_file(char *path, size_t *length){ int fd; char buf[4096], *copy = NULL; if (!length) return NULL; fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) return NULL; *length = 0; for (;;) { int n; n = read(fd, buf, sizeof(buf)); if (n < 0) goto error; if (!n) break; copy = must_realloc(copy, (*length + n) * sizeof(*copy)); memcpy(copy + *length, buf, n); *length += n; } close(fd); return copy;error: close(fd); free(copy); return NULL;}// 将复制后的 fd 重赋值/执行static int clone_binary(void){ int binfd, memfd; ssize_t sent = 0;#ifdef HAVE_MEMFD_CREATE memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);#else memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);#endif if (memfd < 0) return -ENOTRECOVERABLE; binfd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC); if (binfd < 0) goto error; sent = sendfile(memfd, binfd, NULL, RUNC_SENDFILE_MAX); close(binfd); if (sent < 0) goto error;#ifdef HAVE_MEMFD_CREATE int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS); if (err < 0) goto error;#else int newfd; char *fdpath = NULL; if (asprintf(&fdpath, “/proc/self/fd/%d”, memfd) < 0) goto error; newfd = open(fdpath, O_RDONLY | O_CLOEXEC); free(fdpath); if (newfd < 0) goto error; close(memfd); memfd = newfd;#endif return memfd;error: close(memfd); return -EIO;}int ensure_cloned_binary(void){ int execfd; char **argv = NULL, **envp = NULL; int cloned = is_self_cloned(); if (cloned > 0 || cloned == -ENOTRECOVERABLE) return cloned; if (fetchve(&argv, &envp) < 0) return -EINVAL; execfd = clone_binary(); if (execfd < 0) return -EIO; fexecve(execfd, argv, envp); return -ENOEXEC;}省略掉了部分代码,完整代码可直接参考 runc 代码仓库 。整个的修复逻辑我在上面的代码中加了备注,总结来讲其实就是:创建了一个只存在于内存中的 memfd ;将原本的 runc 拷贝至这个 memfd ;在进入 namespace 前,通过这个 memfd 重新执行 runc ; (这是为了确保之后即使被攻击/替换也操作的还是内存中的这个只读的 runc)经过以上的操作,就基本修复了 CVE-2019-5736 。影响内核相关在上面讲完修复方式后,我们来看下会产生哪些影响。涉及到了系统调用 memfd_create(2) 和 fcntl(2)增加了系统调用,那自然就要看内核是否支持了。实际上,这些函数是在 2015 年 2 月(距这次修复整整 4 年,也挺有趣)被加入到 Linux 3.17 内核中的。换句话说就是 凡是在此内核版本之前的系统,均无法正常使用该功能,对我们的影响就是,如果你在此版本内核之前的机器上使用了包含上述修复代码的 runc 或构建在其之上的 containerd、 Docker 等都无法正常工作 。 以 Docker 举例:安装 docker-ce-18.09.2 或 docker-ce-18.06.3 可避免受 CVE-2019-5736 影响,但如果内核版本较低,在运行容器时可能会有如下情况出现: (不同版本/内核可能出现其他情况)[tao@moelove ~]# docker run –rm my-registry/os/debian echo Hello docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting containerprocess caused “process_linux.go:293: copying bootstrap data to pipe caused "write init-p: broken pipe"”: unknown.解决办法升级内核;这是最直接的办法,而且使用一个新版本的内核也能省去很多不必要的麻烦:)rancher 提供了一个 runc-cve 的 patch,可兼容部分 3.x 内核的系统(我没有测试过)如果你不升级 runc/containerd/Docker 等版本的话,那建议你 1. 将 runc 可执行程序放到只读文件系统上,可避免被覆盖;2. 启动容器时,启用 SELinux; 3. 在容器内使用低权限用户或者采用映射的方式,但保证用户对主机上的 runc 程序无写权限。注意: memfd_create 等相关系统调用,也被加入到了 Debian 3.16 和 Ubuntu 14.04 updates 中,当然也被反向移植到了 CentOS 7.3 内核 3.10.0-514 版本之后。 (Red Hat 给 CentOS 7.x 的 3.10 内核上反向移植了很多特性)内存相关从上面的说明中,也很容易可以看到, 内存的使用上会有所增加,不过之后已做了修复。这里不再进行展开。其他偶尔可能触发一些内核 bug 之类的(总之建议升级 :)等待 rc8 发布上面已经介绍了 1.0-rc7 出现的主要原因 CVE-2019-5736;当然这个版本中也有一些新特性和一些 bugfix 不过不是本文的主要内容,不再赘述。值得一提的是这次的版本命名:runc 1.0-rc7 – “The Eleventh Hour” 后面这个别名其实来自于一部英剧,感兴趣也可以去看看。至于下个版本是不是会是 1.0 正式版呢?目前来看应该不是,有极大可能会发布 runc 1.0-rc8 做一些 bugfix,让我们拭目以待。可以通过下面二维码订阅我的文章公众号【MoeLove】 ...

March 31, 2019 · 3 min · jiezi

使用 Kind 搭建你的本地 Kubernetes 集群

Kind 是我很喜欢也一直在参与的项目,我计划将 Kind 相关的文章写成一个系列。(flag++) 这是第一篇。Kind 介绍Kind 是 Kubernetes In Docker 的缩写,顾名思义是使用 Docker 容器作为 Node 并将 Kubernetes 部署至其中的一个工具。官方文档中也把 Kind 作为一种本地集群搭建的工具进行推荐。安装二进制安装Kind 使用 Golang 进行开发,在仓库的 Release 页面,已经上传了构建好的二进制,支持多种操作系统,可直接按需下载进行使用。e.g.# 下载最新的 0.2.0 版本wget -O /usr/local/bin/kind https://github.com/kubernetes-sigs/kind/releases/download/0.2.0/kind-linux-amd64 && chmod +x /usr/local/bin/kind通过源码安装如果你本地已经配置好了 Golang 的开发环境,那你可以直接通过源码进行安装。e.g.go get -u sigs.k8s.io/kind运行完上述命令后,会将 kind 的可执行文件放到 $(go env GOPATH)/bin 文件夹内,你可能需要将此目录加入到 $PATH 中。或者也可以先 clone 源代码再通过 go build 进行构建。依赖Kind 的主要功能目前需要有 Docker 环境的支持,可参考 Docker 官方文档进行安装。如果需要操作集群,则需要安装 kubectl 命令行。安装方法可参考官方文档搭建单节点集群以下的演示均使用最新的代码(即通过源码安装)。基础用法搭建单节点集群是 Kind 最基础的功能。e.g.master $ kind create cluster –name moeloveCreating cluster “moelove” … ✓ Ensuring node image (kindest/node:v1.13.4) ???? ✓ Preparing nodes ???? ✓ Creating kubeadm config ???? ✓ Starting control-plane ????️Cluster creation complete. You can now use the cluster with:export KUBECONFIG="$(kind get kubeconfig-path –name=“moelove”)“kubectl cluster-info以上命令中, –name 是可选参数,如不指定,默认创建出来的集群名字为 kind。我们根据命令执行完的输出进行操作:master $ export KUBECONFIG="$(kind get kubeconfig-path –name=“moelove”)“master $ kubectl cluster-infoKubernetes master is running at https://localhost:34458KubeDNS is running at https://localhost:34458/api/v1/namespaces/kube-system/services/kube-dns:dns/proxyTo further debug and diagnose cluster problems, use ‘kubectl cluster-info dump’.master $ kubectl get nodesNAME STATUS ROLES AGE VERSIONmoelove-control-plane Ready master 2m v1.13.4以上命令中,kind get kubeconfig-path –name=“moelove” 会返回该指定集群配置文件所在的路径。可以看到单节点的 Kubernetes 已经搭建成功。注意默认情况下,Kind 会先下载 kindest/node:v1.13.4 镜像,该镜像目前托管于 Docker Hub 上,下载时间取决于网络状况。Kind 实际使用 kubeadm 进行集群的创建,对 kubeadm 有所了解的人都知道它默认使用的镜像在国内下载不到,所以需要自己解决网络问题。或者参考下面的方式:Kind 在创建集群的时候,支持通过 –config 的参数传递配置文件给 Kind,在国内,我们可以通过使用国内镜像源的方式来加速集群的创建。(这个方法也适用于直接通过 kubeadm 搭建 Kubernetes 集群)我们先通过以下命令删除刚才搭建的集群:master $ kind delete cluster –name moeloveDeleting cluster “moelove” …$KUBECONFIG is still set to use /root/.kube/kind-config-moelove even though that file has been deleted, remember to unset it接下来,将下面的配置内容保存至一个 YAML 文件中,比如名为 kind-config.yamlkind: ClusterapiVersion: kind.sigs.k8s.io/v1alpha3kubeadmConfigPatches:- | apiVersion: kubeadm.k8s.io/v1beta1 kind: ClusterConfiguration metadata: name: config networking: serviceSubnet: 10.0.0.0/16 imageRepository: registry.aliyuncs.com/google_containers nodeRegistration: kubeletExtraArgs: pod-infra-container-image: registry.aliyuncs.com/google_containers/pause:3.1- | apiVersion: kubeadm.k8s.io/v1beta1 kind: InitConfiguration metadata: name: config networking: serviceSubnet: 10.0.0.0/16 imageRepository: registry.aliyuncs.com/google_containersnodes:- role: control-plane我们使用该配置文件搭建集群。master $ kind create cluster –name moelove –config kind.yamlCreating cluster “moelove” … ✓ Ensuring node image (kindest/node:v1.13.4) ???? ✓ Preparing nodes ???? ✓ Creating kubeadm config ???? ✓ Starting control-plane ????️Cluster creation complete. You can now use the cluster with:export KUBECONFIG="$(kind get kubeconfig-path –name=“moelove”)“kubectl cluster-info上面通过 –config 将我们的配置文件传递给 Kind 用于搭建集群,推荐国内用户使用这种方式。搭建高可用集群Kind 也支持搭建高可用的 K8S 集群,不过只能通过配置文件来实现。可以直接将下面的内容保存至文件中,再将配置文件传递给 Kind 即可。e.g.kind: ClusterapiVersion: kind.sigs.k8s.io/v1alpha3kubeadmConfigPatches:- | apiVersion: kubeadm.k8s.io/v1beta1 kind: ClusterConfiguration metadata: name: config networking: serviceSubnet: 10.0.0.0/16 imageRepository: registry.aliyuncs.com/google_containers nodeRegistration: kubeletExtraArgs: pod-infra-container-image: registry.aliyuncs.com/google_containers/pause:3.1- | apiVersion: kubeadm.k8s.io/v1beta1 kind: InitConfiguration metadata: name: config networking: serviceSubnet: 10.0.0.0/16 imageRepository: registry.aliyuncs.com/google_containersnodes:- role: control-plane- role: control-plane- role: control-plane- role: worker- role: worker- role: worker我们使用以下的命令来搭建高可用的 Kubernetes 集群:master $ kind create cluster –name moelove-ha –config kind-ha-config.yamlCreating cluster “moelove-ha” … ✓ Ensuring node image (kindest/node:v1.13.4) ???? ✓ Preparing nodes ???????????????????????????? ✓ Starting the external load balancer ⚖️ ✓ Creating kubeadm config ???? ✓ Starting control-plane ????️ ✓ Joining more control-plane nodes ???? ✓ Joining worker nodes ????Cluster creation complete. You can now use the cluster with:export KUBECONFIG="$(kind get kubeconfig-path –name=“moelove-ha”)“kubectl cluster-infomaster $ export KUBECONFIG="$(kind get kubeconfig-path –name=“moelove-ha”)“master $ kubectl cluster-infoKubernetes master is running at https://localhost:44019KubeDNS is running at https://localhost:44019/api/v1/namespaces/kube-system/services/kube-dns:dns/proxyTo further debug and diagnose cluster problems, use ‘kubectl cluster-info dump’.可以做下简单的验证:master $ kubectl get nodesNAME STATUS ROLES AGE VERSIONmoelove-ha-control-plane Ready master 3m42s v1.13.4moelove-ha-control-plane2 Ready master 3m24s v1.13.4moelove-ha-control-plane3 Ready master 2m13s v1.13.4moelove-ha-worker Ready <none> 96s v1.13.4moelove-ha-worker2 Ready <none> 98s v1.13.4moelove-ha-worker3 Ready <none> 95s v1.13.4可以看到已经成功创建了多 master 的 Kubernetes 集群。总结这是使用 Kind 搭建本地 Kubernetes 集群的第一篇,同时本篇的内容也是《Kubernetes 从上手到实践》第 4 节内容的补充,搭配食用效果更佳 :)可以通过下面二维码订阅我的文章公众号【MoeLove】 ...

March 31, 2019 · 3 min · jiezi

docker提供api访问

docker提供api访问 环境centosvim /etc/docker/daemon.json添加如下配置{ “hosts”: [ “tcp://0.0.0.0:2375”, “unix:///var/run/docker.sock” ]}添加deamon.json后dockerd命令可以启动docker这时请求 127.0.0.1:2375 可以正常访问使用systemctl无法启动docker的情况systemctl restart dockersystemctl start docker 无法启动docker查看当前的docker配置systemctl cat docker | grep ExecExecStart=/usr/bin/dockerd -H fd://ExecReload=/bin/kill -s HUP $MAINPID覆盖配置systemctl edit docker添加[Service]ExecStart=ExecStart=/usr/bin/dockerd再次查看配置systemctl cat docker | grep ExecExecStart=/usr/bin/dockerd -H fd://ExecReload=/bin/kill -s HUP $MAINPIDExecStart=ExecStart=/usr/bin/dockerd可以使用systemctl命令启动docker参考地址: https://github.com/docker/for…

March 29, 2019 · 1 min · jiezi