如何为K8S生产系统配置安全管理?

Portworx阅读(1765)评论(0)

PX-Security:针对Kubernetes持久卷的多租户授权、身份验证和RBAC
PX-Security演示视频链接 https://v.qq.com/x/page/s30609pfmuq.html
安全对于企业来说至关重要,对于运行在Kubernetes上的基于微服务的应用来说更是如此。Kubernetes提供RBAC授权,根据不同角色设定,管理Kubernetes内部特定资源的访问权限。这些机制对于管理Kubernetes的特定对象(如服务、命名空间、配额等)的访问权限非常有用。但命名空间和pod的安全策略本身,不足以限制谁有权限可以请求更改底层数据管理系统。许多企业通过CNI或CSI等API,调用其他的平台能力来提供网络和存储基础。Kubernetes所缺乏的是将RBAC扩展到这些系统的能力,需要外部系统来确保授权和认证功能的实现。这就是为什么Portworx与Kubernetes携手,通过对支撑Kubernetes中PVCs的持久卷,进行访问角色控制,来提供RBAC、加密和控制权限,这将创建一个无缝的保护层,为您的PVCs提供以下保护:

1.     同一命名空间中的用户可以受到其角色的限制,比如他们可以具有读、写、管理员或其他定义的访问权限。

2.     用户可以通过Token自动进行身份验证,这样审计请求的授权就可以针对特定命名空间来进行。

3.     可以将用户置于基于租户的命名空间中,从而为访问PVCs提供安全的多租户。

4.     即使用户看到存储类,也不意味着他们被授权创建PVC。

5.     将Portworx RBAC与加密一起使用,意味着数据在host上是安全的,命名空间内的非授权用户不能访问数据。

6.     如果一个请求来自Kubernetes外部而没有Token,它将被阻止。

要深入了解Portworx能为您的Kubernetes平台提供什么,可以查看Portworx网站上的安全参考体系架构。我们将重点讨论一些主题,比如如何设置PX-Security,以及如何使用Token对具有相应持久卷访问权限的角色用户进行身份验证。

首先,Portworx通过使用Token支持RBAC。在本文中,PX-Security将使用存储在Kubernetes Secrets中的Token,这些Token提供了最灵活的操作,且不牺牲任何安全性。

开始吧!在我们讨论什么是Token以及如何使用它之前,有一点需要注意,对Portworx的每个请求都是使用存储在Token中的信息进行身份验证和授权的。其中包含关于用户及其角色所需所有相关的验证和签名的信息。因此,我们配置了PX-Security后,我们会创建Token。

让我们来配置PX-Security来达到安全性。请访问 https://central.portworx.com,

点击安装并运行。填写安装程序要求的信息,完成后下载你的YAML文件,将文件保存以便后续做编辑。

接下来,我们将创建用于PX-Security的安全共享的Secrets。我们必须首先创建这些共享的Secrets,因为存储管理员将使用它们来生成和验证Token。出于安全原因,这些数据被存储在Kube-system命名空间中的Kubernetes Secrets中,只有少量的管理员和应用程序可以访问该命名空间。

PORTWORX_AUTH_SYSTEM_KEY=$(cat /dev/urandom | base64 | fold -w 65 | head -n 1)
PORTWORX_AUTH_STORK_KEY=$(cat /dev/urandom | base64 | fold -w 64 | head -n 1)
PORTWORX_AUTH_SHARED_SECRET=$(cat /dev/urandom | base64 | fold -w 64 | head -n 1)

运行以下命令将这些值放入Kubernetes Secret中:

kubectl -n kube-system create secret generic pxkeys \
    --from-literal=system-secret=$PORTWORX_AUTH_SYSTEM_KEY \
    --from-literal=stork-secret=$PORTWORX_AUTH_STORK_KEY \
    --from-literal=shared-secret=$PORTWORX_AUTH_SHARED_SECRET

您可以使用以下命令测试Kubernetes中的共享-secret。

kubectl -n kube-system get secret pxkeys -o json | jq -r '.data."shared-secret"' | base64 -d

打开您的YAML文件,找到PortworxDaemonset,可以看args, 在image:portworx/oci-monitor下。这里我们将添加安全参数(粗体)和PX-Security需要的Secrets:

        - name: portworx
          image: portworx/oci-monitor:2.1.5
          imagePullPolicy: Always
          args:
            ["-c", "px-cluster",
             "-s", "/dev/xvdf",
             "-secret_type", "k8s",
             "-b",
             "-x", "kubernetes",
             "-jwt_issuer", "example-domain.com"]
          env:
            - name: "AUTO_NODE_RECOVERY_TIMEOUT_IN_SECS"
              value: "1500"
            - name: "PX_TEMPLATE_VERSION"
              value: "v4"
            - name: "PORTWORX_AUTH_JWT_SHAREDSECRET"
              valueFrom:
                secretKeyRef:
                  name: pxkeys
                  key: shared-secret
            - name: "PORTWORX_AUTH_SYSTEM_KEY"
              valueFrom:
                secretKeyRef:
                  name: pxkeys
                  key: system-secret
           - name: "PORTWORX_AUTH_STORK_KEY"
             valueFrom:
               secretKeyRef:
                  name: pxkeys
                  key: stork-secret

我们还需要找到Stork部署和编辑环境以包含我们的共享secret。见下文。

         containers:
      - command:
        - /stork
        - --driver=pxd
        - --verbose
        - --leader-elect=true
        - --health-monitor-interval=120
        imagePullPolicy: Always
        image: openstorage/stork:2.2.5
        env:
        - name: "PX_SERVICE_NAME"
          value: "portworx-api"
        - name: "PX_SHARED_SECRET"
          valueFrom:
             secretKeyRef:
                name: pxkeys
                key: stork-secret

完成这两个步骤后,保存YAML文件。现在,我们需要创建我们在Portworx安装YAML中引用的共享Secret。

接下来,使用下载和编辑过的YAML文件创建Portworx集群。

$ kubectl apply-f px-sec-cluster-spec.yaml

$ kubectl get po -n kube-system -l name=portworx
NAME             READY STATUS RESTARTS   AGE
portworx-4vmcx   1/1 Running 0          3m54s
portworx-hwrxh   1/1 Running 0          3m54s
portworx-rbqzk   1/1 Running 0          3m54s

用户和Token

我们需要定义几个用户并为他们生成Token。通常,这些用户有分配给他们的属性,这些属性定义了他们的用户类型。

首先,我们将创建一个存储管理员,该管理员具有全部权限。这样的管理员应该只有一两个。

使用以下内容创建一个名为admin.yaml的文件:

name: Storage Administrator
email: storageadmin@example.com
sub: storageadmin@example.com/storageadmin
roles: ["system.admin"]
groups: ["*"]

接下来,我们将创建一个Kubernetes用户,该用户作为一个验证客户,Kubernetes允许该用户与Portworx交互,并且这些请求来自Kubernetes。您的存储管理员需要设置此用户。

使用以下内容创建一个名为kubernetes.yaml的文件:

name: Kubernetes
email: kubernetes@local.net
sub: kubernetes@local.net/kubernetes
roles: ["system.user"]
groups: ["kubernetes"]

最后,我们将创建一个仅能看 (view-only) 权限的用户,用于演示Portworx如何限制对底层数据管理API的访问。

使用以下内容创建一个名为viewer.yaml的文件:

name: Viewer
email: viewer@example.com
sub: viewer@example.com/viewer
roles: ["system.view"]
groups: ["viewers"]

注意:Sub标记是该用户的唯一标识符,根据JWT标准,不能与其他Token共享。这个值被Portworx用来跟踪资源的所有权。如果电子邮件也用作唯一Sub标识符,请确保它不被任何其他Token使用。

请注意:有一个用户的角色是system.admin,另一个用户的角色是system.user,最后一个用户的角色是system.view。这些角色在PX-Security中是默认的,但也可以根据需要创建其他角色。我们来演示用户如何使用Portworx资源,如创建或删除卷。这跟该用户在Kubernetes RBAC的配置无关。

也就是说,具有system.view的用户也许能够在Kubernetes中内列出和创建PVC对象,但如果他们试图直接使用Portworx创建卷,将会失败。我们还将演示,为什么能够创建PVC对象的用户在此安全模式中实际上无法获得PV,除非该用户拥有由存储管理员配置的有效Token,来验证其角色和权限。

配置好了这些具备相关权限的用户,我们就可以使用我们的共享Secret和Portworx客户端工具pxctl,为这些用户生成自签名证书。

 

注意:您可以创建自己的应用来生成Token,也可以基于我们的开源golang示例程序openstorage-sdk-auth

 

在这个场景中,我们将使用共享Secret和pxctl auth token generate命令。让我们为上述两个用户创建Token。

 

首先,获取共享Secret。

PORTWORX_AUTH_SHARED_SECRET=$(kubectl -n kube-system get secret pxkeys -o json \
    | jq -r '.data."shared-secret"' \
    | base64 -d)

接下来,配置Admin Token。首先是SSH,到Portworx节点,这样就可以使用pxctl命令。

$ PX_POD=$(kubectl get pods -l name=portworx -n kube-system -o jsonpath='{.items[0].metadata.name}')

$ kubectl exec -it -n kube-system $PX_POD  bash

然后,使用admin.yaml和共享Secret创建admin Token。

注意:确保将auth_config文件和PORTWORX_AUTH_SHARED_SECRET 复制到正在使用pxctl的Portworx容器中。

ADMIN_TOKEN=$(/opt/pwx/bin/pxctl auth token generate \
   --auth-config=admin.yaml \
   --issuer=example-domain.com \
   --shared-secret=$PORTWORX_AUTH_SHARED_SECRET \
   --token-duration=1y)
$ pxctl context create admin --token $ADMIN_TOKEN

接下来,配置Kubernetes Token。

KUBE_TOKEN=$(/opt/pwx/bin/pxctl auth token generate \
   --auth-config=kubernetes.yaml \
   --issuer=example-domain.com \
   --shared-secret=$PORTWORX_AUTH_SHARED_SECRET \
   --token-duration=1y)

接下来,配置Viewer token。

VIEWER_TOKEN=$(/opt/pwx/bin/pxctl auth token generate \
   --auth-config=viewer.yaml \
   --issuer=example-domain.com \
   --shared-secret=$PORTWORX_AUTH_SHARED_SECRET \
   --token-duration=1y)
$ pxctl context create viewer --token $VIEWER_TOKEN

现在我们已经创建了用户环境(Context),比如Portworx的Kubectl环境,来供两个用户使用,我们可以作为其中一个用户与Portworx系统进行交互。

注意,您可以使用$pxctl contextlist列出所有环境:

$ pxctl context set viewer

$ pxctl volume create --size 5 myvol
VolumeCreate: Access denied to roles: [system.view]

发生了什么?请记住,我们为具有system.view角色的Viewer设置了用户环境。这是Portworx的默认角色,只能运行只读命令,不具备写操作的权限,因此访问被拒绝。

如何与Kubernetes一起使用?

为了让Kubernetes的用户使用PX-Security,用户必须在向集群发出请求时使用自己的Token。一种方法是让管理员在Kubernetes存储类中配置Token。管理员可以在Portworx命名空间中名为px-k8-user的Secret中设置保存Secret Token。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: px-storage-repl-1
provisioner: kubernetes.io/portworx-volume
parameters:
  repl: "1"
  openstorage.io/auth-secret-name: px-k8s-user
  openstorage.io/auth-secret-namespace: portworx
allowVolumeExpansion: true

如果您正在使用CSI,请确保设置其他的参数。

注意:这目前只在通过Portworx使用CSI时有效。

parameters:
  repl: "1"
  csi.storage.k8s.io/provisioner-secret-name: px-k8s-user
  csi.storage.k8s.io/provisioner-secret-namespace: portworx
  csi.storage.k8s.io/node-publish-secret-name: px-k8s-user
  csi.storage.k8s.io/node-publish-secret-namespace: portworx
  csi.storage.k8s.io/controller-expand-secret-name: px-k8s-user
  csi.storage.k8s.io/controller-expand-secret-namespace: portworx

完成此操作后,具备访问存储类权限的用户可以创建卷。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
   name: mysql-data
spec:
   storageClass: px-storage-repl-1
   accessModes:
     - ReadWriteOnce
   resources:
     requests:
       storage: 12Gi

多租户架构

当您创建上述PVC时,它将使用KubernetesToken作为用户进行身份验证,从而确保该Kubernetes用户是发出请求的用户。这很好,但是多租户环境下,他们都可以使用存储类,因此我们需要一种方法来在不同的命名空间中使用多租户的Token。这是因为Kubernetes提供了使用命名空间隔离帐户资源的好方法,但您需要更安全的多租户解决方案。Portworx可以通过为应用存储卷添加访问控制来达到多租户安全管理。使用PX-Security进行多租户管理,可以执行以下操作。

 

首先,为租户创建一个命名空间。

$ kubectl create namespace tenant-a-ns

使用以下创建一个名为tenant-a.yaml 的文件:

name: tenant-a
email: tenant@tenant-a.com
sub: tenant@tenant-a.com/tenant
roles: ["system.user"]
groups: ["developers"]

使用tenant-name.yaml为Kubernetes创建一个token:

TENANT_A_TOKEN=$(/opt/pwx/bin/pxctl auth token generate \
    --auth-config=tenant-a.yaml \
    --issuer=example-domain.com \
    --shared-secret=$PORTWORX_AUTH_SHARED_SECRET \
    --token-duration=1y)

将该租户的Kubernetes Token保存在一个名为<tenant namespace>/px-k8 -user的Secret中:

$ kubectl -n tenant-a-ns create secret \
  generic px-k8s-user \
  --from-literal=auth-token=$TENANT_A_TOKEN

现在可以设置Kubernetes存储类,通过使用这个Secret,来获得Token权限,并与Portworx开始通讯。

 

下面的CSI存储类一旦创建,将使您的多租户能够使用存储在其命名空间中的Secret中的Token,来创建卷,方法是在命名空间中查找Secret。在使用CSI时,存储类将引用三种受支持操作的secret:provision, node-publish(mount/unmount), and controller-expand。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: px-storage
provisioner: pxd.portworx.com
parameters:
  repl: "1"
  csi.storage.k8s.io/provisioner-secret-name: px-k8s-user
  csi.storage.k8s.io/provisioner-secret-namespace: ${pvc.namespace}
  csi.storage.k8s.io/node-publish-secret-name: px-k8s-user
  csi.storage.k8s.io/node-publish-secret-namespace: ${pvc.namespace}
  csi.storage.k8s.io/controller-expand-secret-name: px-k8s-user
  csi.storage.k8s.io/controller-expand-secret-namespace: ${pvc.namespace}
allowVolumeExpansion: true

请注意 ${pvc.namespace}。这将确保CSI控制器获得正确的Token,该Token与PVC的命名空间相关联。您现在就有了一个基于Token身份验证的多租户解决方案。

 

我们在本Blog中有一部分没有介绍的PX-Security功能就是Portworx卷的加密。您可以在这里(how to work with Encrypted PVCs)查看更多的关于PVC加密的文档 。您可以将Portworx RBAC与卷加密结合使用,来使Kubernetes中的数据更加安全。

打算用容器跑生产系统?备份怎么做才靠谱?

Portworx阅读(3963)评论(0)

PX-Backup: 云原生应用备份与恢复利器

对于IT系统来说,备份是至关重要的。很多情况下需要用到备份数据。例如系统被发现有Bug后,运维团队需要从某个具体时间点的备份数据来重新恢复之前的应用。或者需要调出3年前的某批数据,来供审计部门调查合规性。对于容器化的应用来说,目前的应用备份操作,以及在多环境中追踪数据的完整性和一致性的操作,都是手动且比较复杂的。有些工具能够启动备份的过程,但是这些工具需要能跟传统的企业级存储系统集成。它们并不能很好的支持Kubernetes的环境,并且不能够提供完整的、端到端的企业级云原生备份解决方案。

PX-Backup能够很好的解决问题。一个端到端的备份解决方案,专门为基于Kubernetes的应用而设计,PX-Backup有效管理容器数据的生命周期,对相关元数据进行归类,增加了数据访问的可见性。通过简单的鼠标点击即可完成Kubernetes应用的整体备份和恢复,包括数据、应用配置、以及Kubernetes对象。PX-Backup支持应用的备份,不论数据是存储在Portworx Enterprise上,还是存储在公有云中并通过Kubernetes CSI插件进行管理的块存储里:包括微软Azure,亚马逊AWS,Google云。

PX – Backup  

一个Kubernetes应用一般包括一个/多个Pods以及其他的Kubernetes对象。这些Kubernetes对象包括但不限于:部署、StatefulSets、Pods、Roles、Secrets、配置地图,以及存储持久应用数据的持久存储卷。

PX-Backup提供了一种新的方式来备份Kubernetes应用:

应用备份

为了备份应用,仅仅备份数据是不够的。PX-Backup使企业能够备份整个Kubernetes或者OpenShift应用,包含数据,应用配置和Kubernetes对象。这些备份动作可以通过事先定义的调度计划,或者在任何有需要时,进行触发。

Kubernetes命名空间和OpenShift 项目感知

PX-Backup使用户能够基于标签,或基于整个Kubernetes命名空间,或基于OpenShift项目,来备份每个单独的Pod,或者Pod组,仅需点击几下鼠标。当备份完成后,PX-Backup就会维护原有的命名空间的可感知性,这样用户就能够决定是否需要在新的Kubernetes集群上,在同一个命名空间里恢复所有应用。

支持多集群和多云环境

PX-Backup使企业能够使用单一的用户界面,管理运行在不同本地部署或云中的不同Kubernetes集群的备份。PX-Backup能够备份运行在不同Kubernetes集群上的应用,并提供了对备份的源环境的可见性,使用户能够比较容易的管理备份数据的生命周期,即便这些数据是存储在跨云环境中的。

管理和导入云中的存储卷

即使用户没有使用Portworx Enterprise来存储他们的容器卷,用户仍然可以使用PX-Backup。PX-Backup提供了与云环境的无缝集成,包括GCP, AWS和Azure。PX-Backup允许用户从云中向Portworx Enterprise导入永久存储卷。

使用集群、命名空间或标签选择器来恢复应用

PX-Backup允许用户根据特定的备份时间来选择和恢复一个备份。恢复的工作流程中还允许用户通过选择某个特定的集群,命名空间或者标签来筛选某个具体的备份,这样就能大量减少恢复应用的时间。企业还能够为某个具体的文件来搜索卷备份。

数据资产和备份治理能力

PX-Backup能够保存应用备份的源集群的历史信息记录。这样用户就能够管理备份资产的生命周期,即使该源集群的资源在很久以前已经被释放掉。通过审计logs来保持备份和恢复的历史记录能够帮助用户更有效的管理数据生命周期,增加数据审计能力。

云上跑容器,如何降低存储成本

Portworx阅读(1465)评论(0)

PX-Autopilot: 自动化的存储容量管理,节省一半的云存储成本

不少客户都在使用K8S来管理容器,并且通过Portworx来管理容器存储。虽然云原生的方式让我们获得了更大的自动化和灵活度,许多客户在容器下层的基础架构层的扩展性方面,仍然有一定的局限。K8S和Portworx能够自动化部署容器应用,但是这些应用所基于的基础架构还无法通过自动化的方式进行扩展。DevOps团队还经常被要求去做基础架构投资成本收益的财务分析,并增加财务管理手段来降低成本和让成本更具备可预测性。当基础架构被转移到公有云后,成本管理就成为更加重要的方面,不少用户在公有云上的成本甚至高于他们原有的本地部署架构的成本。Portworx新发布的PX-Autopilot能够对存储基础架构进行更加有效的运营管理,并且降低一半的存储成本。

PX-Autopilot: 自动化的存储容量管理  
PX-Autopilot让客户能够自动化的扩展存储,不仅是扩展某个容器化应用所属的存储(通过PVC的扩容),还可以对基础架构层的存储池进行扩容。Portworx2.3.1最新版本中,已经包含了PX-Autopilot。通过PX-Autopilot,客户能够更加方便的构建企业级自服务K8S应用和数据管理能力,不论是在本地部署,私有云,还是公有云中

我们的目的是帮助客户:

  • 大幅简化为容器应用做存储扩容的操作
  • 在不需要停机的情况下,更有效的管理云计算IaaS的存储层
通过PX-Autopilot的PVC resize功能,用户能够在他们的存储空间即将到达限度之前,自动的扩展PVC。PX-Autopilot可以利用现有的监控解决方案,比如Prometheus,来监控集群中的数据,并且监测高用量资源。当监测发现资源用量达到阈值后,PX-Autopilot自动通过K8S,以及事先制定的扩容规则,来对PVC进行扩容。这些规则的定义和部署都非常的灵活和简单。通过在K8S集群的一个或多个NameSpace上加标签即可实现。当这些集群扩容的时候,由于基础架构层本身的限制,会存在一个短时间内PVC无法被调整。Autopilot可以利用公有云的灵活性来扩大基础架构层的存储池容量。用户只需要在StorageCluster spec中提供一个minSize,以及一个可选的maxSize, Autopilot就会自动化的按照需要扩展存储池容量。目前这样的功能已经支持Microsoft Azure和vSphere。Amazon EBS和Google Persistent Disk也即将支持。

通过PX-Autopilot扩展存储池

通过PX-Autopilot节省云成本  
除了能帮用户节省操作存储集群扩容的近20个小时工作量,PX-Autopilot通过自动化的存储容量调整,可以帮助客户节省大量的存储成本。K8S帮助我们完成了自动化的容器应用部署,但我们还需要对底层基础架构层进行自动化调整,来保证容器应用有足够的计算和存储资源。虽然公有云提供的是按使用量付费的方式,但是实际上客户必须手动的管理存储扩容来应对数据增长,通常会部署超出正常需要2~3倍的块存储。这意味着客户不得不对没有使用的存储去付费。PX-Autopilot可以通过按实际用量自动化扩展存储容量的方式,帮助客户减少一半的存储成本。

很大一部分客户已经体会到了使用PX-Autopilot来扩充公有云存储的益处。Portworx是一个软件定义的存储层,通过Portworx,用户不在需要过度部署存储,而只是需要在应用数据增长需要额外存储的时,自动化的对存储进行扩容。

我们来看一个例子。如果您是在AWS公有云中运行一个云原生的应用。这个应用需要10,000 IOPS,gp2-volume的SSD存储。有10个类似这样的应用,每个卷需要1TB的存储容量。

没有Portworx的话,你需要部署10个3.33TB的EBS卷,来达到所要求的IOPS (EBS提供每GB存储3 IOPS,所以提供每卷10,000 IOPS需要每卷3.33TB,虽然一共我们只需要每卷1TB)。在使用Portworx的情况下,我们可以先从10个1TB每卷的最小存储量开始。PX-Autopilot后续会根据数据量的增长,自动化的来扩容存储,这样可以在一年里节省54%的存储成本。这样的成本节约还没有考虑如果达到最大存储容量附加限制后,额外的计算资源的增加,以及其它与K8S部署有关的软件成本。

Portworx还可以帮助客户,根据自身应用实际使用状况,在需要情况下把卷指向更低类型的存储,或者通过快照把存档指向S3兼容类型的存储。从而进一步降低云存储成本。在以上的例子中,如果你需要使用st1-hdd作为第二层,并通过Portworx来调度应用,并希望降低50%的存储,则会实际上降低64%的存储。类似的,不再使用公有云中收费的存储快照功能,而通过Portworx使用本地快照,或者把快照指向S3,如果把1/3的数据通过S3快照来实现,而不是使用EBS快照,则会有62%的成本降低。

我们将会很快把自动化工作流的功能加入到PX-Autopilot中。下面的表格是更详细的成本节省的分析。

Pivotal是这样评价PX-Autopilot的
更多的客户把关键应用向Pivotal Container Service (PKS)转移,对我们来说,保持生态随着客户需求的发展,持续性进化是非常重要的。我们非常高兴的看到PX-Autopilot帮助PKS的客户有效的进行存储扩容,并且无停机时间。

— Angus MacDonald, General Manager, Global Alliances at Pivotal

PX-Autopilot还将持续更新,它将真正实现云原生存储的自动化,以及SLA下的多租户平台。

为什么 K8s 在阿里能成功?| 问底中国 IT 技术演进

alicloudnative阅读(1607)评论(0)

作者:
曾凡松 阿里云云原生应用平台高级技术专家
张振 阿里云云原生应用平台高级技术专家

导读:本文描述了阿里巴巴在容器管理领域的技术演进历程,解读了为什么 K8s 最终能够大获成功的原因,以及到今年 双11 阿里巴巴内部的 K8s 应用情况。内容着重描述了阿里巴巴基于 K8s 的云原生改造实践过程的三大能力升级,在对应能力升级过程中沉淀的技术解决方案,以及通过这些能力升级所取得的业务价值。

从 2015 年 Google 牵头成立 CNCF 以来,云原生技术开始进入公众的视线并取得快速的发展,到 2018 年包括 Google、AWS、Azure、Alibaba Cloud 等大型云计算供应商都加入了 CNCF,云原生技术也从原来的应用容器化发展出包括容器、Service Mesh、微服务、不可变基础设施、Serverless、FaaS 等众多技术方向,CFCF 旗下也囊括了越来多的开源项目。

Kubernetes 作为 CNCF 的第一个项目从诞生之初就就令人瞩目,Kubernetes 由 Google 工程师基于 Google 内部多年集群管理系统 Borg 的设计经验,结合云计算时代的基础设施特点重新设计而得,旨在帮助企业解决大规模 IT 基础设施的应用容器编排难题。

Google 在 2014 年 6 月开源 Kubernetes 以后,在 Redhat、Microsoft、Alibaba 等厂商和众多开源爱好者共同的努力下,成长为如今容器编排领域的事实标准,极大的推动了云原生领域的发展。

今天为大家分享来自阿里云的 Kubernetes 大规模实践经验,展现阿里云如何基于 Kubernetes 推动阿里巴巴应用运维技术栈走向云原生,如何推动 Kubernetes自身的技术进步,充分挖掘云原生时代的红利助力阿里巴巴大幅降低 双11 的 IT 成本。

容器在阿里巴巴的发展历程

1.png

在 2011 年之前,阿里巴巴使用 VM 虚拟化技术将一个物理机切分为 3 个虚拟机,用于部署淘宝服务,而随着淘宝业务的飞速发展,基于 VM 的技术方案在灵活性上跟不上业务的步伐。

因此,阿里巴巴在 2011 年就开始探索基于 Linux lxc 的容器技术,用于替代传统基于 VM 的应用部署方案,到 2013 年,研发了基于 Linux lxc 的 T4 容器和 AI 容器编排系统。这在当时已是非常领先的技术方案,但自己研发的容器技术与基于 VM 时代的运维系统始终存在一些兼容性问题。

在 2013 年随着 Docker 容器镜像方案的出现,阿里巴巴技术人员立即看到了基于容器 + Docker 镜像技术的未来,开始大力投入到这一领域的研究当中,到 2015 年 Aliswarm、Zeus、Hippo 等容器编排系统蓬勃发展,各自开疆扩土服务了阿里巴巴经济体的一部分业务。诸多的系统在解决了业务运维成本的同时,也带来了一定的重复建设成本,同时也导致了阿里巴巴内部的资源分布比较分散,无法统一调度多样的业务类型发挥出不同业务错峰使用资源的优势。

正是在这样的背景下,Sigma 系统应运而出并在 2017 年统一了阿里巴巴的资源池,统一调度阿里巴巴所有的核心业务,并第一次支持将在线服务与离线作业运行在同一个物理机上,大幅提高数据中心的资源利用效率并降低了阿里巴巴的 IT 成本。

随着云原生技术的高速发展,阿里巴巴也看到了云原生技术的潜力,以及未来企业 IT 全面上云的必然趋势,从 2018 年开始转型到 Kubernetes 技术,通过 Kubernetes 扩展能力将 Sigma 积累多年的调度能力通过 Kubernetes 的方式提供出来。

在 2019 年阿里巴巴宣布全面上云,阿里巴巴开始全面拥抱 Kubernetes,并将 Sigma 调度系统全面的迁移到基于 Kubernetes 的调度系统,该系统也正是支持了今年最大规模 双11 电商交易系统的底层基础设施,稳定的支持了大促前后数百次的应用变更并提供极速的应用发布与扩容体验,为 双11 的顺畅的购物体验立下悍马功劳。

为什么 K8s 在阿里能成功

Kubernetes 在众多的技术中脱颖而出,概括起来可以归纳为以下三个方面。

2.png

  • 首先是其在诞生之初就为云时代而生,拥有超前的眼光和先进的设计理念,加之最初由天才的 Google 工程师基于其内部 Borg 多年的经验设计而来,诞生之后就飞速发展;

后来随着 RedHat、IBM、微软、Vmware、阿里云等来自全球的优秀工程师大力投入,打造了繁荣的社区和生态系统,成为企业容器编排系统的首选。

阿里巴巴经济体拥有众多的子公司,这些子公司在加入阿里巴巴大家庭时或多或少都会有一套自有的容器编排系统,在融入阿里巴巴的基础设施过程中,Kubernetes 是最标准也最容易被经济体内外的客户所接受的一个方案。

  • 其次,Kubernetes 倡导的申明式 API 的设计理念,也贴合了阿里巴巴在应用运维领域的经验与教训;

传统的运维系统通常是基于过程式的设计,而过程式的运维系统在较长的系统调用链路下,通常会出现因异常处理复杂而导致的系统效率低下。

在大规模应用运维系统中复杂又繁多的状态处理也是一个大难题,基于过程式的系统设计很难确保系统的一致性,针对这些边界异常的处理通常又导致运维系统变得非常复杂,最终为异常兜底的只能依赖运维人员的人工操作。基本上可以认为基于过程式的运维系统难以应对超大规模的应用管理,而 Kubernetes 提供的申明式 API 却是解决应用运维状态轮转的一剂良药,是提高运维技术栈整体链路效率的最佳实践原则。

  • 第三,Kubernetes 模块化、可扩展的架构设计,满足阿里巴巴的定制化改造以支持众多业务运维场景的需求。

在阿里巴巴内部,即有大量的无状态核心电商系统,也有大量的缓存、消息队列等中间件有状态系统,也包括大量带有倒排索引数据的检索系统,还有大量的 AI 计算任务,不用的应用类型对底层容器管理平台的要求也有所不同。

因此,一个模块化方便迁入自定义应用管理策略、易于扩展调度模型的设计显得至关重要,是能够服务阿里内部众多应用形态、提供统一容器管理基础设施的关键,Kubernetes 基本上提供了这些关键基础能力,虽然在实际应用过程中仍然会遇到非常多的实际问题。

阿里巴巴的 K8s 应用情况

3.png

在 2019 年 双11,阿里巴巴内部核心业务主要运行在神龙、ECS、ECI 三种资源类型的基础设施之上,而这些不同类型的基础设施资源均通过 Kubernetes 统一管理,以容器的形态提供给上层应用使用,完成了核心业务的支撑。

有别于以往的 双11,今年核心电商业务应用大规模部署在神龙裸金属服务器上。如果有关注过阿里云技术的发展,应该不会对神龙服务器感到陌生,它是阿里云自主研发的新一代云服务器,通过“软硬一体”的技术开创性的将云计算的虚拟化开销分摊到低价硬件板卡上,彻底的释放 CPU 的计算能力,第一次真正的做到了云计算虚拟化的“零”开销。

容器也是一种轻量级的虚拟化方案,神龙+容器+Kubernetes 的结合正是云原生时代的最佳拍档,支撑了今年最大规模的 双11,也将是未来的主流技术形态。

阿里巴巴也在继续使用 ECS 作为 Kubernetes 的底层资源供给,ECS 作为传统的云计算虚拟化方式支撑了部门集团内部业务,同时结合灵活性更好的弹性容器实例 ECI 用于应对业务突发的流量峰值,为业务带来了云计算的弹性价值,真正实现了按需申请、释放资源的极致弹性能力,降低了业务需要提前规划资源所带来的成本。

这些分布在海内外的数十万个节点的资源,被数十个 Kubernetes 集群托管,运行着阿里巴巴上万个应用,共计超过百万的容器,其规模之大前所未有。在今年的 双11 中,阿里巴巴内部最大的 Kubernetes 集群规模达到万级;当然这并不是Kubernetes 的技术极限,而是我们考虑数据中心资源效率与基础设施容灾能力之间所取的平衡,在将来如果有需要这个数字也可能变得更大。

基于 K8s 的云原生改造实践

Kubernetes 作为云原生技术的代表,已经成为了容器编排领域的事实标准,阿里巴巴自 2017 年开始探索,到 2018 年确认技术转型到使用 Kubernetes 来管理生产的容器。

在落地 K8s 的过程中,我们主要面临着两大难题:

4.png

  • 其一,上层多样的业务运维平台;

为了支撑阿里巴巴内部多样的业务形态,在内部发展出来了多个典型的业务运维平台,每一个运维平台的基础设施、流程控制、应用发布策或多或少都会存在一些差别,缺少一个统一的应用运维标准。在调度与集群管理的技术演进过程中,如何牵引整个运维体系升级的同时并保持多个业务的平台及其上业务的稳定性,这是一个巨大的工程。

  • 其二,随着阿里巴巴经济体全面上云战略的实施,整个底层基础设施包括存储、网络、基础运维软件的技术演进也非常迅速。调度与集群管理需要在支持好基础设施快速演进的同时,迭代自身的技术架构,并同时保证业务的稳定性。

基于 K8s 的云原生技术改造正是在这样的背景下诞生,发展到 2019 年 Kubernetes 在内部已大规模部署,所有的核心业务也都已经运行在 K8s 集群管理中。但在这几年的实践过程中,有一个问题始终萦绕在工程师头脑中,在阿里巴巴这么大体量、这么复杂的业务下,遗留了大量传统的运维习惯以及支撑这些习惯的运维体系,在这样的背景下落地Kubernetes (内部一个形象的比喻叫做给高速飞行的飞机更换发动机)到底是在坚持什么,哪些地方可以妥协,哪些地方必须改变?

这一章节, 将为大家分享我们这几年对这个问题的一些思考,特别是经过了今年的 双11 考验后,这个问题的答案基本上得到了工程师群里的集体认可。

负责顶层设计的架构师终于可以喘一口气:拥抱 Kubernetes 本身并不是目的,而通过拥抱 Kubernetes 翘动业务的云原生改造,通过 Kubernetes 的能力治理传统运维体系下的沉疴顽疾,真正释放云的弹性能力,为业务的应用交付解绑提速,才是这次技术变革的最大价值所在。

5.png

面向终态升级

在传统的运维体系下,应用的变更都是运维通过创建操作工单发起工作流,继而对容器平台发起一个个的变更来完成的。比如升级一个服务下的 3000 个实例,工单会被提前计算并生成出多个批次的子任务,并逐个的调用容器平台的接口完成变更应用的变更。

为了确保应用发布工单的顺利执行,在每一个子工单内部,每一个容器的发布也是一个工作流,包括监控开管、镜像拉取、容器启停、服务注册、配置推送等等,如果一切正常该流程会按预期有序的进行。

6.png

在大规模应用发布的场景中,诸如宿主机宕机、磁盘异常、IO 异常、网络异常、内核异常等几乎是必然存在的,如果发布流程中的某一个步骤出现了错误,通常情况下需要运维平台按照一定的策略来重试,直到超过该批次的超时阈值,这将会带来三个问题,下面逐一展开。

  • 其一是重试带来的效率问题;

每一个子任务的执行时间将被任务内的长尾发布所拖累,假设将 3000 个容器分为 30 批次每批 100 个(仅为示意并非最佳实践),每一批次内出现一个容器发布异常时,该批次的发布时间将被重试拉长。

  • 其二是失败带来的一致性问题;

对于发布异常的容器,在工单结束之后通常只能通过外围链路巡检的方式来治理,而事实上通常的巡检是依赖运维人员手工操作的,带来了极大的人工成本和不确定性。

  • 第三是应用并发变更冲突问题。

如果在应用发布的过程中,同时提交了应用扩容的请求,由 3000 扩容到 3200 个实例,扩容的 200 个实例应该采用旧版本还是新版本,采用旧版本扩容将面临的问题是谁最终负责这 200 个旧版本实例的升级,采用新版本扩容将面临的是稳定性问题,如果新版本存在问题新扩容的实例将产生较大的影响。

正是因为这些复杂的问题导致多数运维系统拒绝了并发的应用变更,导致并发操作效率非常底下。

K8s 为应用管理所提供的申明式 API 的设计理念同时解决了解决了这三个问题,用户只需要描述期望的最终状态以及达成期望状态的过程中需要遵守的限制条件,达成终态所需要执行的复杂操作全部交由 K8s 的来完成。

在应用发布过程中,通常情况下 K8s 通过控制并发度及最大不可用实例数来约束应用发布对服务的影响,对于发布过程中失败的实例通过最终一致的方式在系统内部解决。正是基于这一设计,用户发起服务变更时只是更新了应用的预期状态,并不需要等待任何任务的结束,一并解决了应用发布效率、线上配置的一致性和并发变更冲突效率的问题。

7.png

基于面向终态的理念管理应用,我们开发 Advanced StatefulSet 的应用管理工作模型,顾名思义它基于 Kubernetes 官方的 StatefulSet 扩展而来。

在官方的工作模型中,应用通过滚动的方式完成版本升级,也就是创建新的 Pod 同时删除旧版本的 Pod,直到整个应用切换为新的版本。

这种方式简单直接,但存在效率的问题,比如所有应用的 Pod 需要重新的调度,这在大规模应用发布场景将给调度器带来很大的压力;同时,因为新版本 Pod 为全新创建,需要重新分配 IP 并挂载远程卷,这对云计算网络、存储基础设施也将是很大的挑战;再者,因为容器是被全新调度出来的,在机器上需要重新下载新的应用镜像,这将大幅降低应用发布的效率。

为了提高应用发布的效率和资源的确定性,开发了这一工作负载模型,它支持原地发布应用,应用发布前后应用所在的位置保持不变,同时支持了并发更新、容错暂停等丰富的发布策略,高效的满足了阿里巴巴内部电商应用的发布需求。因为应用发布前后位置不变,因此我们可以在灰度发布的过程中预先下载并解压即将要发布的容器镜像,从而大幅提高应用发布的效率。

8.png

在面向终态的应用管理中,复杂的运维过程被 K8s 内部所实现,K8s根据用户的期望及现状计算出需要执行的动作,并逐步的变更直到终态。面向终态带来了卓越的运维效率提升,但同时也为系统工程架构提出了更高的要求。

我们知道在 K8s 内部是一个模块化、分布式的系统,通往终态的运维决策分散在内部的多个模块中,这些模块都有可能对容器发起一些运维动作,比如控制器、运维 Operator、重调度器甚至是 kubelet。在高度自动化的系统中,一旦出现预期外的异常,其杀伤力可能会对其上运行的业务造成灾难性的后果,加之 K8s 中决策分散在众多的模块中,所带来的问题是系统风险的控制变得更加困难,对这个系统设计的质量有很高的要求。

为了控制整个系统的风险,如上图所示,我们在 K8s 系统的关键位置对关键行为行为进行了埋点,针对性的制定了限流及熔断的策略,使得整个系统即使在出现极端错误的场景下,也能够最大化的保护其上运行的业务。

自愈能力升级

9.png

在阿里巴巴传统的运维体系下,容器平台仅生产资源,应用的启动以及服务发现是在容器启动后由运维平台系统来完成的,这种分层的方法给了运维系统最大的自由度,也在容器化后促进了阿里巴巴的容器生态繁荣。

但是这种方式有一个严重的问题,因为容器调度平台无法自主地去触发容器的扩缩容,而需要和一个个运维平台来做复杂的联动,上层运维系统也因为需要感知到底层基础设施的信息,从而导致进行了很多重复建设的工作。

在工程实践上,这些复杂性使得即使经过了细心的设计与大量的投入其工作效率也不高,严重妨碍宿主机发生故障、重启,容器中进程发生崩溃、卡住等异常时的自愈修复效率,同时也让应用弹性伸缩的实现变得非常的复杂和低效。

10.png

我们解决这一问题的思路是通过 K8s 中提供了容器命令以及生命周期钩子,将启动应用以及检查应用启动状态这一正个流程内置到 pod 中,包括与监控、VIP、服务中心、配置中心等基础设施的交互,通过 Pod 实现容器与应用实例的生命周期统一。

容器平台不再是仅生产资源,而是交付可以直接为业务使用的服务,从而使得可以在 K8s 系统内部完成故障自愈闭环,极大地简化了应用故障自愈以及自动弹性扩缩容能力的建设。提高系统自愈的效率,实际上也是帮助业务获得更好的运行时稳定性和应用运维效率。

11.png

在完成了容器与应用实例的生命周期统一之后,我们正在打造一个统一控制器编程框架:Operator Platform。

Operator Platform 由中心的控制组件与一个 sidecar 框架容器以及客户端代码组成,通过对通用的控制器能力的抽象,包括:事件通知、灰度管理、版本控制、缓存、命令管道等能力的封装集成,支持多语言编写operator,使得开发者无需要理解 K8s 的众多的接口细节及错误处理,从而降低了基于 operator 的自动化运维能力的开发难度,使得越来越多的运维能力通过operator 的方式沉淀到 K8s 生态体系中来,让更多的有状态应用能够自动化地部署,提高整个运维体系的运转效率。

通过这种方式,构建了整个机器故障自愈的体系,高效的串联起包括机器锁定、应用驱逐、机器线下、异常修复等流程,确保了集群宿主机的在线率以及业务的可用性。未来,我们期望通过将 operator 编写标准化的方式去推动多个运维平台的基础运维能力能够被最大化的复用,减少重复建设的成本。

不可变基础设施

12.png

第三个重要的能力升级是对不可变基础设施的升级。

我知道 Docker 提供了一种统一的应用交付的形式,通过把应用的二进制、配置、依赖文件在构建过程中打到一个镜像中,从而确保了应用被一次构建出来之后在多个环境中交付的确定性,避免了环境不一致带来的诸多问题。

而 K8s 更进一步,通过将不同用途的 Docker 容器组装在一起成为一个 pod,通常情况下在升级 pod 时需要整个的销毁重建,从而确保应用镜像、卷、资源规格的一致性。在落地 K8s 的过程中,坚持了不可变基础设施的设计理念,通过 K8s pod 将原本运行在一个富容器中的应用与运维基础组件分离到不同的容器中,并通过升级容器镜像的方式完成应用的升级。

这里有一个概念需要澄清,并不是使用 K8s 就等于践行了不可变基础设施的理念,而是必须要确保应用运维通过镜像升级而不是动态发布文件的方式完成,而事实上因为一些历史原因,这一用法在行业中普遍存在。

13.png

当然,与 K8s 有所不同的是,我们并未强制坚持 pod 的不可变而是取了一个折中的方式,即坚持容器不可变。

原因是我们将应用容器与运维基础设施容器分离之后,运维容器作为应用容器的 sidecar 容器,其拥有着不同的版本迭代策略。应用容器由应用运维人员负责发布,其策略因应用的不同而不同,比如电商应用使用 StatefulSet 而本地生活使用 Deployment 来管理应用,而基础设施容器则由基础设施运维负责,其发布策略与应用本身也存在一些差别。

为了解决这个问题,我们开发了一个叫做 SidecarSet 的基础设施容器管理模型,它使用同一个集合统一管理多个应用的运维容器,将基础设施的变更与应用容器的变更进行分离,从而支持基础设施的快速演进。将基础设施容器定义从应用 pod 中抽离出来后,应用管理员不再关心基础容器的启动参数,而是交由基础设施运维人员通过配置 SidecarSet 自动为应用注入运维容器,简化了应用运维的复杂性。

可以看到,这种关注点分离的设计,同时简化了应用运维与基础设施运维的负担。

总结与展望

阿里云通过落地 K8s 推动阿里巴巴运维体系走向云原生,在应用容器发布管理效率、服务稳定性以及企业 IT 成本方面取得了很大的突破。

我们一直在思考,通过什么样的方式能够将阿里巴巴的应用管理经验输出到更多的场景,解决更多客户面临的应用管理难题,在企业全面云化这样的趋势下,如何解决企业在公有云、私有云、混合云以及多云场景的应用管理复杂性。

14.png

正是在这样的背景下,阿里云与微软在 2019 年 11 月联合推出了一款用于构建和交付云原生应用的标准规范,即 Open Application Model(简称 OAM)

OAM 提出了一种通用的模型,让各平台可以在统一的高层抽象上透出应用部署和运维能力,解决跨平台的应用交付问题。同时,OAM 以标准化的方式沟通和连接应用开发者、运维人员、应用基础设施,让云原生应用交付和管理流程更加连贯、一致。

15.png

通过应用交付标准化的方法,我们期望未来在云上部署一个应用,就像手机在应用商店中安装一个淘宝一样便捷与高效。

最后,本文提到的阿里巴巴在云原生改造上完成的相关能力升级,我们都已经或者即将开源到OpenKruise 项目中,欢迎大家关注与交流!

参与方式:

  • 钉钉扫码进入 OAM 项目中文讨论群

16.png
(钉钉扫码加入交流群)

云原生实践峰会即将开幕

17.png

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”

Saas 应用12个架构规范

JFrogchina阅读(1313)评论(0)

一、引言

如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论:

  • 使用标准化流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。
  • 和操作系统之间尽可能的划清界限,在各个系统中提供最大的可移植性
  • 适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。
  • 将开发环境和生产环境的差异降至最低,并使用持续交付实施敏捷开发。
  • 可以在工具、架构和开发流程不发生明显变化的前提下实现扩展

这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。

二、特别声明

本文转自国外一篇文章,由Adam Wiggins所著,原文地址:https://12factor.net/

在此文基础上增加个人的理解以及部分图解。

 

三、12个架构规范

1. 统一源代码管理系统

一份基准代码(Codebase),多份部署(deploy)

在类似 SVN 这样的集中式版本控制系统中,基准代码 就是指控制系统中的这一份代码库;而在 Git 那样的分布式版本控制系统中,基准代码 则是指最上游的那份代码库。

基准代码和应用之间总是保持一一对应的关系:

  • 一旦有多个基准代码,就不能称为一个应用,而是一个分布式系统。分布式系统中的每一个组件都是一个应用,每一个应用可以分别使用 12-Factor 进行开发。
  • 多个应用共享一份基准代码是有悖于 12-Factor 原则的。解决方案是将共享的代码拆分为独立的类库,然后使用 依赖管理 策略去加载它们。

 

2. 依赖管理

显式声明依赖

 

大多数编程语言都会提供一个打包系统,用来为各个类库提供打包服务,就像 Perl 的 CPAN 或是 Ruby 的 Rubygems 。通过打包系统安装的类库可以是系统级的(称之为 “site packages”),或仅供某个应用程序使用,部署在相应的目录中(称之为 “vendoring” 或 “bunding”)

 

12-Factor规则下的应用程序不会隐式依赖系统级的类库。 它一定通过 依赖清单 ,确切地声明所有依赖项。此外,在运行过程中通过 依赖隔离 工具来确保程序不会调用系统中存在但清单中未声明的依赖项。这一做法会统一应用到生产和开发环境。

 

显式声明依赖的优点之一是为新进开发者简化了环境配置流程。新的开发者可以检出应用程序的基准代码,安装编程语言环境和它对应的依赖管理工具,只需通过一个 构建命令 来安装所有的依赖项,即可开始工作,如Maven,Pip,Npm等

 

12-Factor 应用同样不会隐式依赖某些系统工具,如 ImageMagick 或是curl。即使这些工具存在于几乎所有系统,但终究无法保证所有未来的系统都能支持应用顺利运行,或是能够和应用兼容。如果应用必须使用到某些系统工具,那么这些工具应该被包含在应用之中。

 

3. 配置管理

在环境中存储配置

 

通常,应用的 配置 在不同 部署 (预发布、生产环境、开发环境等等)间会有很大差异。这其中包括:

  • 数据库,Memcached,以及其他后端服务的配置
  • 第三方服务的证书,凭证,如 Amazon S3、Twitter 等
  • 每份部署特有的配置,如域名等

 

应用程序不允许将配置存储为代码中的常量,这需要严格地将配置与代码分离。配置在部署之间差异很大,代码则没有。另外,“config”的这个定义不包括内部应用程序配置,这种类型的配置在部署之间不会有所不同,因此最好在代码中保存

 

提示:对应用程序是否在代码中正确分配了所有配置的试金石是,代码库是否可以随时变为开源,而不用担心泄漏任何敏感凭据。

 

 

应用程序应将配置存储在环境变量中(通常缩写为env varsenv)。在不更改任何代码的情况下,可以在部署之间轻松更改Env变量; 与配置文件不同,它们几乎没有机会被意外地检入代码仓库; 与自定义配置文件或其他配置机制(如Java系统属性)不同,它们是与语言和操作系统无关的标准。

 

 

 

 

4. 后端服务

把后端服务(backing services)当作附加资源

 

后端服务是指程序运行所需要的通过网络调用的各种服务,如数据库(MySQLCouchDB),消息/队列系统(RabbitMQBeanstalkd),SMTP 邮件发送服务(Postfix),以及缓存系统(Memcached)。

 

类似数据库的后端服务,通常由部署应用程序的系统管理员一起管理。除了本地服务之外,应用程序有可能使用了第三方发布和管理的服务。示例包括 SMTP(例如 Postmark),数据收集服务(例如 New Relic 或 Loggly),数据存储服务(如 Amazon S3),以及使用 API 访问的服务(例如 TwitterGoogle MapsLast.fm)。

 

12-Factor 应用不会区别对待本地或第三方服务。 对应用程序而言,两种都是附加资源,通过一个 url 或是其他存储在 配置 中的服务定位/服务证书来获取数据。12-Factor 应用的任意 部署 ,都应该可以在不进行任何代码改动的情况下,将本地 MySQL 数据库换成第三方服务(例如 Amazon RDS)。类似的,本地 SMTP 服务应该也可以和第三方 SMTP 服务(例如 Postmark )互换。上述 2 个例子中,仅需修改配置中的资源地址。

12-Factor 应用将这些都视作 附加资源 ,这些资源和它们附属的部署保持松耦合。

 

 

5. 构建,发布,运行

严格分离构建和运行

 

基准代码 转化为一份部署(非开发环境)需要以下三个阶段:

  • 构建阶段 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包 依赖项,编译成二进制文件和资源文件。
  • 发布阶段 会将构建的结果和当前部署所需 配置 相结合,并能够立刻在运行环境中投入使用。
  • 运行阶段 (或者说“运行时”)是指针对选定的发布版本,在执行环境中启动一系列应用程序 进程

12-factor 应用严格区分构建,发布,运行这三个步骤。 举例来说,直接修改处于运行状态的代码是非常不可取的做法,因为这些修改很难再同步回构建步骤。

每一个发布版本必须对应一个唯一的发布 ID,例如可以使用发布时的时间戳(2011-04-06-20:32:17),亦或是一个增长的数字(v100)。发布的版本就像一本只能追加的账本,一旦发布就不可修改,任何的变动都应该产生一个新的发布版本。这样也便于回退到任意历史版本,而不需要冒风险重新构建。

 

新的代码在部署之前,需要开发人员触发构建操作。但是,运行阶段不一定需要人为触发,而是可以自动进行。如服务器重启,或是进程管理器重启了一个崩溃的进程。因此,运行阶段应该保持尽可能少的模块,这样假设半夜发生系统故障而开发人员又捉襟见肘也不会引起太大问题。构建阶段是可以相对复杂一些的,因为错误信息能够立刻展示在开发人员面前,从而得到妥善处理。

 

 

6. 进程

以一个或多个无状态进程运行应用

 

运行环境中,应用程序通常是以一个和多个 进程 运行的。

 

12-Factor 应用的进程必须无状态且 无共享  任何需要持久化的数据都要存储在 后端服务 内,比如数据库。

内存区域或磁盘空间可以作为进程在做某种事务型操作时的缓存,例如下载一个很大的文件,对其操作并将结果写入数据库的过程。12-Factor应用根本不用考虑这些缓存的内容是不是可以保留给之后的请求来使用,这是因为应用启动了多种类型的进程,将来的请求多半会由其他进程来服务。即使在只有一个进程的情形下,先前保存的数据(内存或文件系统中)也会因为重启(如代码部署、配置更改、或运行环境将进程调度至另一个物理区域执行)而丢失。

 

一些系统依赖于 “粘性 session”, 这是指将用户 session 中的数据缓存至某进程的内存中,并将同一用户的后续请求路由到同一个进程。粘性 session 是 12-Factor 极力反对的。Session 中的数据应该保存在诸如 Memcached 或 Redis 这样的带有过期时间的缓存中。

 

7. 端口绑定

通过端口绑定(Port binding)来提供服务

 

应用有时会运行于服务器的容器之中。例如 PHP 经常作为 Apache HTTPD 的一个模块来运行,正如 Java 运行于 Tomcat 。

12-Factor 应用完全自我加载 而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用 通过端口绑定来提供服务 ,并监听发送至该端口的请求。

还要指出的是,端口绑定这种方式也意味着一个应用可以成为另外一个应用的 后端服务 ,调用方将服务方提供的相应 URL 当作资源存入 配置 以备将来调用。

 

 

8. 并发

通过进程模型进行扩展

 

在 12-factor 应用中,进程是一等公民。12-Factor 应用的进程主要借鉴于 unix 守护进程模型 。开发人员可以运用这个模型去设计应用架构,将不同的工作分配给不同的 进程类型 。例如,HTTP 请求可以交给 web 进程来处理,而常驻的后台工作则交由 worker 进程负责。

 

上述进程模型会在系统急需扩展时大放异彩。 12-Factor 应用的进程所具备的无共享,水平分区的特性 意味着添加并发会变得简单而稳妥。这些进程的类型以及每个类型中进程的数量就被称作 进程构成 。

 

 

9. 易处理

快速启动和优雅终止可最大化健壮性

 

12-Factor 应用的 进程 是 易处理(disposable的,意思是说它们可以瞬间开启或停止。 这有利于快速、弹性的伸缩应用,迅速部署变化的 代码 或 配置 ,稳健的部署应用。

 

进程应当追求 最小启动时间 。 理想状态下,进程从敲下命令到真正启动并等待请求的时间应该只需很短的时间。更少的启动时间提供了更敏捷的 发布 以及扩展过程,此外还增加了健壮性,因为进程管理器可以在授权情形下容易的将进程搬到新的物理机器上。

 

另外进程 一旦接收 终止信号(SIGTERM 就会优雅的终止 。就网络进程而言,优雅终止是指停止监听服务的端口,即拒绝所有新的请求,并继续执行当前已接收的请求,然后退出。此类型的进程所隐含的要求是HTTP请求大多都很短(不会超过几秒钟),而在长时间轮询中,客户端在丢失连接后应该马上尝试重连;对于 worker 进程来说,优雅终止是指将当前任务退回队列。

 

 

10. 开发环境与线上环境一致

尽可能的保持开发,预发布,线上环境相同

 

开发环境(即开发人员的本地 部署)和线上环境(外部用户访问的真实部署)之间存在着很多差异。这些差异表现在以下三个方面:

  • 时间差异: 开发人员正在编写的代码可能需要几天,几周,甚至几个月才会上线。
  • 人员差异: 开发人员编写代码,运维人员部署代码。
  • 工具差异: 开发人员或许使用 Nginx,SQLite,OS X,而线上环境使用 Apache,MySQL 以及 Linux。

12-Factor 应用想要做到 持续部署 就必须缩小本地与线上差异。 再回头看上面所描述的三个差异:

  • 缩小时间差异:开发人员可以几小时,甚至几分钟就部署代码。
  • 缩小人员差异:开发人员不只要编写代码,更应该密切参与部署过程以及代码在线上的表现。
  • 缩小工具差异:尽量保证开发环境以及线上环境的一致性。

将上述总结变为一个表格如下:

12-Factor 应用的开发人员应该反对在不同环境间使用不同的后端服务 ,即使适配器已经可以几乎消除使用上的差异。这是因为,不同的后端服务意味着会突然出现的不兼容,从而导致测试、预发布都正常的代码在线上出现问题。这些错误会给持续部署带来阻力。从应用程序的生命周期来看,消除这种阻力需要花费很大的代价。

 

 

11. 日志

把日志当作事件流

 

日志 使得应用程序运行的动作变得透明。在基于服务器的环境中,日志通常被写在硬盘的一个文件里,但这只是一种输出格式。

 

12-factor应用本身从不考虑存储自己的输出流。 不应该试图去写或者管理日志文件。相反,每一个运行的进程都会直接的标准输出(stdout)事件流。开发环境中,开发人员可以通过这些数据流,实时在终端看到应用的活动。

在预发布或线上部署中,每个进程的输出流由运行环境截获,并将其他输出流整理在一起,然后一并发送给一个或多个最终的处理程序,用于查看或是长期存档。这些存档路径对于应用来说不可见也不可配置,而是完全交给程序的运行环境管理。类似 Logplex 和 Fluentd 的开源工具可以达到这个目的。

 

这些事件流可以输出至文件,或者在终端实时观察。最重要的,输出流可以发送到 Splunk 这样的日志索引及分析系统,或 Hadoop/Hive 这样的通用数据存储系统。这些系统为查看应用的历史活动提供了强大而灵活的功能,包括:

  • 找出过去一段时间特殊的事件。
  • 图形化一个大规模的趋势,比如每分钟的请求量。
  • 根据用户定义的条件实时触发警报,比如每分钟的报错超过某个警戒线。

 

 

12. 管理进程

后台管理任务当作一次性进程运行

 

进程构成(process formation)是指用来处理应用的常规业务(比如处理 web 请求)的一组进程。与此不同,开发人员经常希望执行一些管理或维护应用的一次性任务,例如:

  • 运行数据移植(Django 中的 manage.py migrate, Rails 中的 rake db:migrate)。
  • 运行一个控制台(也被称为 REPL shell),来执行一些代码或是针对线上数据库做一些检查。大多数语言都通过解释器提供了一个 REPL 工具(python 或 perl) ,或是其他命令(Ruby 使用 irb, Rails 使用 rails console)。
  • 运行一些提交到代码仓库的一次性脚本。

一次性管理进程应该和正常的 常驻进程 使用同样的环境。这些管理进程和任何其他的进程一样使用相同的 代码 和 配置 ,基于某个 发布版本 运行。后台管理代码应该随其他    应用程序代码一起发布,从而避免同步问题。

如何熟悉一个系统?(内含知识大图)

alicloudnative阅读(1439)评论(0)

作者 | 唐志龙(鲲龙)  阿里巴巴高级开发工程师

导读:本文总结了熟悉系统主要分三部分:业务学习、技术学习、实战。每部分会梳理一些在学习过程中需要解答的问题,这些问题随着经验的积累需要逐步补充完善。

前言

开发人员经常会面临下面一些场景:

  • 新人入职,需要学习已有系统,作为 landing 的一部分,如何学习?
  • 被拉过去参与一个陌生系统的迭代开发或者系统维护(bugfix),如何快速上手?
  • 同事离职或转岗,需要把系统交接给你,怎么去接? 内心 os:这是一口锅吗?

1.png

这样的场景多了,就需要去梳理常见问题以及应对方法,方便后续遇到类似场景可以快速应对。本文总结熟悉系统主要分三部分:业务学习、技术学习、实战。每部分会梳理一些在学习过程中需要解答的问题,这些问题随着经验的积累需要逐步补充完善。

业务学习

业务学习就是从业务角度去学习系统,我们需要了解系统的客户是谁、使用人是谁、带来了什么价值,系统提供了哪些功能等。不清楚业务,就等于不知道系统在干什么。技术是为业务落地而服务,清楚了业务才知道怎样用技术更好地服务业务,所以业务学习是熟悉一个系统的首要任务。这块主要的学习方式有跟产品、运营、开发沟通,学习产品设计文档文档、PRD、自己使用系统,还有一些常见图,如产品功能架构图、业务流程图、功能树,用例图等。

常见问题:

  • 系统所在行业的情况是怎样?
  • 系统的目标用户是谁?比如是给公司高层做决策用?给运营或客服用?还是互联网用户用?
  • 平均有多少人在使用?高峰期有多少人在用?
  • 系统有什么业务价值?有哪些指标可以衡量系统业务价值?
  • 系统有哪些功能模块?
  • 系统有哪些领域概念?梳理下系统的领域模型;
  • 系统的关键业务流程有哪些?关键业务流程是怎样?
  • 系统的非功能性需求有哪些?如性能、质量、扩展性、安全性等;
  • 系统未来的发展规划是怎样?

技术学习

技术学习主要学习系统的架构、如何实现、系统的运维等。描述一个系统的架构有五视图方法论。

五视图分别是:

  • 逻辑架构
  • 开发架构
  • 运行架构
  • 物理架构
  • 数据架构

逻辑架构

逻辑架构着重考虑功能需求,系统应当向用户提供什么样的服务,关注点主要是行为或职责的划分。常用表达图形,静态图有包图、类图、对象图;动态图有序列图、协作图、状态图、活动图。逻辑架构的核心设计任务是模块划分、接口定义、领域模型细化。

常见问题:

  • 有哪些子系统或模块?系统之间是什么样的关系?
  • 对外上下游接口有哪些?对接人是谁?
  • 关键业务流程怎么实现的?用类图、序列图等方式表达出来。

开发架构

开发架构关主要关注系统源代码、第三方 SDK、使用的框架、中间件、工具包。

常见问题:

  • 代码在哪?
  • 包怎么划分的?怎么分层?如 mvc、controller-service-dao;
  • 用了什么框架,如 ssh、dubbo;
  • 用了哪些工具包?如 apache commons、guava;
  • 用了哪些中间件?如 metaq、tair、schedulerX、Diamond;
  • 依赖哪些平台?如权限平台、流程引擎等。

运行架构

运行架构的着重考虑运行期质量属性,关注点是系统的并发、同步、通信等问题,这势必涉及到进程、线程、对象等运行时概念,以及相关的并发、同步、通信等。

常见问题:

  • 系统能支撑多少 qps?峰值 qps 多少?
  • 与上下游系统怎么交互的?rpc?http?同步还是异步?

物理架构

物理架构的设计着重考虑安装和部署需求,关注点是目标程序及其依赖的运行库和系统软件最终如何安装或部署到物理机器,以及如何部署机器和网络来配合软件系统的可靠性、可伸缩性、持续可用性、性能和安全性等要求。

常见问题:

  • 系统如何发布部署?有哪些部署环境?
  • 系统有多少台机器?
  • 系统部署怎么部署的?关注接入层,部署方式,如集群部署、分布式部署等
  • 有没有容器化?
  • 有没有多机房部署?

数据架构

数据架构的设计着重考虑数据需求,关注点是持久化数据的存储方案,不仅包括实体及实体关系数据存储格式,还可能包括数据传递、数据复制、数据同步等策略。

常见问题:

  • 数据存储在哪?用了什么数据库,如 oracle、mysql;
  • 梳理 E-R 图;
  • 数据量有多少?是否有分库分表?
  • 用了哪些 nosql 库?
  • 有哪些数据同步任务?
  • 大数据框架的使用情况如何?

系统运维

系统运维重点关注什么时候会出问题,出了问题怎么解决。

常见问题:

  • 什么时间容易出问题?比如电商 双11,对系统的压力很大,这时候很容易出问题;
  • 对关键功能是否有监控?需要看系统有配置了哪些报警项,监控了哪些方面;
  • 出了问题怎么解决?日志在哪?是否有全链路跟踪?是否有一些紧急操作,比如开关配置、降级、限流配置;
  • 系统有哪些坑?找开发同学回顾历史问题,以免踩坑。通过同事总结的 case,或者与负责的产品、运营、技术与了解。系统总会有一些坑,需要把这些坑填上。历史代码经过多次迭代总会导致复杂度高(分支、嵌套、循环很多),存在设计漏洞,性能隐患等,很难维护,这些就需要我们去重构了。记住有一句话:填的坑越大,能力越大;
  • 运营、客服反馈的常见问题有哪些?

实践

熟悉了系统的业务和技术后,就要实战了,通过实战进一步加深对系统的熟悉程度。实践可以通过做需求、修 bug、重构等方式,亲自动手编码、调试、测试、上线。

总结

已有系统通常经历了从 0 到 N 的建设过程,熟悉系统其实是一个逆向推导过程,也是一个学习架构、阅读源码的过程。在学习的过程中最好能带上思考,比如为什么要这么设计?为什么要用这个中间件?是否有更好的编码方式?哪些地方可以优化等,以此达到一个深入熟悉的过程。

附:总结图

2(1).jpg

云原生实践峰会即将开幕

3.png

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”

2020,最关注企业级云原生实践落地的大会来了!

alicloudnative阅读(6261)评论(0)

过去的 2019 年,云原生关注度依然居高不下,更多开发者热衷使用云原生技术,更多企业开始探索云原生架构转型落地。尽管云原生技术已经被广泛接受,其在企业技术栈的落地仍然面临挑战。

在与各行业头部企业深度合作和交流中,我们发现国内云原生实践已累积了诸多宝贵经验。云原生技术带来的资源成本降低、研发运维效率提升等巨大价值,已经驱动企业主动迎接这些挑战。可以预见通过云原生上云最大化使用云的能力,高效的社会分工,使企业聚焦于自身业务发展,将成为企业的共识。

2020,站在一个全新十年的节点上,我们期望在以开放创新为支撑的云原生领域发声,邀请来自国内外 IT 公司的一线云原生技术专家们,碰撞思想、共话实践。全方位洞悉云原生技术趋势,分享企业云原生落地实践痛点及经验,共同探索中国企业的云原生化转型的新路径。

2020 年 2 月 29 日,阿里云主办首届云原生实践峰会即将亮相北京!

拉至底部获取赠票福利

1.png

大会官网链接https://developer.aliyun.com/topic/cloudnative2020#/

2.png

主论坛

云原生技术正在快速开拓新的技术边疆,支持新的应用范式,承载新的计算价值。在大会主论坛将分享云原生技术趋势下,我们的洞察和判断;并邀请多位行业领袖分享企业级云原生转型经验。

议题(部分)

  • 云原生和可见的云未来
  • 从 IDC 到全面上云,申通云原生演进之路
  • 阿里巴巴云原生开源探索
  • 云原生在金融场景的实践
  • Apache Flink on K8s 的云原生发展
  • 企业级云原生数据库
  • 云原生生态合作伙伴计划重磅发布

主题演讲嘉宾(部分)

3.png

丁宇(花名:叔同)2010 年加入阿里,云原生应用平台负责人;10 次参与 双11 作战,推动和参与了 双11 几代技术架构的演进升级。

4.png

李响,阿里云智能资深技术专家,负责阿里巴巴大规模集群调度与管理系统,帮助阿里巴巴通过云原生技术初步完成了基础架构的转型,实现了资源利用率与软件的开发和部署效率的大幅提升,并同步支撑了云产品的技术演进。CNCF 技术监督委员会代表,etcd 作者。

5.png

杨海悌(花名:齐风) 蚂蚁金服资深技术专家,具备多年的中间件、PaaS、网络接入、云原生工作经验,目前负责蚂蚁金服资源调度、网络服务、SOFAMOSN、监控等领域,参与并主导蚂蚁 LDC 弹性服务、容器化、Mesh 化等架构演进和云原生技术在蚂蚁规模化应用。

6.png

叶正盛(花名:斗佛)阿里云智能资深技术专家。20 年 IT 领域工作经验。曾带领团队构建阿里巴巴 & 蚂蚁金服集团数据库业务研发体系,创立了全球领先的云计算数据传输、数据管理、数据库云备份、数据库自动驾驶服务的行业产品标杆。目前负责阿里云数据库产品线整体规划工作,包括 PolarDB、AnalyticDB、RDS、NoSQL 等数据库产品,致力于打造全球领先的数据库云计算服务。

7.png

宁晓民(花名:灭道)阿里云云原生合作伙伴负责人。具有 10 多年企业架构(EA)、分布式架构、云原生架构的深度实践经验。2013 年加入阿里巴巴集团,曾负责淘宝共享业务平台技术架构设计,见证与实践了阿里云云原生技术演进及商业化进程,负责多个阿里云战略客户上云架构升级。目前负责云原生合作伙伴业务线。

8.png

任春德(花名:瓦力)阿里云智能高级技术专家。10 年的 Hadoop 相关的大数据计算平台研发经验,目前在计算平台事业部负责 Flink on YARN/K8s 的资源调度管理的研发,致力于为大数据计算提供大规模、高效、稳定的运行平台。

分论坛

分论坛 1: 微服务架构与 Service Mesh 专场

微服务是数字化转型的关键技术架构,而 Service Mesh 已成为云原生堆栈的重要组成部分,本论坛将通过大量企业云原生技术应用案例,深入探讨微服务架构与 Service Mesh 的落地经验及未来发展趋势。

议题(部分)

  • 云原生时代的微服务:架构演进与趋势
  • 双 11 洗礼下的最佳实践,云原生微服务治理与监管控一体解决方案
  • 使用 ASM 重新定义云原生应用通信基础设施
  • 深耕微服务,拥抱云原生,基于 EDAS 的微服务最佳实践及案例分享
  • Serverless 应用引擎如何落地企业级生产应用
  • 云原生时代的“必备品”:可观测 Prometheus + 链路跟踪最佳实践

演讲嘉宾(部分)

9.png

分论坛 2: 容器云专场

微服务是数字化转型的关键技术架构,而 Service Mesh 已成为云原生堆栈的重要组成部分,本论坛将通过大量企业云原生技术应用案例,深入探讨微服务架构与 Service Mesh 的落地经验及未来发展趋势。

议题(部分)

  • 创见未来 – 云原生构建数字经济时代新基石
  • 进击的小玩 – 云原生应用在玩吧的落地与实践
  • 云原生的容器安全
  • Kubernetes 集群智能诊断实践下的 AIOps 演进
  • 专有云的云原生最佳实践 —— 阿里云敏捷 PaaS 容器服务

演讲嘉宾(部分)

10.png

开发者 Workshop

本次大会将设置 6 场开发者 Workshop,聚焦 Kubernetes、微服务、消息、Serverless、函数计算以及 Service Mesh。帮助开发者快速上手云原生技术,共同实操、探讨云原生在企业级落地实践中的难点及解决方法。

议题

  • Kubernetets Workshop
  • 微服务 Workshop
  • 消息 Workshop
  • Serverless Workshop
  • 函数计算 Workshop
  • Service Mesh Workshop

演讲嘉宾(部分)

11.png

报名参与

  • 早鸟票

RMB 98 元(2 月 15 日恢复原价 196 元) 含大会限量礼包,Workshop 席位有限,先到先得!

  • VIP 票

RMB 688元 含晚宴及大会限量礼包,Workshop 席位有限,先到先得!

12.png

扫描二维码,购买 5 折早鸟票

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”

生产环境容器落地最佳实践 – JFrog 内部K8s落地旅程

JFrogchina阅读(1135)评论(0)

引言

Kubernetes已经成为市场上事实上领先的编配工具,不仅对技术公司如此,对所有公司都是如此,因为它允许您快速且可预测地部署应用程序、动态地伸缩应用程序、无缝地推出新特性,同时有效地利用硬件资源。

 

本期我们将回顾采用Kubernetes作为容器编排工具的公司所面临的复杂性和挑战。我们希望我们提供的经验教训、最佳实践和技巧将帮助您在前往K8s旅途中起步并继续前进。

 

 

本期将介绍关于在Kubernetes生产环境的最佳实践,包括::

  • 为上K8s容器云准备好应用程序
  • 在Kubernetes中获得灵活性和通用性
  • 为所有应用程序使用单一、可信和可靠的源
  • 自动部署到Kubernetes
  • 在Kubernetes中构建可靠且可伸缩的环境
  • 可见性和安全性:在Kubernetes中保护您的应用程序
  • 在Kubernetes中记录、监视和调试您的微服务
  • 将应用程序部署到Kubernetes的生产环境中

 

背景

JFrog与Kubernetes的旅程始于我们寻找一个合适的容器编排解决方案,以便为内部目的创建一个功能齐全的环境。我们的开发人员需要测试我们非常复杂的环境,包括JFrog Artifactory和其他产品。与此同时,我们需要为程序和产品经理提供一个完整的功能环境,以便向我们的客户演示平台。

 

为了满足我们的需求,每个产品都需要一个独立的CI/CD开发环境,以便在测试各个分支之间的交互时独立地测试各个分支。

 

随着我们对Kubernetes越来越有信心,我们认识到将JFrog产品分发到Kubernetes的价值,能够跨不同的阶段、开发和生产环境运行应用程序。Kubernetes还允许我们更好地利用我们的资源,因为我们不再需要为单独部署每个产品而启动单个VM。下面我们将回顾落地过程中的主要挑战(6大挑战),同时分享我们的最佳实践、技巧,和在将您的容器应用程序一路带到生产环境中所获得的经验教训。

 

                                                                                           图1 – 应用分发到K8 的6大挑战

 

Kubernetes 介绍

Kubernetes允许您创建容器化的应用程序,并将它们并行的部署,而不必担心各种服务和组件之间的兼容性。将应用程序容器化运行在Kubernetes中的好处是,您可以在一个充满活力的社区中开发产品,从而更容易创建可伸缩的微服务应用程序。这样做的缺点是,当整个团队都在处理各种组件时,情况会很快变得非常复杂。此外,容器化的应用程序可以包含多种组件类型,这取决于您使用的操作系统、语言和框架。

 

 

让我们从使用Kubernetes运行应用程序所需的三个基本组件开始:

 

Ø  容器云集群

Kubernetes集群是您的容器化应用程序运行的编排基础设施。您需要决定是否要自己管理它,以及是否要使用云提供商托管它。此组件不在文档的此范围内讨论。

 

Ø  CI/CD 流水线

CI/CD流水线在Kubernetes中运行,并使流程自动化,从源代码和外部依赖包开始,一直到将应用程序部署到Kubernetes集群中。Kubernetes流水线是“应用程序感知的”(面向应用),这意味着它们天生能够动态地提供一个完整的容器化应用程序堆栈(通常由多个service、deployments, replica sets, secrets, configmap等组成)。对应用程序上下文的每次更改,无论是代码、、镜像还是配置更改,都将触发流水线。

Ø  Kubernetes Registry

您的生产集群应该使用一个单独的、受管理的和可信的真实源,该源存储和记录应用程序和其依赖组件。使用Kubernetes Registry,您可以在一个pod中并行运行多个应用程序堆栈,而不产生冲突,也不需要关心每个应用程序的内部依赖关系。这将维护正在运行的集群、向上和向下扩容应用程序、开发新版本和调试应用程序具体问题分隔开来。

 

 

上K8s容器云前准备好你的应用程序

应用程序是服务/解决方案的核心。在Kubernetes中运行应用程序之前,需要计划和准备应用程序。

Ø  问卷清单:为K8S准备应用程序

下表显示了在准备Kubernetes应用程序之前必须询问的与应用程序相关的任务和问题。

 

有关将构建软件的基础知识,请参见软件12因素。https://12factor.net/

 

 

在Kubernetes中获得灵活性和通用性

多语言编程和多种不同的工具和技术提供了多种可能性。您可以选择最适合您的业务需求的技术,但是每种技术可能有不同的接口、REST API和自己的包格式。支持这些工具的唯一方法是做到在制品从创建到部署的生命周期的管理中实现通用。

 

 

Ø  部署Artifactory作为您的Kubernetes Registry

通过使用Artifactory作为“Kubernetes Registry”,您可以获得灵活性和通用性,作为可信的单一来源,它允许您深入了解代码到应用集群的过程,同时关联每个应用程序的每一层(layer)。Artifactory在一个系统中支持超过25种不同的技术栈,具有一个元数据模型、一个升级流和强大的制品依赖关系。

 

 

Artifactory允许您将容器化的微服务部署到Kubernetes集群,因为它作为一个通用存储库管理平台来满足您的所有CI/CD需求,而不管它们在您的组织中何处运行。登记应用程序包后,可以继续传播和执行构建、测试、升级,最后部署到Kubernetes。为了方便地将Artifactory(和其他JFrog产品)部署到Kubernetes,请参考我们在helm hub中的官方JFrog Helm Charts(https://hub.helm.sh/charts/jfrog)。

 

 

自动化部署到Kubernetes

在CI/CD流水线的每个阶段中不需要人工干预的情况下可靠地大规模部署应用程序是的协调的主要原因。但是如何以一种可重复、可靠的方式将代码发布到集群中呢?如何确保只有正确版本的应用程序才能投入生产?

 

 

为此,我们建议将Artifactory部署为存储库管理平台,通过抹平开发和操作之间的差距在CI/CD流水线中扮演重要角色。

 

Ø  将Artifactory部署为Helm Charts仓库

Artifactory原生支持Helm存储库,使您能够完全控制Kubernetes的部署过程。它提供安全的、私有的、本地的Helm存储库,通过细粒度的访问控制在您的组织中共享Helm Charts。使用远程存储库代理和缓存公共Helm Charts资源,并将本地和远程资源聚合到单个虚拟Helm存储库下,从而从单个URL访问所有Helm Charts。

 

 

K8S 专家建议:

当使用Artifactory作为您的Helm 存储库时,我们建议:

  • 分离您的稳定存储库和开发阶段存储库(基于成熟度)。
  • 在Charts中使用SemVer version 2版本。
  • 定期重新计算索引。

 

Ø  在CI/CD流水线中部署应用程序的最佳实践

在CI/CD流水线中部署应用程序时,我们建议:

 

  • 使用相同的Helm Chart进行本地、分段、测试和生产,同时每个环境使用不同的yaml 文件。每个yaml都需要包含特定的环境配置值。例如:values-stg..yaml,,value-prod.yaml。
  • 在VCS源代码管理系统中管理应用自定义值。
  • 默认配置值yaml应该是针对开发人员或本地的,这样开发人员就可以轻松地在本地使用它。
  • 对依赖项使用外部charts。使用社区已经完成的工作!
  • 出于安全目的:将您的迷药从Charts中分离出来,并将它们作为外部Charts引用。

 

升级发布可靠和可伸缩的应用到Kubernetes环境

在Kubernetes集群中并行运行多个应用程序需要建立对工件(Docker镜像)的持续访问,同时支持零停机的高负载服务。

 

 

Ø  在Kubernetes部署Artifactory 高可用

通过在Kubernetes集群中部署Artifactory HA(高可用),在集群中,您将体验到零宕机服务,如果一个pod被回收或崩溃,或者节点意外停机,容器集群将自动调度恢复对应服务的Pod。

 

在Kubernetes部署Artifactory HA的好处是:

 

  • 在不影响性能的情况下,支持更高的负载兵法。
  • 提供水平服务器可伸缩性,允许您在组织增长时轻松地增加容量以满足任何负载需求。
  • 支持在没有系统停机的情况下执行大多数维护任务。
  • 通过使用零停机时间替换应用程序的各个实例,可以在实例上安装更新版本,从而支持滚动升级。

在下例中,使用三个节点部署了一个Artifactory HA集群:一个主节点和两个成员节点。因为负载均衡只在成员节点上执行。这使得主节点可以自由地处理作业和任务,不会被入站流量中断。

Ø  Kubernetes集群的存储和可伸缩性

Artifactory HA允许您在Kubernetes中突破应用程序的限制,因为它支持大量存储替代方案。有关更多信息,请参见配置文件存储库。

https://www.jfrog.com/confluence/display/RTF/Configuring+the+Filestore

 

 

可见性和安全性:在Kubernetes中保护您的应用程序

像Docker和Kubernetes这样的云本地技术提供了更大的攻击面,为恶意数据挖掘、勒索软件和数据盗窃提供了更多潜在的入口点。在Kubernetes集群中运行的服务并不是完全独立的,它们可以访问集群中的其他区域。

 

 

正是出于这个原因,集群的可见性非常重要,尤其是从安全性的角度来看。您需要知道容器中运行的是什么,因为您的应用程序很少包含单个组件,而是包含外部依赖项,如OS包、OSS libs和第三方流程。这就引出了一个不可避免的问题——它们安全吗?它们是否包含安全漏洞?他们是否遵守自由/开源软件许可?

 

Ø  获的k8s中容器的可见性

Artifactory通过提供可审核性来深入了解整个CI/CD流程,因为它捕获了整个CI/CD流程中产生的大量有价值的元数据。您可以跟踪负责生成Docker镜像层的应用层的CI作业。它还可以通过允许比较两个构建来显示构建差异,从而很容易地跟踪Docker镜像基于哪个层生成的,到哪个构建产生的,从而跟踪到提交。

 

k8专家提示:

推荐阅读:每个人都必须遵循9个Kubernetes安全最佳实践。

(https://www.cncf.io/blog/2019/01/14/9-kubernetes-security-best-practices-everyone-must-follow/

 

Ø  扫描和检测容器中的漏洞

JFrog Xray与Artifactory协作,在应用程序生命周期的任何阶段执行二进制软件工件的通用分析。它对容器中的所有层执行递归扫描,并通过扫描和分析工件及其元数据(递归地遍历任何级别的依赖关系)来帮助识别所有层中的漏洞。可以在Xray中设置策略,根据Xray扫描发现的风险级别限制或阻止容器镜像部署到Kubernetes。通过这种方式,可以阻止脆弱或不兼容的应用程序运行,或者限制它们在启动时可以做什么。

 

Ø  在K8S中保护您的开源项目

大多数应用程序严重依赖于包管理器和开源存储库,因此很容易受到来自这些源的恶意或不安全代码的攻击。作为我们支持和贡献开源社区计划的一部分,JFrog开发了KubeXray,这是一个开源项目,它将Xray的安全性扩展到Kubernetes pod中运行(或即将运行)的应用程序。使用Xray通过扫描容器映像生成的元数据,KubeXray可以对已经部署的内容执行策略。

 

KubeXray监控您所有的活动Kubernetes Pod,以帮助您:

 

  • 捕获当前在所有Kubernetes Pod中运行的应用程序中最新的风险或漏洞。
  • 对正在运行的应用程序强制执行当前策略,即使您已经更改了这些策略。
  • 对未被Xray扫描且风险未知的正在运行的应用程序执行策略。

 

Ø  使用Helm 2防止未经授权的访问

Helm 2包含一个名为“Tiller”的服务器端组件。Tiller是一个集群内的服务器,它与Helm客户端交互,并与Kubernetes API服务器交互。

 

 

Tiller 绝对是很酷的,但重要的是要知道有安全问题。这是因为Helm客户端负责管理Charts,而服务器负责管理发布。这带来了很大的风险,因为Tiller使用root权限运行,有人可能会未经授权访问您的服务器。

 

Rimas Mocevicius是JFrog公司的一名员工,也是Helm公司的联合创始人,他提出了一种创新的方法来解决这种情况,即在工作站上或CI/CD管道上运行Helm和Tiller,而不将Tiller安装到Kubernetes集群中。您可以下载并安装无Tiller 的Helm v2插件。

 

Ø  使用用RBAC管理Kubernetes

必须将RBAC(基于角色的访问控制)设置为Kubernetes的管理功能,因为它允许您定义哪个用户可以管理集群及其粒度。除了定义可以列出哪些用户和应用程序之外,还可以获取、创建或删除pods和其他Kubernetes对象。一个好的实践是通过在为应用程序创建的服务帐户中设置“automountServiceAccountToken: false”来禁用对API的访问。

 

如果没有指定服务帐户,它会自动将相同名称空间中的“默认”服务帐户分配给pod。我们建议不要使用名称空间附带的默认值。始终为应用程序创建服务帐户,因为它允许您设置应用程序的限制,包括名称空间或集群范围的操作,并完全禁用对Kubernetes API的访问。

 

 

在K8S中记录日志、监视和调试应用程序

微服务的数量随着复杂性的增加而增加,问题是如何跟踪和监视它们,以及应该监视什么。当涉及到微服务时,您需要收集以下数据微服务:

 

  • 意外事件:例如,在数据库容器中执行的所有权更改
  • 微服务宕机。
  • 不正确的文件选择在生产造成混乱。
  • 不允许使用特定的基本OS版本。

 

Ø  在Kubernetes中应用程序记录日志的最佳实践

应用程序和系统日志对于排除Kubernetes集群活动的故障非常重要。

 

在Kubernetes中应用程序记录日志时,请遵循以下最佳实践::

  • 限制对日志的直接访问。
  • 在使用Kubernetes仪表板(不推荐用于生产环境)时,将仪表板设置为具有访问权限的只读。您可以允许其他成员执行故障排除,但不要完全访问仪表板,因为它可能会对Kubernetes集群造成损害。
  • 确保您的日志是实时可访问的,并且可以在稍后的阶段进行分析。
  • 使用ELK/EFK技术栈等日志收集工具(ElasticSearch、Logstash/Fluentd和Kibana)收集和索引来自系统和应用程序的所有日志。
  • 考虑将日志保存在单独的集群中,以便在稍后阶段使用日志。如果集群宕机,允许您访问日志

 

Ø  持续监控K8S中的微服务

持续监视系统和应用程序健康状况非常重要。

 

对于实时监视Kubernetes集群和其中运行的应用程序,有许多免费的和商业的解决方案。其中一个流行的解决方案是Prometheus ,Grafana的结合,提供实时监控,可以与报警工具相结合。

 

 

将应用程序部署到K8S生产环境中

Ø  在K8S顺利开始旅程的10个技巧

  1. 对于初学者,我们建议从阅读Kubernetes的艰难方式开始!

(https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/README.md)

  1. 从小事做起。从示例中学习,从一个小应用程序(nginx)开始,使用现有的演示,并尝试在Docker的Skin Kubernetes中部署应用程序。

 

  1. 在进入K8S之前准备好你的应用程序。

(https://docs.google.com/document/d/1YS_jICIEPZLle7KcpEoLjuKCZ_TkgNzb9LajPU4AhsI/edit#heading=h.81oh8o1kpi75)

 

  1. 为使应用程序在k8s中运行,设置一个最小的目标。
  2. 使用托管的k8S来解放您的工作,例如:AKS、ESK或GKE,它们为您抽象了许多复杂性。
  3. 每个Pod有一个主容器。
  4. 我们建尝试GKE 托管管理Kubernetes。
  5. 确定在Kubernetes集群内或集群外存储数据库的位置。这一点非常重要,因为您需要在集群崩溃时计划集群恢复。考虑以下:

 

-当K8S在prem上运行时:在Kubernetes中将现有的数据库作为无状态应用程序使用。

 

-在云上运行K8S时:,选择一个如PostgreSQL或MySQL 的 operator ,其知道如何在Kubernetes节点宕机时恢复的持久化数据库。

 

  1. 部署到容器云时,请将对应集群分开,运行CI/CD流水线,以及从外部CI/CD流水线部署应用到Kubernetes集群。

 

  1. 与社区合作

 

总结

正如本篇文章所描述的,我们展示了Kubernetes和JFrog Artifactory是如何让您可靠地、可预测地部署应用程序、动态地伸缩应用程序、无缝地推出新特性并有效地利用硬件资源的。

 

本篇文章旨在回顾希望采用Kubernetes作为容器编排工具的公司所面临的复杂性和挑战。我们希望我们分享的经验教训、最佳实践和技巧将帮助您在前往K8s的旅途中起步并继续前进。

你的应用有漏洞吗?使用第三方依赖需谨慎

JFrogchina阅读(915)评论(0)

引言

开源对软件的发展可以说具有深远的意义,它帮助我们共享成果,重复使用其他人开发的软件库,让我们能够专注于我们自己的创新,它推进了技术的快速发展。据不完全统计78% 的企业都在使用开源,但是其中有多少企业关注第三方开园依赖的安全呢?其中仅有13% 将安全作为第一考虑因素。可喜的是仍然有50% 的企业将安全列为第二或第三位考虑因素,越来越多的公司开始重视第三方依赖的安全性。
 

为什么要关住第三方依赖的安全性

想象我们交付的软件 Application 是一张饼,我们自己开发的代码仅占其中很小一部分,见下图:

而开源依赖并不等于是安全的,当然也不等于不安全,自2000年,仅有几家大厂贡献开源,其中有Apache, Linux, IBM, OpenSSL等,而到了2015年之后,任何人都在贡献开源社区,下图是主流软件库的发展 ,数量庞大

而我们在使用这些依赖的时候,一定要意识到:

  1. 开源依赖往往很少有进行安全性测试的
  2. 开源软件开发人源对安全意识普遍不高
  3. 开源软件提供方没有多余的预算进行安全性测试
  4. 黑客的主要攻击目标是开源,因为攻击一个,影响范围很大

 

让我们一起看几组第三方依赖安全的调查数据:

 

 

 

如何管理第三方依赖安全

我们看到第三方依赖是存在非常大的安全隐患的,那我们应该如何做呢?不使用第三方依赖显然是不现实的,我们总结了四个步骤

  1. 了解你都使用了哪些依赖
  2. 删除你不需要的依赖
  3. 查找并修复当前已知的漏洞
  4. 持续监听新发现的漏洞,重复前三个步骤

依赖分析

相对简单,我们使用目前的依赖管理工具可以轻松做到,如maven的dependency tree

删除不需要的依赖

我们发现很对开发人员在维护依赖的时候,即使该依赖已经不适用,但不会删除,这显然会扩大黑客的攻击范围,因此我们需要定期检查删除不需要的依赖

发现并修复漏洞

第三步开始较为复杂,所幸已有很多开源组织提供了免费的漏洞库,如US-CERT,NVD,OSVDB等漏洞广播源,该类组织集中维护发现的已知漏洞,对外提供表述漏洞数据描述以及漏洞广播,为开源社区安全提供数据支持,有了漏洞数据源之后,判断我们的依赖中是否有依赖就简单了,我们仅需要根据我们的依赖包与漏洞数据库进行对比,就可以发现我们发布的应用中是否包含已知的漏洞,甚至有些开源组织会在漏洞库的基础上提供关于漏洞的修复建议,如 Synk.io,JFrog 和 Sync 合作贡献了一个漏洞数据源(JXray),其中包含主流漏洞数据源,包括刚才提到的几个,这样我们就可以对我们包含对漏洞进行漏洞升级。

JXray 漏洞数据源

 

持续监听新的漏洞

我们知道漏洞是持续增长的,近几年每年平均都有900左右的新漏洞,我们需要持续监听这些新产生的漏洞,并与我们内部软件生命周期集成,与DevOps有机结合(DevSecOps),这显然需要一套平台或系统帮助我们系统的管理第三方漏洞安全,下面我们整理了一个漏洞扫描平台技术需求设计

 

 

漏洞扫描平台技术需求设计

能力分类 技术指标 指标需求描述 价值描述
扫描能力 多语言支持 支持主流语言漏洞扫描能力,如war,jar,docker,npm,python,debian,rpm等 统一监管企业各种技术栈的开发,漏洞风险与License合规分析,全面避免漏洞上线到生产环境
深度扫描能力 对二进制包深入逐层进行漏洞扫描,如war包中包含jar包 细粒度,深层次发现可能的漏洞,处理混合式软件发布体系,如Docker镜像,rpm等
分析能力 正向依赖分析 能够分析定位出扫描目标漏洞包所在位置,标出具体哪个依赖出现漏洞 为企业快速定位问题及恢复提供数据依据
反向依赖分析 能够自动化分析出漏洞包的影响范围 快速分析漏洞问题的影响范围,加速线上漏洞的恢复,最大程度降低企业风险

以及评估风险成本

漏洞库 开源漏洞数据集成 集成NVD等漏洞数据中心 针对第三方依赖包,对外部依赖包进行统一监管
商业漏洞数据集成 集成第三方商业漏洞工具能力,如

BlackDuck,

WhiteSource等

丰富漏洞数据库,最大程度降低第三方依赖漏洞风险
本地漏洞数据中心 对第三方依赖或企业自研件添加自定义漏洞,如与Jira等缺陷管理系统的集成 针对企业内部构建的软件监管,避免团队内部漏洞包进一步扩散到其他团队
其他漏洞扫描工具集成 通过API,自定义扩展对接第三方漏洞数据库,如病毒扫描工具集成 进一步丰富漏洞扫描范围,加强漏洞扫描能力,如木马病毒等
告警 自定义告警规则 不同项目管理人员可以监听各自项目或软件制品 同时提供全局监管与分级监管机制,提高项目团队自主安全意识
告警通知,自动化 邮件通知及webhook支持,

发现漏洞可以与自动化任务集成,如高危漏洞触发回滚任务

提高企业漏洞快速相应能力,甚至漏洞自修复能力,降低企业风险
生态,CI/CD 作为CI/CD软件交付质量关卡 可以在软件交付流水线中集成,根据扫描结果,继续或阻止流水线运行 多维度加强软件交付质量,增加流水线质量关卡,保证软件交付质量
RestAPI支持 提供RestFul方式对接漏洞扫描平台 方便企业与内部工具链集成
可视化 漏洞分析报表 漏洞扫描趋势图

漏洞频率top图

可视化漏洞监管能力

提供决策依据

License报表 License分布图

License兼容性分析图

可视化企业在用License

提供决策依据

 

 

 

JFrog Xray 介绍

JFrog Xray 是一个通用的漏洞扫描平台,可以满足我们对第三方漏洞安全管理的所有需求,其主要有以下几个特性

支持多语言漏洞扫描

Java,Docker,Npm,Python,Ruby Gems,Nuget,Rpm,Debian等主流语言漏洞扫描,统一对所有开发技术栈进行安全管理

深入扫描能力

我们会深入分析软件的依赖及其传递依赖,甚至是Docker 镜像中的操作系统层,如Docker 镜像中ubuntu操作系统Layer中某一个debian包存在漏洞。下图是一个Docker 镜像中包含的一个基础maven jar包含漏洞的分析图

影响范围分析

当我们监听到一个新的漏洞后,我们往往很难定为其被哪些项目依赖并试用,极为耗时,且总会有遗漏的情况出现,提高了企业损失的几率。

JFrog Xray 会根据所有收集到的依赖拓扑,进行反向依赖性分析,逐层找到所有包含漏洞包的上层应用。快速分析漏洞的影响范围,评估漏洞上线风险,指导企业进行漏洞修复

开放式集成

可以扩展与其他第三方漏洞数据平台集成,如Whitesource,Blackduck等,通过Xray 平台提供的Rest Api,甚至可以与企业自己漏洞数据源进行集成,形成企业安全的统一管理闭环。

 

DevOps 集成能力(DevSecOps)

我们可以在软件持续交付流水线中集成漏洞扫描能力,将安全机制集成进来,作为企业软件质量关卡中的一部分,当发现漏洞的时候,阻止漏洞包交付到生产环境,如下图

 

 

 

JFrog Xray 架构介绍

JFrog Xray 采用微服务架构设计,其中主要包含以下几个微服务,

  • Server,主服务,UI
  • Indexer,索引层,进行软件包索引
  • Persist,持久层,存储漏洞及扫描结果
  • Analysis,分析层,分析依赖拓扑及反向依赖,发现漏洞并告警

JFrog Xray同时支持高可用集群方式,针对企业级安全管理,提高漏洞扫描的效率及稳定性,并且与 JFrog Artifactory 通用二进制包管理系统原生集成,共同组成制品管理统一管理方案。

 

微服务数据流

 

 

 

总结

本次分享,介绍了在使用第三方依赖时的安全隐患,以及针对该类问题,我们应该如何管理第三方依赖的安全,同时介绍了JFrog Xray 的安全管理特性,帮助企业轻松管理第三方漏洞,降低企业安全风险,避免含有漏洞的包上线到生产环境或客户环境中。

优秀的DevOps工程师必须具备的软技能

JFrogchina阅读(1138)评论(0)

年末将至,大批攻城狮与程序猿早已蠢蠢欲动,开始了跳槽涨薪之旅,虽然受社会大形势影响,IT行业虽然无法和前几年的突飞猛进的势头相比,但是对DevOps的热度却只增不减,工程效能团队的普及率正在迅速增长,对DevOps工程师需求量也是呈指数式增加。转型做DevOps工程师、DevOps教练也是逐渐成为IT圈的时尚。那么如何在大量的DevOps工程师中脱颖而出,打破开发与运维之间的隔阂,成为团队内首屈一指的DevOps专家呢?

首先,DevOps没有初级工程师的说法,只要你了解这个领域,就会知道,需求、开发、构建、测试、安全、发布、部署等都是DevOps工程师必备的能力,为此我们查看所有招聘软件,DevOps工程师的招聘JD中,都会要求候选人了解git、jenkins、sonarqube、ansible、zabbix、docker、k8s、saltstack、java、python、shell、nginx、F5、mysql、redis等等等。如果这些工具、语言全部都了解,怕是初级工程师很难做到。所以一旦进入了这个领域,已经成为一位高级工程师,并且有足够的能力能Hold上述开源工具及语言了。这些都是DevOps工程师应该具备的硬实力,如果感觉自己在DevOps这个领域没有进步空间,请打开招聘软件随便看一个岗位需求,自然就会知道自己欠缺的技能。

DevOps工程师只具备上述技能点就能完美匹配职责么,为什么每次我们看到业界大拿每次在运维峰会上侃侃而谈,而自己却只能坐在工位上配置ansible、编写流水线?所以仅仅靠技术是无法成为DevOps专家的,工具及语言只是用来解决问题的手段,为此我们还需要具备下述软技能来突破瓶颈或提升个人能力:

 

  1. 敏捷及项目管理能力

DevOps与敏捷有着千丝万缕的联系,为了实现DevOps的首要目标:增强客户体验、提高创新能力、更快实现价值,那么作为一位DevOps工程师,你是否了解客户的需求、产品的目标、用户的体验、业界的发展方向等?如果不了解,请你去参与业务组的每日站会。可以通过站会了解到,需求是如何拆解的,迭代周期为什么设计为双周,发布频率、功能的使用群体等。有这样的经验积累,才能开发出更贴合业务需求的DevOps平台,业务部门也可以放心的将整个持续交付流程运行在你所开发的平台中。更好的做法是,DevOps工程师可以带领业务团队实践敏捷,结合开发的平台,设计最佳的项目管理及敏捷方案,并把方案落实到实际的项目中,最终通过交付流水线来落地,实现真正的DevOps持续交付。

 

  1. 技术布道能力

作为DevOps工程师,无论是落地了某些强大的工具链、还是引入了哪种前沿的开发理念,如果没有人去使用,依然是毫无价值。

技术布道从性质上说更靠近市场推广、而从行为细节更贴近技术。DevOps工程师首要的工作就是技术及工具链选型。选择更适合业务发展的技术方案和架构带来的工程效能的提升不是一点点的,所以对新技术的敏感性是DevOps工程师的一个核心技能。一味的适应过去的开发模式,不去尝试改变,是无法实践DevOps的。所以新的开发模式、前沿的技术理念如何在整个组织内推广就是DevOps工程师的职责了。在工具链维护、DevOps平台开发的工作之余,做好技术推广、写好技术文章、处理好与开发团队运维团队的关系,给使用者一个好的体验和目标,DevOps的转型自然会得到团队的支持。

 

  1. 成本控制能力(赚钱与花钱的能力)

站在巨人的肩膀上,我们可以看的更远,所以在DevOps建设过程中我们使用了大量的开源工具,避免自己造轮子。但是开源工具是需要维护成本和二次开发的,稳定性和安全性都是我们在使用过程中的巨大的挑战。一个DevOps工程师的成本算上社保、公积金、工资、奖金等一年不会低于500K,但是500K可以购买的商业软件确比比皆是。如果用一个工程师一年的成本去购买一个商业软件,可以节省掉3个工程师的维护和二次开发的时间,并且提高了产品的稳定性和易用性,这笔买卖不值么?用省下来的钱给工程师发奖金,不香么(当然省下来的钱也大概率不会打到员工的工资卡上)。

所以,不是全部用开源的就省钱,这个时代最贵的是人才!所以DevOps工程师要有成本控制的思维,无论在硬件还是在软件的选型上,都要精打细算,毕竟DevOps团队是个花钱的团队,花掉的钱一定要产生价值,虽然业务价值不好评估,我们可以评估节省的成本来体现DevOps的重要性。

 

  1. PPT

PPT一直是程序员的痛处,甚至一度有一些有趣的声音,比如某公司年会上对PPT的吐槽,PPT做得好会变相的认为该员工没有实际的能力,只能靠PPT汇报的精彩就得以晋升,所以流传着一句话“累死累活干不过做 PPT 的”。这种声音是错误的,,PPT 是 DOC文档的精华本,一般大多数时候通过图文图表等方式展示你要表达的重点。没有哪位专家是拿着github地址来分享代码如何构思巧妙,逻辑如何精彩的。ppt是用于人与人交流的介质,DevOps工程师可以通过吸引人的PPT帮助其他开发者理解你所推广的开发理念,接受统一的持续集成工具链。

 

  1. 演讲能力

综上,具备了项目管理能力、敏捷能力、对新技术敏感性、具备了技术布道能力,PPT能力,接下来就是演讲能力了。为什么需要演讲能力?公司内的开发人员、测试人员、运维人员都相当于你的客户,给客户演示你的DevOps平台,介绍前沿的DevOps理念,都是需要站台的,这是一个体现演讲能力最常见的场景了。所以,DevOps工程师一定不要只知道盯着屏幕撸代码,只有与其他团队加强沟通,才能慢慢消除掉彼此间的不信任,消除运维与开发之间的隔阂。推广DevOps的不只有技术,文化依然是关键的一个环节。

 

DevOps是开发运维一体化、更是工具和文化的集合体,作为一名优秀的DevOps工程师,具备全面技术能力是基础,自身软技能的积累则是决定因素。

kubernetes-部署RabbitMQ

Daniel_Ji阅读(7157)评论(0)

1、RabbitMQ简介

RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。AMQP:Advanced Message Queue,高级消息队列协议。它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言灯条件的限制。AMQP具有如下的特性:

  • 可靠性(Reliablity):使用了一些机制来保证可靠性,比如持久化、传输确认、发布确认。
  • 灵活的路由(Flexible Routing):在消息进入队列之前,通过Exchange来路由消息。对于典型的路由功能,Rabbit已经提供了一些内置的Exchange来实现。针对更复杂的路由功能,可以将多个Exchange绑定在一起,也通过插件机制实现自己的Exchange。
  • 消息集群(Clustering):多个RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker。
  • 高可用(Highly Avaliable Queues):队列可以在集群中的机器上进行镜像,使得在部分节点出问题的情况下队列仍然可用。
  • 多种协议(Multi-protocol):支持多种消息队列协议,如STOMP、MQTT等。
  • 多种语言客户端(Many Clients):几乎支持所有常用语言,比如Java、.NET、Ruby等。
  • 管理界面(Management UI):提供了易用的用户界面,使得用户可以监控和管理消息Broker的许多方面。
  • 跟踪机制(Tracing):如果消息异常,RabbitMQ提供了消息的跟踪机制,使用者可以找出发生了什么。
  • 插件机制(Plugin System):提供了许多插件,来从多方面进行扩展,也可以编辑自己的插件。

RabbitMQ中的消息都只能存储在Queue中,生产者(下图中的P)生产消息并最终投递到Queue中,消费者(下图中的C)可以从Queue中获取消息并消费。

2、RabbitMQ部署

下面是RabbitMQ部署的定义代码,此代码由两部分组成,即RabbitMQ部署的部署以及其代理服务。镜像使用的是bitnami/rabbitmq:latest。通过NodePort模式对外暴露了15672和5672端口,并通过nfs文件系统对RabbitMQ的数据进行持久化。

#-------------定义RabbitMQ部署-----------------
apiVersion: apps/v1beta2
kind: Deployment
metadata:
 name: rabbit
spec:
 replicas: 1
 selector:
   matchLabels:
     app: rabbit
 strategy:
   rollingUpdate:
     maxSurge: 25%
     maxUnavailable: 25%
   type: RollingUpdate
 template:
   metadata:
     labels:
       app: rabbit
   spec:
     containers:
     - image: bitnami/rabbitmq:latest
       imagePullPolicy: IfNotPresent
       name: rabbit
       ports:
       - containerPort: 15672
         name: rabbit15672
         protocol: TCP
       - containerPort: 5672 
         name: rabbit5672 
         protocol: TCP
       resources: {}
       volumeMounts:
       - mountPath: /bitnami
         name: rabbit-persistent-storage
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - name: rabbit-persistent-storage
        nfs:
         path: /home/nfs-share/rabbit
         server: 10.0.33.201

#-----------------定义rabbit的代理服务--------------
apiVersion: v1
kind: Service
metadata:
 name: rabbit-service
spec:
 ports:
 - name: rabbit15672
   nodePort: 31199
   port: 15672
   protocol: TCP
   targetPort: 15672
 - name: rabbit15672 
   nodePort: 305672 
   port: 5672 
   protocol: TCP 
   targetPort: 5672
 selector:
   app: rabbit
 type: NodePort

通过kubectl,执行下面的命令在Kubernetes集群中部署Oracle数据库。

$ kubectl create -f rabbitmq.yaml --namespace=kube-public

在部署完成后,通过下面的命令可以查看RabbitMQ暴露的端口:

$ kubectl get svc --namespace=kube-public

3、部署验证

在浏览器中输入:http://10.0.33.203:31199/,访问部署好的RabbitMQ。在登录页面输入用户名和密码(此处初始user/bitnami),系统将会进入RabbitMQ的主页。

4、运行环境配置

在部署时,可以通过设置下面的环境变量来改变容器的运行时:

  • RABBITMQ_USERNAME: 用户名,默认值为user
  • RABBITMQ_PASSWORD: 密码,默认值为bitnami
  • RABBITMQ_HASHED_PASSWORD: 哈希密码
  • RABBITMQ_VHOST: 安装后启动创建的虚拟主机,默认值为 /
  • RABBITMQ_ERL_COOKIE: Erlang cookie用于确定不同的节点之间是否允许行互相通信。
  • RABBITMQ_NODE_TYPE: 节点类型,有限制: statsqueue-ram or queue-disc。 默认值为stats
  • RABBITMQ_NODE_NAME: 节点名称和主机,例如: node@hostnamenode 。默认值为rabbit@localhost。
  • RABBITMQ_NODE_PORT_NUMBER: 节点端口,默认值为5672
  • RABBITMQ_CLUSTER_NODE_NAME: 集群名称,例如:clusternode@hostname
  • RABBITMQ_CLUSTER_PARTITION_HANDLING: 集群分区恢复机制,默认值为: ignore
  • RABBITMQ_MANAGER_PORT_NUMBER: 管理端口,默认值为15672
  • RABBITMQ_DISK_FREE_LIMIT: Rabbitmq存储数据的可用空间限制,当低于该值的时候,将触发流量限制。默认值为 {mem_relative, 1.0}
  • RABBITMQ_ULIMIT_NOFILES: 资源限制, 打开文件描述符的最大数目,默认值为65536

作者简介:

季向远,北京神舟航天软件技术有限公司。本文版权归原作者所有。

“云”端的语雀:用 JavaScript 全栈打造商业级应用

alicloudnative阅读(663)评论(0)

作者|  不四(死马)蚂蚁金服 语雀产品技术负责人

语雀是什么?

语雀是一个专业的云端知识库,面向个人和团队,提供与众不同的知识管理,打造轻松流畅的工作协同,它提供各种格式的在线文档(富文本、表格、设计稿等)编辑能力,支持实时在线多人协同编辑,数据云端保存不丢失。而语雀与其他文档工具最大的不同是,它通过知识库来对文档进行组织,让知识创作者更好的管理知识。

1.png

语雀技术架构演进

原型阶段

语雀诞生于 2016 年,当时蚂蚁金融云需要一个工具来承载它的文档。当时负责的技术同学利用业余时间,开始搭建这个文档工具。项目的初期,没有任何人员和资源支持,同时也为了快速验证原型,技术选型上选择了最低成本的方案。

底层服务完全基于体验技术部内部提供的 BaaS 服务和容器托管平台:

  • Object 服务:一个类 MongoDB 的数据存储服务;
  • File 服务:阿里云 OSS 的基础上封装的一个文件存储服务;
  • DockerLab:一个容器托管平台;

这些服务和平台都是基于 Node.js 实现,专门给内部创新型应用使用,也正是由于有这些降低创新成本的内部服务,才给工程师们提供了更好的创新环境。

应用层服务端自然而然的选用了体验技术部开源的 Node.js Web 框架 Egg(蚂蚁内部的封装 Chair),通过一个单体 Web 应用实现服务端。应用层客户端也选用了 React 技术栈,结合内部的 antd,并采用 CodeMirror 实现了一个功能强大、体验优雅的 markdown 在线编辑器。

2.png

这时可以算作语雀的“原型阶段”,它仅仅是一个工程师的业余项目,采用内部专为创新应用提供的 BaaS 服务和一系列的开源技术解决方案,验证了在线文档工具这个产品原型。

PS:当时我还不在语雀团队,但是巧的是我却在给语雀提供 Object、File 等 BaaS 服务和 Egg.js Web 框架的支持。

内部服务阶段

随着在线文档工具得到了团队内部的认可,语雀的目标已经不仅仅是金融云的文档工具,而是志在替代 confluence 等竞品,成为阿里内部十万员工的知识管理平台。语雀要面向知识创作者,只提供 Markdown 编辑器肯定无法让非技术人员更高效的使用语雀。尽管有不少真爱粉因为语雀开始学习甚至爱上了 Markdown,但是我们仍然义无反顾的踏入了富文本编辑器领域的深坑。同时和 Word 等富文本编辑器不同,我们选择了更“Web”的路线,在富文本编辑器中加入了公式、文本绘图、思维导图等特色功能。而随着语雀在知识管理领域的不断探索,知识管理的三层结构(团队、知识库、文档)开始成型。在此之上的协作、分享、搜索与消息动态等功能越来越复杂单纯的依靠 BaaS 服务已经无法满足语雀的业务需求了。

为了应对业务发展带来的挑战,我们主要从下面几个点进行改造:

  • BaaS 服务虽然使用简单成本低,但是它们提供的功能不足以满足语雀业务的发展,同时稳定性上也有不足。所以我们将底层服务由 BaaS 替换成了内部的 IaaS 服务(MySQL、OSS、缓存、搜索等服务)。
  • Web 层仍然采用了 Node.js 与 Egg 框架,但是业务层借鉴 rails 社区的实践开始变成了一个大型单体应用,通过引入 ORM 构建数据模型层,让代码的分层更清晰;
  • 前端编辑器从 codeMirror 迁移到 Slate。为了更好的实现语雀编辑器的功能,我们内部 fork 了 Slate 进行深入开发,同时也自定义了一个独立的内容存储格式,以提供更高效的数据处理和更好的兼容性。

3.png

在内部服务阶段,语雀已经成为了一个正式的产品,和蚂蚁的其他项目没有什么区别了,通过在阿里内部的磨炼,语雀的产品形态基本定型。

商业化阶段

随着语雀的内部影响力越来越大,一些离职出去创业的阿里校友们开始找到玉伯:“语雀挺好用的,有没有考虑商业化之后让外面的公司也能够用起来?” 经过小半年的酝酿和重构,18 年初,语雀开始正式对外提供服务,进行商业化。

当一个应用走出公司内到商业化环境中,面临的技术挑战一下子就变大了。最核心的知识创作管理部分的功能越来越复杂,表格、思维导图等新格式的加入,多人实时协同的需求对编辑器技术提出了更高的挑战。而为了更好的服务企业用户与个人用户, 语雀在企业服务、会员服务等方面也投入了很大精力。在业务快速发展的同时,服务商业化对质量、安全和稳定性也提出了更高的要求。

为了应对业务发展,语雀的架构也随之发生了演进:

我们将底层的依赖完全上云,全部迁移到了阿里云上,阿里云不仅仅提供了基础的存储、计算能力,同时也提供了更丰富的高级服务,同时在稳定性上也有保障。

  • 丰富的云计算基础服务,保障语雀的服务端可以选用最适合语雀业务的的存储、队列、搜索引擎等基础服务;
  • 更多人工智能服务给语雀的产品带来了更多的可能性,包括 OCR 识图、智能翻译等服务,最终都直接转化成为了语雀的特色服务;

而在应用层,语雀的服务端依然还是以一个基于 Egg 框架的大型的 Node.js web 应用为主。但是随着功能越来越多,也开始将一些相对比较独立的服务从主服务中拆出去,可以把这些服务分成几类:

  • 微服务类:例如多人实时协同服务,由于它相对独立,且长连接服务不适合频繁发布,所以我们将其拆成了一个独立的微服务,保持其稳定性;
  • 任务服务类:像语雀提供的大量本地文件预览服务,会产生一些任务比较消耗资源、依赖复杂。我们将其从主服务中剥离,可以避免不可控的依赖和资源消耗对主服务造成影响;
  • 函数计算类:类似 plantuml 预览、mermaid 预览等任务,对响应时间的敏感度不高,且依赖可以打包到阿里云函数计算中,我们会将其放到函数计算中运行,既省钱又安全;

随着编辑器越来越复杂,在 slate 的基础上进行开发遇到的问题越来越多。最终语雀还是走上了自研编辑器的道路,基于浏览器的 contenteditable 实现了富文本编辑器,通过 canvas 实现了表格编辑器,通过 SVG 实现了思维导图编辑器。

语雀富文本编辑器相关的介绍,可以看看 Lake Editor 之父隆昊的分享:富文本编辑器的技术演进

4.png

语雀的这个阶段(也是现在所处的阶段)是商业化阶段,但是我们仍然保持了一个很小的团队,通过 JavaScript 全栈进行研发。底层的服务全面上云,借力云服务打造语雀的特色功能。同时为企业级用户和个人知识工作者者提供知识创作和管理工具。

JavaScript 全栈

5.png

在社交网络上,大家好像对 JavaScript 全栈的看法都比较负面,“样样通,样样松”可能是大家听到全栈工程师这个名词后的第一印象。那为什么语雀选择了 JavaScript 全栈的方向呢?

JavaScript 全栈与产品工程师

在语雀,我们并不将用 JavaScript 全栈进行开发的工程师定义为全栈工程师,而是“一专多能”型的产品工程师

  • 他们是产品的“技术合伙人”,他们对产品有 owner 感,和产品经理一起参与产品讨论设计,从技术的角度上对产品设计方案提出建议,独立的完成产品功能的全栈研发,并跟踪发布后的产品结果。
  • 同时他们也是某一个技术领域的领域专家,例如有人可能是服务端领域的专家、测试领域的专家、前端构建领域的专家、CSS 领域的专家。他们可以用自己的专业领域知识来优化团队研发工具链,提升产品研发效率。

6.png

在语雀,产品工程师们的产品研发流程是这样的:

  • 在产品设计阶段,产品工程师就会参与进去进行讨论,最终会产出一份 final design 的产品设计稿。由于前期产品工程师参与充分讨论,一般此处定下的产品设计稿到后期的研发过程中不会遇到技术上的问题;
  • 随后会在语雀上进行文档化的系统分析设计。会在语雀上发起异步的评审。一些大的技术方案会有其他的领域专家加入进来一起进行评审,确保将所有的技术难点都梳理清楚;
  • 系统设计清晰后,进入研发阶段;
  • 对所有的代码,都需要有自动化测试覆盖。对所有新增代码和修改的业务逻辑都需要有完全覆盖的单元测试,对关键链路的功能同时也要提供端到端测试。编写完自动化测试是进入代码评审前的必备流程。
  • 阶段性的功能研发完成、测试编写完善后会发起异步的代码评审。会邀请相关业务的负责人和对应的一些领域专家来进行代码评审。从业务逻辑的正确性,安全性,可维护性等多个角度来进行代码评审。
  • 最终在发布上线时,必须遵循三板斧原则:可灰度、可应急、可监控。避免功能变更可能带来的 bug 影响到大量用户。

7.png

语雀是如何进行全栈 JavaScript 测试的呢?感兴趣的同学可以看看语雀团队大前端自动化测试大牛达峰老师的分享:大前端测试的思考和在语雀的实践

通过 JavaScript 全栈,语雀团队可以更高效、高质量的的完成产品研发:

  • 从代码层面上来说,有大量的代码可以复用,以编辑器举例,它不仅仅可以在 Web 端使用,也可以在桌面端使用。同时许多数据处理的能力还可以在服务端使用。
  • 从产品研发效率上来说,全栈研发减少了大量沟通成本,在语雀当前的阶段是非常高效的。而 JavaScript 全栈避免了开发者在不同的语言中进行切换,不用考虑前端使用的 lodash / moment 等工具类在其他语言中应该用什么,大大提升全栈的研发效率。
  • 最后从工程师角度来看,全栈研发让工程师有机会深度参与到产品研发的整个流程中,大家会自发的去思考产品有什么优化点,从技术上能帮助产品做什么。例如语雀最近新上的 OCR 搜图功能,就是语雀的全栈工程师自发从技术预研到产品落地完成整个产品优化的。

8.gif

JavaScript 全栈与 Node.js

说到 JavaScript 全栈,有一个绕不过去的技术就是 Node.js。作为一个与前端结合紧密的服务端运行时,基本上就成为了全栈的代言人。那 Node.js 是不是真的是一个适合大型商业化项目的语言呢?大家对它都有颇多质疑:

9.png

其实随着 JS 语言的发展,许多问题已经得到了解决,例如 Async Function 的出现,可以让开发者以同步的方式编写异步代码,理解起来更简单,异常处理也变简单了。同时随着社区的进一步完善,大量高质量的工具模块、框架涌现出来。语雀的服务端部分基于 Egg 框架,已经集成了大量 Web 开发需要的模块和服务,同时基于 Async Function 编程模型也更加简单。TypeScript 的出现也打消了许多人对 JavaScript 进行大型项目开发的疑虑。除此之外,语雀还有一些其他的方式来保障代码质量和可维护性(语雀甚至是一个纯 JavaScript 项目,没有一行 TypeScript 代码)。

语雀做的第一件事情就是确定核心系统和外部系统的边界。通过六边形架构(也叫做端口适配器架构),我们把语雀核心系统和外界系统和用户之间的交互固定下来。通过“端口”的形式,来确定输入和输出。外部系统通过“适配器”来将系统对接到语雀暴露的端口之上,只需要按照“端口”定义来实现,外部系统可以自由替换。

10.png

在这个模型下,Controller 就是语雀暴露给用户接口的 HTTP 适配器。在 Controller 中,我们对用户请求参数进行格式校验和转换,检查用户权限,并格式化输出。

11.png

我们定义好语雀与第三方平台和服务之间的交互方式(一般是一系列方法),通过适配器,将不同环境的不同服务封装成统一的方法,并在调用时记录好调用日志。

12.png

数据模型层即是数据层的 Model,以 Doc 模型举例,它的 meta 信息数据被存储在了 MySQL 中,而文档正文数据被加密后存储在 OSS 中。对于语雀核心的业务逻辑来说,完全不感知底层的存储在哪里。更进一步来说,只要语雀是使用 SQL 和数据库进行交互,底层数据可以无缝迁移到 OceanBase 等其他支持完整 SQL 语法的数据库中,即使有少量修改也可以在 Model 层封装掉。

13.png

最终以一次文档发布举例,用户通过调用 HTTP 接口与语雀进行交互,数据会通过 Model 层写入到存储中,包括 MySQL 和 OSS,更新文档缓存。同时出发异步消息给其他系统,触发钉钉的 WebHook,并将数据同步到搜索引擎中。这些和外界系统的交互通过适配器封装之后各司其职,参数转换、权限校验、日志记录,不仅确保核心逻辑的精简,也让系统调用链路跟踪更加简单。

14.png

混合应用架构

当系统发展到一定程度后,到底是应该继续在大单体应用上加功能,还是拆分成微服务呢?这两种架构既然存在,肯定有各自的优劣,具体选择那种架构形式,应该是与当前的业务规模和团队分布决定的。所以语雀的技术架构随着语雀的业务形态也变成了一个混合式的技术架构。

15.png

语雀的主服务是一个大型的 Node.js 服务,集中了所有的应用业务逻辑。而在主服务之外,还有一些不同形态的其他服务。

  • 微服务:一些独立而稳定的功能模块,或者有额外部署架构需求的服务,会通过微服务的形式独立部署,系统间暂时通过 HTTP 接口进行交互。例如实时协同服务,由于其自身比较独立稳定,而且是长连接服务,不能频繁发布重启,所以将其部署成了一个独立的微服务。
  • 任务集群:一些 CPU 密集型的任务,或者依赖了一些复杂的第三方依赖的服务,会放到一个独立的任务集群中。例如各种文件预览服务,可能依赖到了其他服务,且需要消耗大量计算成本,放到任务集群通过队列消除并发后最为合适。
  • 函数计算:一些对响应时间比较高且可以函数化的服务,我们会尽量迁移到阿里云的函数计算,例如plantuml、mermaid 等文本绘图服务。

16.png

以 mermaid 的渲染举例。用户输入一段 mermaid 代码调用语雀,语雀调用一个部署在阿里云函数计算的函数,在函数中运行 puppeteer 渲染成 svg 返回。

17.png

为什么要特别把 Serverless 单独拿出来说呢?还记得之前说 Node.js 是单线程,不适合 CPU 密集型任务么?由于 Serverless 的出现,我们可以将这些存在安全风险的,消耗大量 CPU 计算的任务都迁移到函数计算上。它运行在沙箱环境中,不用担心用户的恶意代码造成安全风险,同时将这些 CPU 密集型的任务从主服务中剥离,避免出现并发时阻塞主服务。按需付费的方式也可以大大节约成本,不需要为低频功能场景部署一个常驻服务。所以我们会尽量的把这类服务都迁移到 Serverless 上(如阿里云函数计算)。

语言之外的通用领域

除了语言之外,任何的商业化系统还有更多需要考虑的方面,其中最重要的两点可能就是安全性和稳定性了。
18.png

一个系统从前端、服务端到底层的依赖都存在着各种各样的安全风险:

  • 前端安全风险:XSS、跳转钓鱼、跨站请求等
  • 服务端安全风险:水平权限问题、未授权访问、敏感信息泄露、SSRF、SQL 注入等
  • 云服务的安全风险:短信/邮件轰炸、数据泄露风险、内容安全等

这些安全问题想要解决基本都没有银弹,只能一个个单独处理,但是有一些基本的原则:

  • 不要信任用户的任何输入
    • 任何渲染富文本的地方都需要防范 XSS,内容也可能并不是通过 IDE 输入的;
    • 要在服务端执行用户的代码一定要放在沙箱中;
    • 要从服务端请求用户传递的资源,一定要经过 SSRF 过滤;
  • 沉淀标准的编码范式来处理安全风险,且需要在 Code Review 中重点关注
    • 所有接口都必须有权限校验;
    • 响应序列化方法过滤敏感信息;
    • 不允许拼接 SQL;

语雀从商业化一开始就和安全团队通力协作,从内部的安全意识培训、内部安全团队测试,到内部的红蓝攻防、外部的白帽子渗透测试,安全是一场持久战。

19.png

为了保障语雀的稳定性,我们从前端到服务端和云服务上都做了许多工作,和安全一样,稳定性也是一个从前到后的长期工程。语雀的稳定性保障主要在两个维度:

  • 保障服务可用性:从架构设计上要杜绝单点,底层的数据都需要进行容灾和备份,服务需要多单元、可用区部署。同时避免引入不必要的强依赖;
  • 异常可监控和追溯:从前端的业务埋点日志、异常日志监控,到服务端的全链路日志跟踪和采集,系统性能监控和分析。最终我们可以达到异常可及时感知和追溯,性能问题可以定位分析;

什么叫做避免引入不必要的强依赖呢?以语雀的场景举例,MySQL 就是一个无法去除的强依赖,而缓存不应该是一个强依赖,但是最早语雀的 session 是存储在缓存(Redis)中的,一旦 Redis 集群出问题,用户资料无法获取就导致用户无法登录。这就把缓存变成了一个强依赖。所以我们将 session 存储放到了 MySQL 中,Redis 就变成了一个弱依赖,它挂了系统还能正常运行。另一个例子,语雀前段时间上线了多人实时协同编辑的功能,而在这个功能上线之前,是通过文档加锁的方式避免多个人同时编辑同一篇文档的。然而多人实时协同引入了另一个服务,一旦实时协同服务挂了,用户就无法编辑文档了,它又变成了语雀系统的一个强依赖,为了解决他,我们在用户连接协同服务失败的时候,自动切换到老的锁模式。这样协同服务也变成了语雀的一个弱依赖。

语雀如何选择技术栈

20.png

语雀这几年一步步发展过来,背后的技术一直在演进,但是始终遵循了几条原则:

  1. 技术栈选型要匹配产品发展阶段。产品在不同的阶段对技术提出的要求是不一样的,越前期,对迭代效率的要求越高,商业化规模化之后,对稳定性、性能的要求就会变高。不需要一上来就用最先进的技术方案,而是需要和产品阶段一起考虑和权衡。
  2. 技术栈选型要结合团队成员的技术背景。语雀选择 JavaScript 全栈的原因是孵化语雀的团队,大部分都是 JavaScript 背景的程序员,同时 Node.js 在蚂蚁也算是一等公民,配套的设施相对完善。
  3. 最重要的一点是,不论选择什么技术栈,安全、稳定、可维护(扩展)都是要考虑清楚的。用什么语言、用什么服务会变化,但是这些基础的安全意识、稳定性意识,如何编写可维护的代码,都是决定项目能否长期发展下去的重要因素。

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”