Istio

Istio官网
Istio中文官网
Istio开源
无需太多介绍Service Mesh明日之星,扛把子,截止2019.11还有太多问题没解决
复杂性,性能让人望而却步,能上生产的是真要技术厉害,还得内心强大,项目允许

Linkerd

Linkerd官网
Linkerd中文官网

A service mesh for Kubernetes and beyond. Main repo for Linkerd 2.x.
Linkerd is a service mesh, designed to give platform-wide observability, reliability, and security without requiring configuration or code changes.

Linkerd is a Cloud Native Computing Foundation (CNCF) project.

Maesh

Maesh官网
Maesh开源

Containous(Traefik 团队)推出了全新设计的轻量级 service mesh(服务网格)工具:Maesh,Maesh 允许对 Kubernetes 集群内流动的流量进行管理,这与入流量和出流量同样很重要。
Maesh 构建在 Traefk 之上,是一个简单但功能齐全的服务网格,支持最新的服务网格接口规范 SMI,有助于与现有的一些解决方案进行集成。此外,Maesh 默认是需要开启使用的,这意味着在你决定将它们添加到网格之前,你的现有服务不会受到影响。

比较喜欢用go语言编写的东西,毕竟CNCF中绝大多数项目都是go语言编写的,看后续走向

Consul

Consul官网
Consul开源

Secure Service Networking
Consul is a service networking solution to connect and secure services across any runtime platform and public or private cloud

consul原本是个分布式kv,可以用来做配置中心,注册中心,现在官方默认的宣传语都改成了连接和保护服务

定位服务发现(Service discovery)和 服务网格(Service Mesh)

Envoy

Envoy官网
Envoy开源
ENVOY IS AN OPEN SOURCE EDGE AND SERVICE PROXY, DESIGNED FOR CLOUD-NATIVE APPLICATIONS
ENVOY是开放源代码边缘和服务代理,专为云应用程序而设计

envoy作为服务网格中的通用数据平面, xDS API 已经成为数据平面API接口的实施标准
就好像AWS的OSS对象存储中的S3一样,成了事实标准

SOFAMson

SOFAMson官网
SOFAMson开源

SOFAMson 是一款使用 Go 语言开发的 Service Mesh 数据平面代理,旨在为服务提供分布式、模块化、可观察和智能化的代理能力。SOFAMosn 是 SOFAStack 中的一个项目,其中 MOSN 是 Modular Observable Smart Network 的简称。SOFAMosn 可以与任何支持 xDS API 的 Service Mesh 集成,亦可以作为独立的四、七层负载均衡使用。未来 SOFAMosn 将支持更多云原生场景,并支持 Nginx 的核心转发功能。

目前蚂蚁金服有大规模落地,2019年的双十一已经做了生产实践
API接口方面也是兼容Envoy的 xDS API 标准

背景

Go程序运行时打印git提交信息编译信息
Golang编译信息注入程序
当在debug的过程中,我们需要明确当前运行的go程序是什么版本
不要浪费时间在确认版本的问题上
在go build编译的时候是可以注入外部参数的
让go程序在运行的时候就可以打印编译时候的参数情况

以gitlab-runner为例

gitlab-runner -v
Version:      11.10.1
Git revision: 1f513601
Git branch:   11-10-stable
GO version:   go1.8.7
Built:        2019-04-24T09:29:18+0000
OS/Arch:      linux/amd64

最终实现的go程序运行时终端打印的信息如下

App Name:       app-api
App Version:    v2.0.1
Build version:  84d4ffb verdor
Build time:     2019-08-06T09:58:48+0800
Git revision:   84d4ffb
Git branch:     master
Golang Version: go version go1.12.2 linux/amd64
2019-07-24 10:53:34.732 11516: http server started listening on [:20000]

具体实现

入口文件
main.go

package main

import (
    "fmt"
)

var (
    AppName      string // 应用名称
    AppVersion   string // 应用版本
    BuildVersion string // 编译版本
    BuildTime    string // 编译时间
    GitRevision  string // Git版本
    GitBranch    string // Git分支
    GoVersion    string // Golang信息
)


func main() {
    Version()
    // 你的业务代码入口
}

// Version 版本信息
func Version() {
    fmt.Printf("App Name:\t%s\n", AppName)
    fmt.Printf("App Version:\t%s\n", AppVersion)
    fmt.Printf("Build version:\t%s\n", BuildVersion)
    fmt.Printf("Build time:\t%s\n", BuildTime)
    fmt.Printf("Git revision:\t%s\n", GitRevision)
    fmt.Printf("Git branch:\t%s\n", GitBranch)
    fmt.Printf("Golang Version: %s\n", GoVersion)
}

build编译构建脚本
build.sh

#!/bin/bash

set -e

PROJECT_NAME="app-api"
BINARY="app-api"

OUTPUT_DIR=output
GOOS=$(go env GOOS)

APP_NAME=${PROJECT_NAME}
APP_VERSION=$(git log -1 --oneline)
BUILD_VERSION=$(git log -1 --oneline)
BUILD_TIME=$(date "+%FT%T%z")
GIT_REVISION=$(git rev-parse --short HEAD)
GIT_BRANCH=$(git name-rev --name-only HEAD)
GO_VERSION=$(go version)

CGO_ENABLED=0 go build -a -installsuffix cgo -v -mod=vendor \
-ldflags "-s -X 'main.AppName=${APP_NAME}' \
            -X 'main.AppVersion=${APP_VERSION}' \
            -X 'main.BuildVersion=${BUILD_VERSION}' \
            -X 'main.BuildTime=${BUILD_TIME}' \
            -X 'main.GitRevision=${GIT_REVISION}' \
            -X 'main.GitBranch=${GIT_BRANCH}' \
            -X 'main.GoVersion=${GO_VERSION}'" \
-o ${OUTPUT_DIR}/${BINARY} cmd/${BINARY}.go

本质上是用 -ldflags 参数注入了的外部参数到go的变量当中
go的更多build参数帮助可以通过 go help build获取

问答

Q: 开发环境是windows,没有bash环境怎么办?
A: 都装了git的吧,那么用Git Bash终端是支持的

副标
Dockerize your Vue Application
dockerfile Vue example
docker Vue example
Vue应用docker容器化打包

docker忽略文件

.dockerignore

node_modules

www.conf

server {
    listen 80;
    #listen [::]:80;
    listen 443 ssl http2;
    #listen [::]:443 ssl http2;

    server_name h5.iamle.com web-app-h5;

    ssl_certificate      /etc/nginx/ssl/star.iamle.com.crt;
    ssl_certificate_key  /etc/nginx/ssl/star.iamle.com.key;
    #ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;
    ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers          HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass http://${API_HOST_BASE};
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    }
}

Dockerfile

# 构建阶段 vue build stage
FROM node:10.16.0-alpine  AS build-stage-node

## 配置 apk包加速镜像为阿里
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

## 安装 一些基础包
RUN apk update \
  && apk upgrade \
  && apk add git \
  && apk add bash \
  #&& apk add nghttp2-dev \
  && apk add ca-certificates \
  && apk add wget \
  #&& apk add curl \
  #&& apk add tcpdump \
  && apk add iputils \
  && apk add iproute2 \
  && apk add libc6-compat \
  && apk add -U tzdata \
  && rm -rf /var/cache/apk/*

# ## 设置 操作系统时区
# RUN rm -rf /etc/localtime \
#   && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 设置 工作目录
ENV MY_HOME=/app
RUN mkdir -p $MY_HOME
WORKDIR $MY_HOME

## 安装 全局依赖
# RUN npm install -g express

# 安装 项目依赖
COPY package.json ./
RUN npm config set registry https://registry.npm.taobao.org \
  && npm set sass_binary_site=https://npm.taobao.org/mirrors/node-sass/ \
  && npm install

# 复制vue项目文件
COPY . .

# 构建
RUN npm run build

RUN ls -lsah /app

# 打包应用
# 生产阶段 nginx
# 使用nginx镜像运行构建物
FROM nginx:stable-alpine
COPY --from=build-stage-node /app/dist /var/www/html
RUN ls -lsha /var/www/html
COPY ./www.conf /etc/nginx/conf.d/
RUN rm /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx","-g","daemon off;"]

副标
Dockerize your Python Application
dockerfile python example
dockerfile python flask example

flask框架为例

Dockerfile

FROM alpine:latest

# 打标签
LABEL version="1.0" \
    description="alpine:latest" \
    maintainer="wwek<licoolgo@gmail.com>"

# 配置apk包加速镜像为阿里
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# 安装一些基础包
RUN apk update \
    && apk upgrade \
    && apk add s6 \
    && apk add bash \
    # && apk add nghttp2-dev \
    && apk add ca-certificates \
    && apk add wget \
    # && apk add curl \
    # && apk add tcpdump \
    # && apk add bash-completion \
    && apk add iputils \
    && apk add iproute2 \
    && apk add libc6-compat \
    && apk add -U tzdata \
    && rm -rf /var/cache/apk/*

# 设置 操作系统时区
RUN rm -rf /etc/localtime \
 && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 设置时区变量
ENV TIME_ZONE Asia/Shanghai

# 安装 python3、升级pip、setuptools
RUN apk add --no-cache python3 \
    #&& apk add --no-cache python3-dev \
    && python3 -m ensurepip \
    && rm -r /usr/lib/python*/ensurepip \
    && pip3 install --default-timeout=100 --no-cache-dir --upgrade pip \
    && pip3 install --default-timeout=100 --no-cache-dir --upgrade setuptools \
    && if [ ! -e /usr/bin/pip ]; then ln -s pip3 /usr/bin/pip ; fi \
    && if [[ ! -e /usr/bin/python ]]; then ln -sf /usr/bin/python3 /usr/bin/python; fi \
    && rm -rf /var/cache/apk/* \
    && rm -rf ~/.cache/pip

# 设置 语言支持
ENV LANG=C.UTF-8

# 配置 应用工作目录
WORKDIR /data/apps/appdir

# 增加 项目文件
ADD appmain.py ./
ADD 你的py文件2.py ./
ADD 目录1 ./
ADD requirements.txt ./

# 安装 项目依赖包
RUN pip install -r requirements.txt

# 配置 对外端口
EXPOSE 11000

# 设置启动时预期的命令参数, 可以被 docker run 的参数覆盖掉.
CMD ["python", "appmain.py"]

1. CoreDNS 是什么

img
CoreDNS官网
CoreDNS开源

CoreDNS是Golang编写的一个插件式DNS服务器,是Kubernetes 1.13 后所内置的默认DNS服务器
采用的开源协议为Apache License Version 2
CoreDNS也是CNCF孵化项目,目前已经从CNCF毕业。
CoreDNS 的目标是成为 Cloud Native(云原生)环境下的 DNS 服务器和服务发现解决方案。
你被爬虫啦,原文去https://www.iamle.com看
官方口号
CoreDNS: DNS and Service Discovery
DNS和服务发现

2. CoreDNS功能特性

2.1 插件化(Plugins)

CoreDNS插件链。 每个插件都执行DNS功能,例如Kubernetes服务发现,Prometheus指标或重写查询。
还有非常多的其他插件,插件是CoreDNS核心理念就是插件化

简单(Simplicity)

努力把配置文件变得简单
采用了Caddy中的DSL配置方案,即 Corefile 形式的配置文件
一个最简单的配置文件可以为:

.{}

2.2 服务发现 (Service Discovery)

核心域名系统通过Kubernetes插件与Kubernetes集成,或者通过etcd插件直接与etcd集成。
还有redis插件等

快速和弹性 ( Fast and Flexible)

我们的目标是使CoreDNS快速高效。 它的插件也很灵活。 您可以只使用所需的插件编译CoreDNS。

3. 配置一个内网自定义的服务化域名

假设需要在内网实现
sms.service A记录 10.6.6.2
search.service A记录 10.6.6.3
你被爬虫啦,原文去https://www.iamle.com看
我们为CoreDNS手动增加解析记录
那么Corefile配置文件为
/etc/coredns/Corefile

.:53 {
  # 绑定interface ip
  bind 127.0.0.1
  # 先走本机的hosts
  # https://coredns.io/plugins/hosts/
  hosts {
    # 自定义sms.service search.service 的解析
    # 因为解析的域名少我们这里直接用hosts插件即可完成需求
    # 如果有大量自定义域名解析那么建议用file插件使用 符合RFC 1035规范的DNS解析配置文件
    10.6.6.2 sms.service
    10.6.6.3 search.service
    # ttl
    ttl 60
    # 重载hosts配置
    reload 1m
    # 继续执行
    fallthrough
  }
  # file enables serving zone data from an RFC 1035-style master file.
  # https://coredns.io/plugins/file/
  # file service.signed service
  # 最后所有的都转发到系统配置的上游dns服务器去解析
  forward . /etc/resolv.conf
  # 缓存时间ttl
  cache 120
  # 自动加载配置文件的间隔时间
  reload 6s
  # 输出日志
  log
  # 输出错误
  errors
}

运行CoreDNS

coredns -conf ./Corefile

dig测试CoreDNS的自定义dns解析

dig @127.0.0.1  sms.service

; <<>> DiG 9.10.6 <<>> @127.0.0.1 sms.service
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18343
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;sms.service.           IN  A

;; ANSWER SECTION:
sms.service.        120 IN  A   10.6.6.2

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed May 01 22:23:51 CST 2019
;; MSG SIZE  rcvd: 67

可以看到 sms.service 的A记录已经为10.6.6.2

更多配置探索参考CoreDNS官方手册

4. 部署

这里可以找到基于k8s,基于systemd的部署文件参考
CoreDNS部署参考

安装

wget https://github.com/coredns/coredns/releases/download/v1.5.0/coredns_1.5.0_linux_amd64.tgz
tar zxf coredns_1.5.0_linux_amd64.tgz -C /usr/bin/

增加运行账户

useradd coredns -s /sbin/nologin

systemd的coredns配置文件
/usr/lib/systemd/system/coredns.service

[Unit]
Description=CoreDNS DNS server
Documentation=https://coredns.io
After=network.target

[Service]
PermissionsStartOnly=true
LimitNOFILE=1048576
LimitNPROC=512
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
User=coredns
WorkingDirectory=~
ExecStart=/usr/bin/coredns -conf=/etc/coredns/Corefile
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target
systemctl enable coredns
systemctl start coredns
systemctl status coredns

实际上CoreDNS编译出来的是一个单二进制文件
二进制文件+配置文件就能跑了,部署起来非常简单

5. 参考

CoreDNS 使用与架构分析

1. Flink开发环境安装

1.1 前置安装

开发工具IDEA
Docker环境(Flink平台运行在docker中)
jdk支持
Maven支持
netcat支持

jdk,Maven推荐OSX用brew安装,Windows用Chocolatey安装
netcat在Windows上用Chocolatey安装,命令为”choco install netcat”

1.1 docker-compose 安装flink

docker-compose.yml

version: "2.1"
services:
  jobmanager:
    image: flink
    expose:
      - "6123"
    ports:
      - "8081:8081"
    command: jobmanager
    environment:
      - JOB_MANAGER_RPC_ADDRESS=jobmanager

  taskmanager:
    image: flink
    expose:
      - "6121"
      - "6122"
    depends_on:
      - jobmanager
    command: taskmanager
    links:
      - "jobmanager:jobmanager"
    environment:
      - JOB_MANAGER_RPC_ADDRESS=jobmanager

运行

docker-compose up -d

浏览器打开 http://127.0.0.1:8081 可以看到dashboard

2. 编写一个简单的流处理 job

假设这个job项目名称为helloword
这个job用nc程序监听一个tcp服务,使其可以输入文本流
计算单词出现次数

2.1 Maven 初始化项目

mvn archetype:generate \
      -DarchetypeGroupId=org.apache.flink \
      -DarchetypeArtifactId=flink-quickstart-java \
      -DarchetypeVersion=1.7.2

设建立的项目
groupId为com.iamle.flink
artifactId为helloword

如果是 Windows,建议使用 Git Bash 终端执行mvn

2.2 IDEA打开helloword

删除自动生成的 BatchJob.java、StreamingJob.java
新建SocketWindowWordCount.java

package com.iamle.flink;

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;

public class SocketWindowWordCount {

    public static void main(String[] args) throws Exception {

        // 输入tcp流
        final int port;
        final String host;
        port = 9008; // nc监听的tcp端口
        host = "192.168.0.8"; // docker宿主机ip

        // get the execution environment
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // get input data by connecting to the socket
        DataStream<String> text = env.socketTextStream(host, port, "\n");

        // parse the data, group it, window it, and aggregate the counts
        DataStream<WordWithCount> windowCounts = text
                .flatMap(new FlatMapFunction<String, WordWithCount>() {
                    @Override
                    public void flatMap(String value, Collector<WordWithCount> out) {
                        for (String word : value.split("\\s")) {
                            out.collect(new WordWithCount(word, 1L));
                        }
                    }
                })
                .keyBy("word")
                .timeWindow(Time.seconds(5), Time.seconds(1))
                .reduce(new ReduceFunction<WordWithCount>() {
                    @Override
                    public WordWithCount reduce(WordWithCount a, WordWithCount b) {
                        return new WordWithCount(a.word, a.count + b.count);
                    }
                });

        // print the results with a single thread, rather than in parallel
        windowCounts.print().setParallelism(1);

        env.execute("Socket Window WordCount");
    }

    // Data type for words with count
    public static class WordWithCount {

        public String word;
        public long count;

        public WordWithCount() {}

        public WordWithCount(String word, long count) {
            this.word = word;
            this.count = count;
        }

        @Override
        public String toString() {
            return word + " : " + count;
        }
    }
}

pom.xml 入口类
com.iamle.flink.StreamingJob 改为
com.iamle.flink.SocketWindowWordCount

2.3 编译项目jar

cd  helloword
mvn clean package

在项目中的target目录中得到 helloword-1.0-SNAPSHOT-shaded.jar

3. 提交job

先运行流的输入服务

nc -l 9008
# nc -l -p 9008 # windows

方式1
打开 http://127.0.0.1:8081/#/submit dashboard后
在Submit new job中上传helloword-1.0-SNAPSHOT-shaded.jar
upload后>勾选>Submit

在nc终端,随便输入一些字符串后回车
在名为taskmanager的docker实例标准终端中可以看到计算结果(可以用kitematic打开docker容器实例查看其标准终端)

4. 官方示例

flink官方示例