├── .gitignore ├── LICENSE ├── README.md ├── README_CN.md ├── SECURITY.md ├── acs-engine ├── README.md ├── README_CN.md ├── config-k8s-dashboard.md └── config_k8s_ui_http.sh ├── aks-engine ├── README.md ├── config-k8s-dashboard.md ├── config_k8s_ui_http.sh └── example │ ├── kubernetes-1.11.5.json │ └── kubernetes-vmss-1.13.2.json ├── aks ├── README.md ├── cluster-autoscaler-deployment-mooncake.yaml └── gpu-support.md ├── cicd ├── README.md ├── README_CN.md ├── armtemplate │ └── jenkins_private_registry_k8s │ │ ├── azuredeploy.json │ │ ├── azuredeploy.parameters.json │ │ └── metadata.json └── script │ ├── README.md │ ├── bash │ ├── README.md │ └── create-service-principal.sh │ ├── deploy-dev-ops │ ├── README.md │ └── deploy-dev-ops.sh │ ├── jenkins │ ├── README.md │ ├── add-aptly-build-job.sh │ ├── add-docker-build-deploy-k8s.sh │ ├── add-docker-build-job.sh │ ├── basic-aptly-build-job.xml │ ├── basic-docker-build-deploy-k8s-job.xml │ ├── basic-docker-build-deploy-k8s.groovy │ ├── basic-docker-build-job.xml │ ├── basic-docker-build.groovy │ ├── basic-user-pwd-credentials.xml │ ├── init-aptly-repo.sh │ ├── install_jenkins.sh │ ├── install_jenkins_plugin.sh │ ├── jenkins-on-azure │ │ ├── azure.svg │ │ ├── copy.png │ │ ├── headshot.png │ │ ├── index.html │ │ ├── install-web-page.sh │ │ ├── site.css │ │ ├── site.js │ │ └── title.png │ ├── jenkins-verified-ver │ ├── run-cli-command.sh │ └── unsecure-jenkins-instance.sh │ ├── powershell │ ├── Jenkins-Windows-Init-Script-SSH.ps1 │ ├── Jenkins-Windows-Init-Script-no-secrets.ps1 │ ├── Jenkins-Windows-Init-Script.ps1 │ ├── Migrate-Image-From-Classic.ps1 │ └── README.md │ ├── quickstart_template │ ├── 101-spinnaker.sh │ ├── 201-jenkins-acr.sh │ ├── 201-jenkins-private-registry-k8s.sh │ ├── 301-jenkins-acr-spinnaker-k8s.sh │ └── 301-jenkins-aptly-spinnaker-vmss.sh │ ├── solution_template │ ├── jenkins │ │ ├── createUiDefinition.json │ │ └── mainTemplate.json │ ├── nested │ │ ├── VM-password.json │ │ ├── VM-sshPublicKey.json │ │ ├── publicIP-existing.json │ │ ├── publicIP-new.json │ │ ├── spinnaker-VM-Init.json │ │ ├── storageAccount-existing.json │ │ └── storageAccount-new.json │ └── spinnaker │ │ ├── createUiDefinition.json │ │ └── mainTemplate.json │ └── spinnaker │ ├── add_k8s_pipeline │ ├── README.md │ ├── add_k8s_pipeline.sh │ ├── application.json │ ├── load_balancer.json │ └── pipeline.json │ ├── copy_kube_config │ ├── README.md │ └── copy_kube_config.sh │ └── install_halyard │ ├── README.md │ └── install_halyard.sh ├── doc └── imgs │ ├── cicd_architecture.png │ └── monitor.png ├── monitoring ├── README.md ├── README_CN.md └── k8s │ ├── controller │ ├── config.sh │ ├── manual_config.sh │ └── nginx-config │ │ └── nginx-site.conf │ ├── deployment │ ├── AzureChinaCloud │ │ └── controller_parameters.json │ ├── AzureCloud │ │ └── controller_parameters.json │ └── controller_template.json │ ├── helm-charts │ ├── configs │ │ ├── elk_azure_china_cloud.yaml │ │ ├── grafana.yaml │ │ ├── heapster.yaml │ │ ├── heartbeat-config │ │ │ └── heartbeat.yml │ │ ├── heartbeat.yaml │ │ └── influxdb.yaml │ ├── elk │ │ ├── Chart.yaml │ │ ├── charts │ │ │ ├── elastic_search_chart │ │ │ │ ├── Chart.yaml │ │ │ │ ├── templates │ │ │ │ │ ├── es_client_deployment.yaml │ │ │ │ │ ├── es_configmap.yaml │ │ │ │ │ ├── es_data_service.yaml │ │ │ │ │ ├── es_data_statefullset.yaml │ │ │ │ │ ├── es_discovery_service.yaml │ │ │ │ │ ├── es_master_deployment.yaml │ │ │ │ │ └── es_service.yaml │ │ │ │ └── values.yaml │ │ │ ├── filebeat_chart │ │ │ │ ├── Chart.yaml │ │ │ │ ├── templates │ │ │ │ │ ├── filebeat_configmap.yaml │ │ │ │ │ └── filebeat_deployment.yaml │ │ │ │ └── values.yaml │ │ │ ├── kibana_chart │ │ │ │ ├── Chart.yaml │ │ │ │ ├── templates │ │ │ │ │ ├── kibana_configmap.yaml │ │ │ │ │ ├── kibana_deployment.yaml │ │ │ │ │ └── kibana_service.yaml │ │ │ │ └── values.yaml │ │ │ └── logstash_chart │ │ │ │ ├── Chart.yaml │ │ │ │ ├── pipeline │ │ │ │ └── logstash.conf │ │ │ │ ├── templates │ │ │ │ ├── logstash_configmap.yaml │ │ │ │ ├── logstash_deployment.yaml │ │ │ │ └── logstash_service.yaml │ │ │ │ └── values.yaml │ │ ├── templates │ │ │ └── _helpers.tpl │ │ └── values.yaml │ ├── grafana │ │ ├── Chart.yaml │ │ ├── README.md │ │ ├── templates │ │ │ ├── NOTES.txt │ │ │ ├── _helpers.tpl │ │ │ ├── configmap.yaml │ │ │ ├── dashboards-configmap.yaml │ │ │ ├── deployment.yaml │ │ │ ├── ingress.yaml │ │ │ ├── job.yaml │ │ │ ├── pvc.yaml │ │ │ ├── secret.yaml │ │ │ └── svc.yaml │ │ └── values.yaml │ ├── heapster │ │ ├── Chart.yaml │ │ ├── README.md │ │ ├── templates │ │ │ ├── NOTES.txt │ │ │ ├── _helpers.tpl │ │ │ ├── deployment.yaml │ │ │ └── service.yaml │ │ └── values.yaml │ ├── heartbeat │ │ ├── Chart.yaml │ │ ├── config │ │ │ └── heartbeat.yml │ │ ├── templates │ │ │ ├── _helpers.tpl │ │ │ ├── configmap.yaml │ │ │ └── deployment.yaml │ │ └── values.yaml │ └── influxdb │ │ ├── .helmignore │ │ ├── Chart.yaml │ │ ├── README.md │ │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── config.yaml │ │ ├── deployment.yaml │ │ ├── post-install-set-auth.yaml │ │ ├── pvc.yaml │ │ ├── secret.yaml │ │ └── service.yaml │ │ └── values.yaml │ └── licenses │ ├── charts.md │ └── elk-acs-kubernetes.md ├── private-docker-registry ├── README.md ├── README_CN.md ├── azuredeploy-template.json ├── azuredeploy.parameters.json ├── certs │ ├── server.crt │ └── server.key ├── cloud-config-template.yml ├── config-insecure-registry-in-master.sh ├── config-insecure-registry.sh ├── deploy-docker-registry.sh └── images │ └── 1.png └── resources └── kured-1.1.0.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevOps Open Source Solution for Azure China 2 | 3 | ## Overview 4 | 5 | DevOps open source solution helps user to set up container-based cluster with orchestrator(including Kubernetes, DC/OS, Docker Swarm) supported quickly and easily on Azure China. Also this solution provides CI/CD pipeline enabled by Jenkins and plugins, and monitoring stacks(ELK + Grafana) reference implementation. It includes several parts: 6 | 7 | * Container-based Clusters: Created by [acs-engine](https://github.com/Azure/acs-engine), users could choose DC/OS, Kubernetes, or Swarm as the orchestrator. We choose Kubernetes as the reference implementation in this project 8 | * Private Docker registry: store custom images 9 | * CI/CD Pipeline: CI/CD pipeline implementation based on Jenkine and plugins 10 | * Monitoring Stack: Cluster(node + pod) resource and container/app monitoring and log analytics 11 | 12 | ## Architecture 13 | * K8S cluster architecture deployed with acs-engine 14 | ![Image of k8s architecture](https://docs.microsoft.com/en-us/azure/container-service/kubernetes/media/acs-intro/kubernetes.png) 15 | 16 | * CI/CD with Open Source Toolchain: 17 | ![Image of CI/CD architecture](doc/imgs/cicd_architecture.png) 18 | 19 | * Monitor reference architcture: 20 | ![Image of monitor architecture](doc/imgs/monitor.png) 21 | 22 | ## User guides 23 | 24 | If you'd like to deploy from beginning, please follow below holistic steps. If you already have some components being used in your project, you could pick the missing parts from this project and deploy it separately. 25 | 26 | * [Deploy a Kubernetes cluster using acs-engine](acs-engine/README.md) - shows you how to use the acs-engine to build container-based clusters. 27 | * [Deploy a Private docker registry](private-docker-registry/README.md) - describes how to deploy a secure private docker registry 28 | * [CI/CD pipeline](cicd/README.md) - shows how to deploy a Jenkins master and create pipeline which includes below 5 steps: 29 | * Check out git repro 30 | * Build Docker images 31 | * Push docker image to private docker registry 32 | * Test and validation 33 | * Deploy to Kubernetes 34 | * [Monitor](monitoring/README.md) - shows how to set up monitoring stacks 35 | * Heapster + Influxdb + Grafana 36 | * Beats + Logstash + Elasticsearch + Kibana 37 | 38 | 39 | ## Contributing 40 | 41 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 42 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 43 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 44 | 45 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 46 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 47 | provided by the bot. You will only need to do this once across all repos using our CLA. 48 | 49 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 50 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 51 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 52 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # DevOps开源解决方案 2 | 3 | ## 概览 4 | 5 | 此开源解决方案帮助用户快速搭建基于Azure容器技术的微服务和DevOps容器集群,并提供基于Jenkins的持续集成和持续部署管道,以及基于ELK和Grafana的监控和分析实现。主要包括下面几个组成部分: 6 | * 容器集群: 使用[acs-engine](https://github.com/Azure/acs-engine)创建容器集群,用户可以选择DC/OS,Kubernetes,Swarm作为编排工具。acs-engine还会帮助您创建负载均衡,网络管理,安全和存储等相关组件,以及完成高可用性(Availability Set)等相关设置,使您可以在容器集群上方便地部署容器化应用。在这个项目中,我们选择Kubernetes作为参考实现 7 | * 私有镜像仓库: 镜像仓库可以和容器编排引擎(如Kubernetes,Swarm,DC/OS)进行集成,用于存储自定义的镜像。此镜像仓库兼容Docker格式的镜像仓库,可以和Docker工具进行无缝迁移 8 | * CI/CD管道: 基于Jenkins的持续集成和持续部署(CI/CD)管道实现 9 | * 监控和日志: 包括集群资源(Node + Pod)以及容器(container)和应用(app)的监控及日志分析 10 | 11 | ## 参考架构 12 | 13 | * 使用acs-engine部署的Kubernetes容器集群架构 14 | ![Image of K8S architecture](https://docs.microsoft.com/en-us/azure/container-service/kubernetes/media/acs-intro/kubernetes.png) 15 | 16 | * CI/CD开源解决方案: 17 | ![Image of CI/CD architecture](doc/imgs/cicd_architecture.png) 18 | 19 | * 监控和日志参考架构: 20 | ![Image of monitor architecture](doc/imgs/monitor.png) 21 | 22 | ## 用户指南 23 | 24 | 此项目按模块化进行设计,每一部分都可以单独部署和使用。用户可以根据实际的需要,选择其中的某一部分单独进行部署。也可以按照下面的步骤从头搭建完整的devops开源解决方案。 25 | * [使用acs-engine部署Kubernete集群](acs-engine/README_CN.md) - 描述如何使用acs-engine将一个容器集群文件转化成一组ARM模板,通过在Azure上部署这些模板建立一套基于Docker的容器服务集群。 26 | * [创建私有镜像仓库](private-docker-registry/README_CN.md) - 描述如何在Azure上部署安全的私有镜像仓库 27 | * [基于Jenkins的CI/CD管道实现](cicd/README_CN.md) - 展示如何ARM部署基于Jenkins的持续集成和持续部署(CI/CD)管道实现。目前的管道实现包括5个步骤: 28 | * 从GitHub迁出代码 29 | * 构建Docker镜像 30 | * 推送镜像到私有镜像参考 31 | * 测试和验证 32 | * 发布到Kubernetes集群 33 | * [基于ELK和Grafana的监控与日志分析实现](monitoring/README_CN.md) - 使用ARM模板在容器机器上部署下面的工具链: 34 | * Heapster + Influxdb + Grafana(用于集群资源的监控,如对于Node/Pod的CPU,内存,网络等资源的监控) 35 | * Beats + Logstash + Elasticsearch + Kibana (用于容器/应用的日志收集和分析,以及服务状态的监控) 36 | 37 | 38 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /acs-engine/README_CN.md: -------------------------------------------------------------------------------- 1 | # 微软Azure容器服务引擎 2 | 3 | 微软容器服务引擎(`acs-engine`)用于将一个容器集群描述文件转化成一组ARM(Azure Resource Manager)模板,通过在Azure上部署这些模板,用户可以很方便地在Azure上建立一套基于Docker的容器服务集群。用户可以自由地选择集群编排引擎DC/OS, Kubernetes或者是Swarm/Swarm Mode。集群描述文件使用和ARM模板相同的语法,它们都可以用来部署Azure容器服务。关于acs-engine的详细内容请参考:https://github.com/Azure/acs-engine 4 | 5 | ## 1. 安装acs-engine(建议安装v0.14.0及后续的版本,之前的版本需要做一些额外的工作才可以工作)。支持直接安装包和通过源代码编译两种方式: 6 | - 下载并解压具体版本的[acs-engine](https://github.com/Azure/acs-engine/releases/),对于没有安装包的版本,可直接从国内的镜像站点下载:https://mirror.kaiyuanshe.cn/kubernetes/acs-engine/ 7 | ``` 8 | curl -LO https://mirror.kaiyuanshe.cn/kubernetes/acs-engine/v0.14.0/acs-engine-v0.14.0-linux-amd64.tar.gz 9 | tar -xvzf acs-engine-v0.14.0-linux-amd64.tar.gz 10 | ``` 11 | - [本地下载源代码并编译acs-engine](https://github.com/Azure/acs-engine/blob/master/docs/acsengine.zh-CN.md) 12 | 13 | 14 | ## 2. 准备一个SSH公钥私钥对 15 | 除了使用Kubernetes APIs和集群进行交互外,还可以通过SSH的方式访问master和agent节点。如果你还没有生成SSH Key,[可以直接生成一个新的](https://github.com/Azure/acs-engine/blob/master/docs/ssh.md#ssh-key-generation)。 16 | ``` 17 | ssh-keygen -t rsa 18 | ``` 19 | 20 | ## 3. [安装azure-cli](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) 21 | ``` 22 | sudo su 23 | echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ wheezy main" | sudo tee /etc/apt/sources.list.d/azure-cli.list 24 | apt-key adv --keyserver packages.microsoft.com --recv-keys 417A0893 25 | apt-get install -y apt-transport-https 26 | apt-get update 27 | apt-get install -y azure-cli 28 | ``` 29 | 30 | ## 4. 创建Service Principle 31 | K8S集群集成了对各种云提供商核心功能的支持。在Azure上,acs-engine使用Service Principle和ARM进行交互。根据说明创建一个新的[service principal](https://github.com/Azure/acs-engine/blob/master/docs/serviceprincipal.md). 32 | ``` 33 | az cloud set -n AzureChinaCloud 34 | az login 35 | az account set --subscription="${SUBSCRIPTION_ID}" (if there is only one subscription, this step is optional) 36 | az ad sp create-for-rbac --name XXX 37 | ``` 38 | 39 | ## 5. 克隆并编辑Kubernetes集群定义文件[example/kubernetes.json](https://raw.githubusercontent.com/Azure/acs-engine/master/examples/kubernetes.json),将需要的参数配置好。点击查看关于[集群定义文件](https://github.com/Azure/acs-engine/blob/master/docs/clusterdefinition.zh-CN.md)的详细说明。 40 | * adminUsername - 修改agent用户名 41 | * dnsPrefix - 设置集群DNS名称前缀 42 | * keyData - 使用SSH公钥填充 43 | * clientId - 使用Service Principle中的appId填充 44 | * secret - 使用Service Principle中的password填充 45 | * 在`apiVersion: "vlabs"`后面增加位置定义`"location": "chinaeast",` (这一步不能缺少) 46 | 47 | ## 6. 生成ARM模板 48 | 运行`acs-engine generate kubernetes.json`命令生成ARM模板。主要包括多个类似如下模板的文件: 49 | * apimodel.json - 集群配置文件 50 | * azuredeploy.json - 核心的ARM (Azure Resource Model)模板,用来部署Docker集群 51 | * azuredeploy.parameters.json - 部署参数文件,其中的参数可以自定义 52 | * certificate and access config files - 某些编排引擎例如kubernetes需要生成一些证书,这些证书文件和它依赖的kube config配置文件也存放在和ARM模板同级目录下面 53 | 54 | ## 7. 使用ARM模板部署K8S容器集群 55 | ``` 56 | az cloud set -n AzureChinaCloud 57 | az login 58 | az group create -l chinaeast -n xxx 59 | az group deployment create -g xxx --template-file azuredeploy.json --parameters azuredeploy.parameters.json 60 | ``` 61 | 62 | ## 8. 验证集群安装是否正确 63 | SSH登录到集群master节点,并执行以下命令。如果在default和kube-system命名空间下面的services(kubernetes, heapster,kube-dns,kubernetes-dashboard,tiller-deploy)运行正常,则说明安装成功。 64 | ``` 65 | kubectl get services --all-namespaces 66 | ``` 67 | 68 | ## 9. 配置Kubernetes管理网站 (可选) 69 | > SSH登录到集群master节点 70 | ``` 71 | ssh -i @ 72 | ``` 73 | > 下载 config_k8s_ui_http.sh 脚本 74 | ``` 75 | curl -LO https://raw.githubusercontent.com/Azure/devops-sample-solution-for-azure-china/acs-engine/config_k8s_ui_http.sh 76 | ``` 77 | > 通过以下命令运行脚本: 78 | ``` 79 | bash config_k8s_ui_http.sh -c -g -t -i -s -u -p 80 | ``` 81 | 参数说明: 82 | * -c [Azure实例名, AzureCloud 或者 AzureChinaCloud]" 83 | * -g [资源组名]" 84 | * -t [Service principal tenant id, 例如. foo.onmicrosoft.com, bar.partner.onmschina.cn etc. ]" 85 | * -i [Service principal app id]" 86 | * -s [Service principal secret]" 87 | * -u [Kubernetes 管理网站用户名, 默认值是 'admin']" 88 | * -p [Kubernetes 管理网站用户密码, 默认值是 'password']" 89 | 90 | > 通过以下链接访问Kubernetes管理网站: 91 | ``` 92 | http:///ui 93 | ``` 94 | -------------------------------------------------------------------------------- /acs-engine/config-k8s-dashboard.md: -------------------------------------------------------------------------------- 1 | ## Config kubernetes dashboard (only for testing purpose) 2 | - Login to master node via SSH 3 | ``` 4 | ssh -i @ 5 | ``` 6 | - Download config_k8s_ui_http.sh script 7 | ``` 8 | curl -LO https://raw.githubusercontent.com/Azure/devops-sample-solution-for-azure-china/master-dev/acs-engine/config_k8s_ui_http.sh 9 | ``` 10 | - Run following command: 11 | ``` 12 | bash config_k8s_ui_http.sh -c -g -t -i -s -u -p 13 | ``` 14 | Usages: 15 | * -c [Cloud instance name, AzureCloud or AzureChinaCloud]" 16 | * -g [Resource group]" 17 | * -t [Service principal tenantId, e.g. 89e1b688-8d74-xxx-9680-54d0a43a4f0d ]" 18 | * -i [Service principal app id]" 19 | * -s [Service principal secret]" 20 | * -u [Kubernetes dashboard user name, default value is 'admin']" 21 | * -p [Kubernetes dashboard user password, default value is 'password']" 22 | 23 | - Access dashboard via following link: 24 | ``` 25 | http:///api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ 26 | ``` 27 | 28 | > You may hit access error when using kubernetes dashboard, run following command and refresh: 29 | > ``` 30 | > kubectl create clusterrolebinding kubernetes-dashboard --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard 31 | > ``` 32 | -------------------------------------------------------------------------------- /aks-engine/config-k8s-dashboard.md: -------------------------------------------------------------------------------- 1 | ## Config kubernetes dashboard (only for testing purpose) 2 | - Login to master node via SSH 3 | ``` 4 | ssh -i @ 5 | ``` 6 | - Download config_k8s_ui_http.sh script 7 | ``` 8 | curl -LO https://raw.githubusercontent.com/Azure/devops-sample-solution-for-azure-china/master-dev/acs-engine/config_k8s_ui_http.sh 9 | ``` 10 | - Run following command: 11 | ``` 12 | bash config_k8s_ui_http.sh -c -g -t -i -s -u -p 13 | ``` 14 | Usages: 15 | * -c [Cloud instance name, AzureCloud or AzureChinaCloud]" 16 | * -g [Resource group]" 17 | * -t [Service principal tenantId, e.g. 89e1b688-8d74-xxx-9680-54d0a43a4f0d ]" 18 | * -i [Service principal app id]" 19 | * -s [Service principal secret]" 20 | * -u [Kubernetes dashboard user name, default value is 'admin']" 21 | * -p [Kubernetes dashboard user password, default value is 'password']" 22 | 23 | - Access dashboard via following link: 24 | ``` 25 | http:///api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ 26 | ``` 27 | 28 | > You may hit access error when using kubernetes dashboard, run following command and refresh: 29 | > ``` 30 | > kubectl create clusterrolebinding kubernetes-dashboard --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard 31 | > ``` 32 | -------------------------------------------------------------------------------- /aks-engine/example/kubernetes-1.11.5.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "vlabs", 3 | "location": "chinaeast2", 4 | "properties": { 5 | "orchestratorProfile": { 6 | "orchestratorType": "Kubernetes", 7 | "orchestratorVersion": "1.11.5" 8 | }, 9 | "masterProfile": { 10 | "count": 1, 11 | "dnsPrefix": "k8s1115", 12 | "vmSize": "Standard_D2_v2" 13 | }, 14 | "agentPoolProfiles": [ 15 | { 16 | "name": "agentpool1", 17 | "count": 2, 18 | "vmSize": "Standard_D2_v2", 19 | "availabilityProfile": "AvailabilitySet" 20 | } 21 | ], 22 | "linuxProfile": { 23 | "adminUsername": "azureuser", 24 | "ssh": { 25 | "publicKeys": [ 26 | { 27 | "keyData": "ssh-rsa ... user@dev" 28 | } 29 | ] 30 | } 31 | }, 32 | "servicePrincipalProfile": { 33 | "clientId": "63ae75bb-xxxx-xxxx-xxxx-6beca315b963", 34 | "secret": "" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /aks-engine/example/kubernetes-vmss-1.13.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiVersion": "vlabs", 3 | "location": "chinaeast2", 4 | "properties": { 5 | "orchestratorProfile": { 6 | "orchestratorType": "Kubernetes", 7 | "orchestratorVersion": "1.13.2" 8 | }, 9 | "masterProfile": { 10 | "count": 1, 11 | "dnsPrefix": "andy-vmss1132", 12 | "vmSize": "Standard_D2_v2" 13 | }, 14 | "agentPoolProfiles": [ 15 | { 16 | "name": "agentpool1", 17 | "count": 2, 18 | "vmSize": "Standard_D2_v2", 19 | "availabilityProfile": "VirtualMachineScaleSets" 20 | } 21 | ], 22 | "linuxProfile": { 23 | "adminUsername": "azureuser", 24 | "ssh": { 25 | "publicKeys": [ 26 | { 27 | "keyData": "ssh-rsa ... user@dev" 28 | } 29 | ] 30 | } 31 | }, 32 | "servicePrincipalProfile": { 33 | "clientId": "63ae75bb-xxxx-xxxx-xxxx-6beca315b963", 34 | "secret": "" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /aks/cluster-autoscaler-deployment-mooncake.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: cluster-autoscaler 6 | name: cluster-autoscaler 7 | namespace: kube-system 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: cluster-autoscaler 13 | template: 14 | metadata: 15 | labels: 16 | app: cluster-autoscaler 17 | spec: 18 | serviceAccountName: cluster-autoscaler 19 | containers: 20 | - image: gcr.azk8s.cn/google-containers/cluster-autoscaler:v1.2.2 21 | imagePullPolicy: Always 22 | name: cluster-autoscaler 23 | resources: 24 | limits: 25 | cpu: 100m 26 | memory: 300Mi 27 | requests: 28 | cpu: 100m 29 | memory: 300Mi 30 | command: 31 | - ./cluster-autoscaler 32 | - --v=3 33 | - --logtostderr=true 34 | - --cloud-provider=azure 35 | - --skip-nodes-with-local-storage=false 36 | - --nodes=1:10:nodepool1 37 | env: 38 | - name: ARM_SUBSCRIPTION_ID 39 | valueFrom: 40 | secretKeyRef: 41 | key: SubscriptionID 42 | name: cluster-autoscaler-azure 43 | - name: ARM_RESOURCE_GROUP 44 | valueFrom: 45 | secretKeyRef: 46 | key: ResourceGroup 47 | name: cluster-autoscaler-azure 48 | - name: ARM_TENANT_ID 49 | valueFrom: 50 | secretKeyRef: 51 | key: TenantID 52 | name: cluster-autoscaler-azure 53 | - name: ARM_CLIENT_ID 54 | valueFrom: 55 | secretKeyRef: 56 | key: ClientID 57 | name: cluster-autoscaler-azure 58 | - name: ARM_CLIENT_SECRET 59 | valueFrom: 60 | secretKeyRef: 61 | key: ClientSecret 62 | name: cluster-autoscaler-azure 63 | - name: ARM_VM_TYPE 64 | valueFrom: 65 | secretKeyRef: 66 | key: VMType 67 | name: cluster-autoscaler-azure 68 | - name: AZURE_CLUSTER_NAME 69 | valueFrom: 70 | secretKeyRef: 71 | key: ClusterName 72 | name: cluster-autoscaler-azure 73 | - name: AZURE_NODE_RESOURCE_GROUP 74 | valueFrom: 75 | secretKeyRef: 76 | key: NodeResourceGroup 77 | name: cluster-autoscaler-azure 78 | - name: ARM_CLOUD 79 | value: AzureChinaCloud 80 | restartPolicy: Always 81 | -------------------------------------------------------------------------------- /aks/gpu-support.md: -------------------------------------------------------------------------------- 1 | ## GPU workload support on Azure China AKS 2 | [Use GPUs for compute-intensive workloads on Azure Kubernetes Service (AKS)](https://docs.microsoft.com/en-us/azure/aks/gpu-cluster) provides detailed steps about how to run GPU workloads on AKS cluster, while there are some configurations needed to change on Azure China. e.g. following docker hub images should be changed to use `dockerhub.azk8s.cn`: 3 | 4 | | original image in doc | supported images on Azure China | 5 | | ---- | ---- | 6 | | k8s-device-plugin:1.11 | dockerhub.azk8s.cn/nvidia/k8s-device-plugin:1.11 | 7 | | microsoft/samples-tf-mnist-demo:gpu | dockerhub.azk8s.cn/microsoft/samples-tf-mnist-demo:gpu | 8 | 9 | Below are detailed steps about how to run GPU workload on Azure China AKS cluster: 10 | ## Prerequisite 11 | Make sure your Azure subscription could create NC serial VMs, e.g. `Standard_NC6s_v3`, otherwise you may file a support ticket to enable that kind of VM size for your Azure subscription. 12 | 13 | ## 1. set up AKS cluster on GPU enabled VM 14 | > Below example sets `node-vm-size` as `Standard_NC6s_v3` which supports GPU on Azure China, on global azure, `node-vm-size` could be `Standard_NC6` etc. 15 | 16 | ```sh 17 | RESOURCE_GROUP_NAME=demo-gpu1126 18 | CLUSTER_NAME=demo-gpu1126 19 | LOCATION=chinaeast2 20 | az group create -n $RESOURCE_GROUP_NAME -l $LOCATION 21 | 22 | az aks create -g $RESOURCE_GROUP_NAME -n $CLUSTER_NAME --node-count 1 --node-vm-size Standard_NC6s_v3 --disable-rbac --generate-ssh-keys --kubernetes-version 1.12.6 -l $LOCATION 23 | az aks get-credentials -g $RESOURCE_GROUP_NAME -n $CLUSTER_NAME 24 | kubectl get nodes 25 | ``` 26 | 27 | ## 2. install GPU plugin on AKS cluster 28 | ```sh 29 | kubectl create -f https://raw.githubusercontent.com/andyzhangx/demo/master/linux/gpu/nvidia-device-plugin-ds-mooncake.yaml 30 | ``` 31 | 32 | ## 3. Run GPU workload on AKS cluster 33 | ```sh 34 | kubectl create -f https://raw.githubusercontent.com/andyzhangx/demo/master/linux/gpu/gpu-demo-mooncake.yaml 35 | ``` 36 | 37 | For more detailed steps, refer to [Use GPUs for compute-intensive workloads on Azure Kubernetes Service (AKS)](https://docs.microsoft.com/en-us/azure/aks/gpu-cluster) 38 | -------------------------------------------------------------------------------- /cicd/README_CN.md: -------------------------------------------------------------------------------- 1 | # 基于 Jenkins 的持续集成和持续部署(CI/CD)管道实现 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 这个模板帮助你在Azure中国上快速搭建一台基于Linux Ubuntu 14.04 LTS的型号为DS1_v2的Jenkins虚拟机 11 | 12 | 另外它会创建一个Jenkins流水线,包括从一个包含dockerfile的代码仓库中迁出代码,编译并生成Docker镜像,然后将Docker镜像推送到一个私有镜像仓库,最后将镜像部署到一个Kubernetes集群。 13 | 14 | ## A. 部署一个内嵌了包含编译和发布Docker镜像流水线的Jenkins虚拟机 15 | 1. 点击 "Deploy to Azure" 按钮. 如果你还没有Azure中国的订阅,可以到[Azure中国的官网](http://www.azure.cn)申请订阅并免费试用. 16 | 1. 输入用来部署Jenkins虚拟机的用户名和密码,并提供虚拟机的DNS前缀。 17 | 1. 输入一个代码仓库,代码仓库必须在根目录中包含一个Dockerfile。 18 | 1. 提供一个私有Docker镜像仓库的地址, 以及登陆的用户名和密码。(如果使用本项目中部署的HTTP private registry,镜像仓库地址应为http://< DNS or Public IP >:5000) 19 | 1. 提供Kubernetes master FQDN, 用户名和私有的encode过的key [base64](https://en.wikipedia.org/wiki/Base64),流水线会部署一个示例项目到kubernetes集群中. 你可以使用[在线工具](https://www.bing.com/search?q=base64+encode&qs=AS&pq=base64+&sk=AS1&sc=8-7&cvid=FFECC475833E43958634B83EA90B2364&FORM=QBLH&sp=2) 进行encode. 20 | 21 | ## B. 配置 SSH port forwarding 22 | **默认Jenkins使用http协议, 监听8080端口,用户不能通过不安全的协议被验证!** 23 | 24 | 你需要配置端口forwarding以在你本机打开Jenkins的图形界面,如果你不知道虚拟机的完整DNS名字,可以通过: `Resource Groups > {Resource Group Name} > Deployments > {Deployment Name, usually 'Microsoft.Template'} > Outputs`来查看。 25 | 26 | ### 如果你使用Windows系统: 27 | 安装putty并运行以下命令 28 | 29 | ``` 30 | putty.exe -ssh -L 8080:localhost:8080 @ 31 | ``` 32 | 33 | 或者通过以下步骤手动操作: 34 | 1. 打开putty,选则 'Connection > SSH > Tunnels' 35 | 1. 在 Options controlling SSH port forwarding 界面, 输入8080端口. 然后输入 127.0.0.1:8080作为目标. 点击添加 36 | 1. 点击 Open to establish the connection. 37 | 38 | ### 如果你使用的是 Linux or Mac: 39 | 运行以下命令: 40 | ```bash 41 | ssh -L 8080:localhost:8080 @ 42 | ``` 43 | 44 | ## C. 连接 Jenkins 45 | 46 | 1. 当你配置了ssh forwarding以后,你可以在本机上通过 http://localhost:8080/ 访问jenkins的管理界面. 47 | 1. 第一次登陆jenkins管理界面需要一个token, 你可以登陆到虚拟机然后运行 `sudo cat /var/lib/jenkins/secrets/initialAdminPassword` 查看token. 48 | 1. 现在你可以开始使用jenkins了! 或者你可以通过http://< Public DNS name of instance you just created > 查看一个不可修改的jenkins管理界面. 49 | 1. 如果你想利用Azure VM作为jenkins的agent,可以安装插件 http://aka.ms/azjenkinsagents 50 | 51 | ## 注意事项 52 | 如果你使用的是不安全的私有镜像仓库, 例如你是通过http而不是https访问镜像仓库,或者你使用的证书没有被授信。你需要在jenkins master和kubernets集群的每个节点上都运行以下命令 53 | ```bash 54 | sudo touch /etc/docker/daemon.json 55 | sudo vim /etc/docker/daemon.json 56 | ``` 57 | then add below entry to configuration: 58 | 59 | {"insecure-registries" : [ "私有镜像仓库的DNS/IP:端口" ]} 60 | 61 | then save the changes and run below command to restart docker 62 | ```bash 63 | sudo service docker restart 64 | ``` 65 | 66 | ## 示例项目 67 | 这个模板中包含的jenkins流水线基于示例项目( https://github.com/azure-devops/spin-kub-demo ).你可以使用你自己的项目,但需要更新jenkins流水线中编译和部署的脚本。 68 | 69 | ## 故障排除 70 | 71 | 如果部署出现错误,或者部署成功后不能成功访问Jeknis UI,需要登陆到跳板机上(使用部署模板中提供的用户名密码),访问/var/lib/waagent/custom-script/download/0/目录,检查stdout和stderr两个文件的内容,获得所有安装过程信息。 72 | 73 | ## 参考项目 74 | 75 | ### [Azure-devops-utils](https://github.com/Azure/azure-devops-utils) (MIT License) 76 | 77 | This repository contains utility scripts to run/configure DevOp systems in Azure. 78 | -------------------------------------------------------------------------------- /cicd/armtemplate/jenkins_private_registry_k8s/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUsername": { 6 | "value": "azureuser" 7 | }, 8 | "adminPassword": { 9 | "value": "GEN-PASSWORD" 10 | }, 11 | "jenkinsDnsPrefix": { 12 | "value": "GEN-UNIQUE" 13 | }, 14 | "gitRepository": { 15 | "value": "https://github.com/azure-devops/spin-kub-demo.git" 16 | }, 17 | "privateRegistryUrl": { 18 | "value": "http://139.217.12.139" 19 | }, 20 | "privateRegistryUserName": { 21 | "value": "azureuser" 22 | }, 23 | "privateRegistryPassword": { 24 | "value": "Vl_10218" 25 | }, 26 | "kubernetesMasterFQDN": { 27 | "value":"" 28 | }, 29 | "kubernetesUserName": { 30 | "value":"" 31 | }, 32 | "kubernetesPrivateKey": { 33 | "value":"" 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /cicd/armtemplate/jenkins_private_registry_k8s/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "itemDisplayName": "Jenkins to Azure Container Registry", 3 | "icon": "ubuntu", 4 | "description": "This template allows you to deploy an instance of Jenkins on a DS1_v2 size Linux Ubuntu 14.04 LTS VM. It also includes an optional pipeline push images to private registry and deploy to a kubernetes cluster.", 5 | "summary": "This template allows you to deploy an instance of Jenkins on a DS1_v2 size Linux Ubuntu 14.04 LTS VM. It also includes an optional pipeline push images to private registry and deploy to a kubernetes cluster.", 6 | "githubUsername": "azure-devops", 7 | "dateUpdated": "2017-06-26" 8 | } -------------------------------------------------------------------------------- /cicd/script/README.md: -------------------------------------------------------------------------------- 1 | # Azure DevOps Utilities 2 | This repository contains utility scripts to run/configure DevOps systems in Azure. These scripts can be used individually, but are also leveraged in several 'Getting Started' solutions: 3 | * [Jenkins Quickstart Templates](https://azure.microsoft.com/resources/templates/?term=Jenkins) 4 | * [Spinnaker Quickstart Templates](https://azure.microsoft.com/resources/templates/?term=Spinnaker) 5 | 6 | ## Contents 7 | * Common 8 | * [create-service-principal.sh](bash/create-service-principal.sh): Creates Azure Service Principal credentials. 9 | * [deploy-dev-ops.sh](deploy-dev-ops/): Deploys a DevOps pipeline targeting either a Kubernetes cluster or VM Scale Sets. 10 | * Jenkins 11 | * [basic-docker-build.groovy](jenkins/basic-docker-build.groovy): Sample Jenkins pipeline that clones a git repository, builds the docker container defined in the Docker file and pushes that container to a private container registry. 12 | * [add-docker-build-job.sh](jenkins/add-docker-build-job.sh): Adds a Docker Build job in an existing Jenkins instance. 13 | * [add-aptly-build-job.sh](jenkins/add-aptly-build-job.sh): Adds a sample Build job in an existing Jenkins instance that pushes a debian package to an Aptly repository. 14 | * [init-aptly-repo.sh](jenkins/init-aptly-repo.sh): Initializes an Aptly repository on an existing Jenkins instance. 15 | * [unsecure-jenkins-instance.sh](jenkins/unsecure-jenkins-instance.sh): Disables the security of a Jenkins instance. 16 | * [Jenkins-Windows-Init-Script.ps1](powershell/Jenkins-Windows-Init-Script.ps1): Sample script on how to setup your Windows Azure Jenkins Agent to communicate through JNLP with the Jenkins master. 17 | * [Migrate-Image-From-Classic.ps1](powershell/Migrate-Image-From-Classic.ps1): Migrates an image from the classic image model to the new Azure Resource Manager model. 18 | * [install_jenkins.sh](jenkins/install_jenkins.sh): Bash script that installs Jenkins on a Linux VM and exposes it to the public through port 80 (login and cli are disabled). 19 | * [run-cli-command.sh](jenkins/run-cli-command.sh): Script that runs a Jenkins CLI command. 20 | * Spinnaker 21 | * [add_k8s_pipeline.sh](spinnaker/add_k8s_pipeline/): Adds a Kubernetes pipeline with three main stages: 22 | 1. Deploy to a development environment 23 | 1. Wait for manual judgement 24 | 1. Deploy to a production environment 25 | * [copy_kube_config.sh](spinnaker/copy_kube_config/): Programatically copies a kubeconfig file from an Azure Container Service Kubernetes cluster to a Spinnaker machine. 26 | * [install_halyard.sh](spinnaker/install_halyard/): Install Halyard and automatically configure Spinnaker to use Azure Storage (azs) as its persistent storage. 27 | 28 | 29 | _This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments._ -------------------------------------------------------------------------------- /cicd/script/bash/README.md: -------------------------------------------------------------------------------- 1 | ## Create Service Principal [Deprecated] 2 | 3 | It is now recommended to use [version 2.0](https://docs.microsoft.com/cli/azure/install-azure-cli) of the Azure CLI: 4 | ```bash 5 | az login 6 | az account set --subscription 7 | az ad sp create-for-rbac 8 | ``` 9 | By default, the last command creates a Service Principal with the 'Contributor' role scoped to the current subscription. Pass the '--help' parameter for more info if you want to change the defaults. 10 | 11 | See [here](https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli?toc=%2fazure%2fazure-resource-manager%2ftoc.json) for more information 12 | 13 | If you still want to use [version 1.0](https://docs.microsoft.com/azure/cli-install-nodejs) of the Azure CLI, then use this script. It prompts for user input to be able to authenticate on Azure and to pick the desired subscription (this step can be skipped by providing the subscription id as a script argument). 14 | 15 | ## Questions/Comments? azdevopspub@microsoft.com 16 | -------------------------------------------------------------------------------- /cicd/script/deploy-dev-ops/README.md: -------------------------------------------------------------------------------- 1 | # Deploy a Continuous Delivery pipeline [![Build Status](http://devops-ci.westcentralus.cloudapp.azure.com/job/qs/job/deploy-dev-ops/badge/icon)](http://devops-ci.westcentralus.cloudapp.azure.com/blue/organizations/jenkins/qs%2Fdeploy-dev-ops/activity) 2 | 3 | This script deploys a DevOps pipeline targeting either a Kubernetes cluster or VM Scale Sets. It deploys an instance of Jenkins and Spinnaker on an Ubuntu 14.04 VM in Azure. 4 | 5 | ## Arguments 6 | | Name | Description | 7 | | --- | ---| 8 | | --subscription_id
-s | Subscription id, optional if a default is already set in the Azure CLI | 9 | | --deploy_target
-dt | Deployment target for Spinnaker (either 'k8s' for a Kubernetes cluster or 'vmss' for VM Scale Sets), defaulted to 'k8s' | 10 | | --username
-u | Username for the DevOps VM, defaulted to 'azureuser' | 11 | | --dns_prefix
-dp | DNS prefix for the DevOps VM, defaulted to a generated string | 12 | | --resource_group
-rg | Resource group to deploy to, defaulted to a generated string | 13 | | --location
-l | Location to deploy to, e.g. 'westus', optional if a default is already set in the Azure CLI | 14 | | --app_id
-ai | Service Principal App Id (also called client id), defaulted to a generated Service Principal | 15 | | --app_key
-ak | Service Principal App Key (also called client secret), defaulted to a generated Service Principal | 16 | | --tenant_id
-ti | Tenant Id (only necessary if you want this script to log in to the cli with the Service Principal credentials) | 17 | | --password
-p | Password for the DevOps VM (only used for the 'vmss' scenario) | 18 | | --ssh_public_key
-spk | SSH Public Key for the DevOps VM (only used for the 'k8s' scenario), defaulted to '~/.ssh/id_rsa.pub' | 19 | | --git_repository
-gr | Git repository with a Dockerfile at the root (only used for the 'k8s' scenario), defaulted to 'https://github.com/azure-devops/spin-kub-demo' | 20 | | --quiet
-q | If this flag is passed, the script will not prompt for any values. An error will be thrown if a required parameter is not specified. | 21 | 22 | ## Example usage 23 | To run interactively: 24 | ```bash 25 | bash <(curl -sL https://aka.ms/DeployDevOps) 26 | ``` 27 | 28 | To run non-interactively: 29 | ```bash 30 | curl -sL https://aka.ms/DeployDevOps | bash -s -- 31 | ``` 32 | 33 | ## Questions/Comments? azdevopspub@microsoft.com -------------------------------------------------------------------------------- /cicd/script/jenkins/README.md: -------------------------------------------------------------------------------- 1 | ## Jenkins groovy script to build and push a Docker container 2 | > [basic-docker-build.groovy](basic-docker-build.groovy) 3 | 4 | Sample Jenkins pipeline that clones a git repository, builds the docker container defined in the Docker file and pushes that container to a private container registry. 5 | The Jenkins Job that uses this groovy script must have these parameters defined: 6 | 7 | | Jenkins job parameters | Description | 8 | |-------------------------|-------------------------------------------------------------------------------------------------------------| 9 | | git_repo | A public git repository that has a Dockerfile | 10 | | docker_repository | The container repository | 11 | | registry_url | The Docker private container registry url | 12 | | registry_credentials_id | The Jenkins credentials id that stores the user name and password for the Docker private container registry | 13 | 14 | ## Add a Docker Build job in an existing Jenkins instance 15 | > [add-docker-build-job.sh](add-docker-build-job.sh) 16 | 17 | Bash script that adds a Docker Build job in an existing Jenkins instance. The created job will use the [basic-docker-build.groovy](basic-docker-build.groovy) script. 18 | add-docker-build-deploy-k8s 19 | ## Add a docker build, push to private docker images and deploy to kubernetes cluster job in an existing Jenkins instance 20 | > [add-docker-build-deploy-k8s.sh](add-docker-build-deploy-k8s.sh) 21 | 22 | Bash script that adds a Docker build, push to private docker images and deploy to kubernetes cluster job in an existing Jenkins instance. The created job will use the [basic-docker-build-deploy-k8s.groovy](basic-docker-build-deploy-k8s.groovy) script. 23 | ## Disable security for a Jenkins instance 24 | > [unsecure-jenkins-instance.sh](unsecure-jenkins-instance.sh) 25 | 26 | Bash script that disables the security of a Jenkins instance. 27 | 28 | If you accidentally set up security realm / authorization in such a way that you may no longer able to reconfigure Jenkins you can use this script to disable security. 29 | 30 | ***Don't make your instance publicly available when running this script! Anyone can access your unsecure Jenkins instance!*** 31 | For more informations see the [Jenkins documentation](https://jenkins.io/doc/book/operating/security/#disabling-security) 32 | 33 | ## Install Jenkins 34 | > [install_jenkins.sh](install_jenkins.sh) 35 | Bash script that installs Jenkins on a Linux VM and exposes it to the public through port 80 (login and cli are disabled). 36 | 37 | ## Install Jenkins plugins 38 | > [run-cli-command.sh](run-cli-command.sh) 39 | Bash script that runs a Jenkins cli command. 40 | 41 | ## Questions/Comments? azdevopspub@microsoft.com -------------------------------------------------------------------------------- /cicd/script/jenkins/add-aptly-build-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function print_usage() { 4 | cat <&2 23 | print_usage 24 | exit -1 25 | fi 26 | } 27 | 28 | function run_util_script() { 29 | local script_path="$1" 30 | shift 31 | curl --silent "${artifacts_location}${script_path}${artifacts_location_sas_token}" | sudo bash -s -- "$@" 32 | local return_value=$? 33 | if [ $return_value -ne 0 ]; then 34 | >&2 echo "Failed while executing script '$script_path'." 35 | exit $return_value 36 | fi 37 | } 38 | 39 | #set defaults 40 | job_short_name="hello-karyon-rxnetty" 41 | job_display_name="Sample Aptly Job" 42 | job_description="A basic pipeline that builds a debian package and pushes it to an Aptly repository hosted on the Jenkins VM." 43 | repository_name="hello-karyon-rxnetty" 44 | artifacts_location="https://raw.githubusercontent.com/Azure/azure-devops-utils/master/" 45 | git_url="https://github.com/azure-devops/hello-karyon-rxnetty.git" 46 | 47 | while [[ $# > 0 ]] 48 | do 49 | key="$1" 50 | shift 51 | case $key in 52 | --git_url|-g) 53 | git_url="$1";; 54 | --repository_name|-rn) 55 | repository_name="$1";; 56 | --job_short_name|-jsn) 57 | job_short_name="$1";; 58 | --job_display_name|-jdn) 59 | job_display_name="$1";; 60 | --job_description|-jd) 61 | job_description="$1";; 62 | --artifacts_location|-al) 63 | artifacts_location="$1";; 64 | --sas_token|-st) 65 | artifacts_location_sas_token="$1";; 66 | --help|-help|-h) 67 | print_usage 68 | exit 13;; 69 | *) 70 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 71 | exit -1 72 | esac 73 | shift 74 | done 75 | 76 | throw_if_empty git_url $git_url 77 | throw_if_empty repository_name $repository_name 78 | 79 | #download dependencies 80 | job_xml=$(curl -s ${artifacts_location}/jenkins/basic-aptly-build-job.xml${artifacts_location_sas_token}) 81 | 82 | #prepare job.xml 83 | job_xml=${job_xml//'{insert-job-display-name}'/${job_display_name}} 84 | job_xml=${job_xml//'{insert-job-description}'/${job_description}} 85 | job_xml=${job_xml//'{insert-git-url}'/${git_url}} 86 | job_xml=${job_xml//'{insert-repository-name}'/${repository_name}} 87 | 88 | echo "${job_xml}" > job.xml 89 | 90 | echo "Installing git..." 91 | sudo DEBIAN_FRONTEND=noninteractive apt-get install git -y 92 | 93 | echo "Installing Java 8..." 94 | sudo DEBIAN_FRONTEND=noninteractive apt-get install -y openjdk-8-jdk 95 | 96 | gradle_version="3.5" 97 | echo "Installing Gradlew ${gradle_version}..." 98 | wget -nv https://services.gradle.org/distributions/gradle-${gradle_version}-bin.zip 99 | sudo unzip gradle-${gradle_version}-bin.zip -d /opt/gradle 100 | sudo ln -s /opt/gradle/gradle-${gradle_version}/bin/gradle /usr/bin/gradle 101 | 102 | run_util_script "jenkins/run-cli-command.sh" -c "install-plugin git -restart" 103 | 104 | echo "Waiting for Jenkins to be back online..." 105 | run_util_script "jenkins/run-cli-command.sh" -c "version" 106 | 107 | echo "Adding basic vmss job..." 108 | run_util_script "jenkins/run-cli-command.sh" -cif "job.xml" -c "create-job ${job_short_name}" 109 | 110 | #cleanup 111 | rm job.xml 112 | rm jenkins-cli.jar -------------------------------------------------------------------------------- /cicd/script/jenkins/basic-aptly-build-job.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {insert-job-description} 5 | {insert-job-display-name} 6 | false 7 | 8 | 9 | 28 | true 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /cicd/script/jenkins/basic-docker-build-deploy-k8s-job.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {insert-job-description} 5 | {insert-job-display-name} 6 | false 7 | 8 | 9 | 10 | 11 | git_repo 12 | Git repository from where we're going to checkout the code (master branch) and build a docker image. 13 | NB! The repository must contain a Dockerfile in the root 14 | {insert-git-url} 15 | 16 | 17 | docker_repository 18 | The docker repository 19 | {insert-container-repository} 20 | 21 | 22 | registry_url 23 | Container Registry URL 24 | {insert-registry} 25 | 26 | 27 | service_name 28 | the deployment service name in Kubernetes 29 | testapp 30 | 31 | 32 | service_port_number 33 | the expose port number for service 34 | 8000 35 | 36 | 37 | registry_credentials_id 38 | The credentials id that points to the Container Registry credentials 39 | {insert-docker-credentials} 40 | com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl 41 | true 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 53 | true 54 | 55 | 56 | -------------------------------------------------------------------------------- /cicd/script/jenkins/basic-docker-build-deploy-k8s.groovy: -------------------------------------------------------------------------------- 1 | node { 2 | def app = ''; 3 | def start_index = params.registry_url.indexOf("//") + 2; 4 | def registry_url = params.registry_url.substring(start_index); 5 | stage('Checkout git repo') { 6 | git branch: 'master', url: params.git_repo 7 | } 8 | stage('Build Docker image') { 9 | app = docker.build(params.docker_repository + ":${env.BUILD_NUMBER}", '.') 10 | } 11 | stage('Push Docker image to Private Registry') { 12 | docker.withRegistry(params.registry_url, params.registry_credentials_id ) { 13 | app.push("${env.BUILD_NUMBER}"); 14 | } 15 | } 16 | stage('Test And Validation') { 17 | app.inside { 18 | sh 'echo "Test passed"' 19 | } 20 | } 21 | stage('Deploy to K8S') { 22 | // Clean up old releases 23 | sh "kubectl delete pods,deployment -l run=${params.service_name} || true" 24 | def cmd = """kubectl run ${params.service_name} --image=${registry_url}/${app.imageName()} --replicas=2 --port=${params.service_port_number}""" 25 | // execute shell for the command above 26 | sh cmd 27 | sh "kubectl get svc ${params.service_name} || kubectl expose deployment ${params.service_name} --target-port=${params.service_port_number} --type=LoadBalancer" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cicd/script/jenkins/basic-docker-build-job.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {insert-job-description} 5 | {insert-job-display-name} 6 | false 7 | 8 | 9 | 10 | 11 | git_repo 12 | Git repository from where we're going to checkout the code (master branch) and build a docker image. 13 | NB! The repository must contain a Dockerfile in the root 14 | {insert-git-url} 15 | 16 | 17 | docker_repository 18 | The docker repository 19 | {insert-container-repository} 20 | 21 | 22 | registry_url 23 | Container Registry URL 24 | {insert-registry} 25 | 26 | 27 | registry_credentials_id 28 | The credentials id that points to the Container Registry credentials 29 | {insert-docker-credentials} 30 | com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl 31 | true 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 43 | true 44 | 45 | 46 | -------------------------------------------------------------------------------- /cicd/script/jenkins/basic-docker-build.groovy: -------------------------------------------------------------------------------- 1 | node { 2 | def built_img = '' 3 | stage('Checkout git repo') { 4 | git branch: 'master', url: params.git_repo 5 | } 6 | stage('Build Docker image') { 7 | built_img = docker.build(params.docker_repository + ":${env.BUILD_NUMBER}", '.') 8 | } 9 | stage('Push Docker image to Azure Container Registry') { 10 | docker.withRegistry(params.registry_url, params.registry_credentials_id ) { 11 | built_img.push("${env.BUILD_NUMBER}"); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /cicd/script/jenkins/basic-user-pwd-credentials.xml: -------------------------------------------------------------------------------- 1 | 2 | GLOBAL 3 | {insert-credentials-id} 4 | {insert-credentials-description} 5 | {insert-user-name} 6 | {insert-user-password} 7 | 8 | -------------------------------------------------------------------------------- /cicd/script/jenkins/init-aptly-repo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function print_usage() { 4 | cat <&2 19 | print_usage 20 | exit -1 21 | fi 22 | } 23 | 24 | # Set defaults 25 | repository_name="hello-karyon-rxnetty" 26 | 27 | while [[ $# > 0 ]] 28 | do 29 | key="$1" 30 | shift 31 | case $key in 32 | --vm_fqdn|-vf) 33 | vm_fqdn="$1";; 34 | --repository_name|-rn) 35 | repository_name="$1";; 36 | --help|-help|-h) 37 | print_usage 38 | exit 13;; 39 | *) 40 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 41 | exit -1 42 | esac 43 | shift 44 | done 45 | 46 | throw_if_empty vm_fqdn $vm_fqdn 47 | throw_if_empty repository_name $repository_name 48 | 49 | # Install aptly 50 | echo "deb http://repo.aptly.info/ squeeze main" | sudo tee -a "/etc/apt/sources.list" > /dev/null 51 | sudo apt-key adv --keyserver keys.gnupg.net --recv-keys 9E3E53F19C7DE460 52 | sudo DEBIAN_FRONTEND=noninteractive apt-get update --yes 53 | sudo DEBIAN_FRONTEND=noninteractive apt-get install aptly --yes 54 | 55 | # Create default aptly repository 56 | sudo su -c "aptly repo create $repository_name" jenkins 57 | sudo su -c "aptly publish repo -architectures=\"amd64\" -component=main -distribution=trusty -skip-signing=true $repository_name" jenkins 58 | 59 | # Serve aptly on port 9999 60 | aptly_nginx_config=$(cat < /dev/null 74 | 75 | #restart nginx 76 | sudo service nginx restart -------------------------------------------------------------------------------- /cicd/script/jenkins/install_jenkins_plugin.sh: -------------------------------------------------------------------------------- 1 | #reference https://gist.github.com/micw/e80d739c6099078ce0f3 2 | #!/usr/bin/env bash 3 | 4 | set -e 5 | set -o pipefail 6 | 7 | plugin_repo_url="https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins" 8 | plugin_dir="/var/lib/jenkins/plugins" 9 | include_optionals=false 10 | 11 | showUsage() { 12 | echo "\ 13 | $0 [OPTIONS] plugin@version ... 14 | 15 | OPTIONS: 16 | -d,--dir DIR Install dir. Default is $plugin_dir 17 | -a,--all Install also optional dependencies 18 | -u,--url URL Change to plugin repo URL. Default is $plugin_repo_url 19 | -h,--help Print this help" 20 | } 21 | 22 | while [[ $# -gt 0 ]] 23 | do 24 | key="$1" 25 | 26 | case $key in 27 | -u|--url) 28 | plugin_repo_url="$2" 29 | shift 30 | ;; 31 | -d|--dir) 32 | plugin_dir="$2" 33 | shift 34 | ;; 35 | -a|--all) 36 | include_optionals=true 37 | ;; 38 | -h|--help) 39 | showUsage 40 | exit 41 | ;; 42 | -*|--*) 43 | echo "Unknown Option" 44 | exit 1 45 | ;; 46 | *) 47 | break 48 | ;; 49 | esac 50 | shift 51 | done 52 | 53 | download_plugin() { 54 | url="${plugin_repo_url}/${1}/${2}/${1}.hpi" 55 | echo "Downloading: $1@$2" 56 | curl -L --silent --output "${plugin_dir}/${1}.hpi" "$url" 57 | } 58 | 59 | get_dependencies() { 60 | hpi_file=$1 61 | manifest="$(unzip -p "${hpi_file}" META-INF/MANIFEST.MF | tr -d '\r' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n //g' )" 62 | if line=$( echo "$manifest" | grep -e "^Plugin-Dependencies" ); then 63 | deps=$( echo "$line" | awk '{ print $2 }' | tr ',' '\n' ) 64 | if ! $include_optionals; then 65 | deps=$( echo "$deps" | grep -v "resolution:=optional" ) 66 | fi 67 | sed 's/;.*$//' <<< "$deps" 68 | else 69 | echo "" 70 | fi 71 | } 72 | 73 | vercomp () { 74 | if [[ "$1" == "$2" ]] 75 | then 76 | echo 0 77 | return 78 | fi 79 | local IFS=. 80 | local i ver1=($1) ver2=($2) 81 | # fill empty fields in ver1 with zeros 82 | for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) 83 | do 84 | ver1[i]=0 85 | done 86 | for ((i=0; i<${#ver1[@]}; i++)) 87 | do 88 | if [[ -z ${ver2[i]} ]] 89 | then 90 | # fill empty fields in ver2 with zeros 91 | ver2[i]=0 92 | fi 93 | if ((10#${ver1[i]} > 10#${ver2[i]})) 94 | then 95 | echo 1 96 | return 97 | fi 98 | if ((10#${ver1[i]} < 10#${ver2[i]})) 99 | then 100 | echo -1 101 | return 102 | fi 103 | done 104 | echo 0 105 | } 106 | 107 | installed_plugins=() 108 | 109 | install_plugin() { 110 | plugin_id="$1" 111 | plugin_version="$2" 112 | 113 | if grep -q "$plugin_id" <<< "$installed_plugins[*]"; then 114 | return 0 115 | fi 116 | 117 | dest="${plugin_dir}/${1}.hpi" 118 | 119 | if [ -f "$dest" ]; then 120 | installed_version=$(unzip -p "${dest}" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version" | awk '{ print $2 }' | tr -d '\n' ) 121 | 122 | if [ "$(vercomp "$installed_version" "$plugin_version")" -lt "0" ]; then 123 | echo "Updating $plugin_id from $installed_version to $plugin_version" 124 | download_plugin "$plugin_id" "$plugin_version" "$plugin_dir" 125 | fi 126 | else 127 | download_plugin "$plugin_id" "$plugin_version" "$plugin_dir" 128 | fi 129 | 130 | installed_plugins+=("$plugin_id") 131 | 132 | deps="$(get_dependencies "$dest")" 133 | echo "$deps" | tr ' ' '\n' | 134 | while IFS=: read -r plugin version; do 135 | install_plugin "$plugin" "$version" 136 | done 137 | } 138 | 139 | for plugin in "$@"; do 140 | IFS="@" read -r plugin version <<< "$plugin" 141 | #escape comments 142 | if [[ "$plugin" =~ ^# ]]; then 143 | continue 144 | fi 145 | 146 | #install the plugin 147 | install_plugin "$plugin" "$version" 148 | done 149 | 150 | echo "Done" 151 | 152 | -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/container-service-for-azure-china/122b8049a59ee620f61a1abc63ad566a607ac769/cicd/script/jenkins/jenkins-on-azure/copy.png -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/headshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/container-service-for-azure-china/122b8049a59ee620f61a1abc63ad566a607ac769/cicd/script/jenkins/jenkins-on-azure/headshot.png -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Jenkins On Azure 8 | 9 | 10 | 11 | 21 | 29 | 30 |
31 |
32 | 33 |
34 |
35 |

Jenkins On Azure

36 |
37 |

This Jenkins instance does not support https, so logging in through a public IP address has been disabled (it would 38 | expose your password and other information to eavesdropping). To securely login, you need to connect to the Jenkins 39 | instance using SSH port forwarding.

40 |

ssh -L 127.0.0.1:8080:localhost:8080 username@{domain-name}

41 |

If you don't want to publicly expose this Jenkins instance, you need to remove the nginx reverse-proxy.

42 |

sudo apt-get purge nginx nginx-common

43 |
44 |
45 | 46 |
47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/install-web-page.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function print_usage() { 3 | cat <&2 19 | print_usage 20 | exit -1 21 | fi 22 | } 23 | 24 | #defaults 25 | artifacts_location="https://raw.githubusercontent.com/Azure/azure-devops-utils/master/" 26 | 27 | while [[ $# > 0 ]] 28 | do 29 | key="$1" 30 | shift 31 | case $key in 32 | --location|-l) 33 | location="$1" 34 | shift 35 | ;; 36 | --url|-u) 37 | url="$1" 38 | shift 39 | ;; 40 | --artifacts_location|-al) 41 | artifacts_location="$1" 42 | shift 43 | ;; 44 | --sas_token|-st) 45 | artifacts_location_sas_token="$1" 46 | shift 47 | ;; 48 | --help|-help|-h) 49 | print_usage 50 | exit 13 51 | ;; 52 | *) 53 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 54 | exit -1 55 | esac 56 | done 57 | 58 | throw_if_empty --location $location 59 | throw_if_empty --url $url 60 | 61 | #install jenkins-on-azure web page 62 | sudo mkdir ${location} 63 | artifacts=("headshot.png" "title.png" "azure.svg" "copy.png" "site.css" "site.js" "index.html") 64 | for i in "${artifacts[@]}"; do 65 | if [[ $i =~ .*html.* ]] 66 | then 67 | raw_resource=$(curl --silent "${artifacts_location}/jenkins/jenkins-on-azure/$i${artifacts_location_sas_token}") 68 | final_resource=${raw_resource//'{domain-name}'/${url}} 69 | echo "${final_resource}" | sudo tee ${location}/$i > /dev/null 70 | else 71 | curl --silent "${artifacts_location}/jenkins/jenkins-on-azure/$i${artifacts_location_sas_token}" -o ${location}/$i 72 | fi 73 | done 74 | -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | position: relative; 3 | min-height: 100%; 4 | } 5 | body { 6 | margin: 0; 7 | padding: 0 0 40px 0; 8 | } 9 | img { 10 | vertical-align: middle; 11 | border: 0; 12 | } 13 | #page-head { 14 | box-sizing: border-box; 15 | } 16 | #header { 17 | background-color: #000000; 18 | height: 40px; 19 | } 20 | #header .logo { 21 | margin-left: 16px; 22 | } 23 | #jenkins-home-link { 24 | position: absolute; 25 | height: 40px; 26 | } 27 | #jenkins-head-icon { 28 | position: absolute; 29 | bottom: 0px; 30 | } 31 | #jenkins-name-icon { 32 | position: absolute; 33 | bottom: 3px; 34 | left: 32px; 35 | } 36 | #breadcrumbBar, #footer-container, .top-sticker-inner { 37 | background-color: #f6faf2; 38 | } 39 | .top-sticker, #top-sticker { 40 | width: 100%; 41 | z-index: 999; 42 | position: absolute; top: 40px; left: 0px; 43 | } 44 | #breadcrumbs { 45 | list-style-type: none; 46 | padding: 0 0 0 8px; 47 | margin: 0; 48 | height: 2em; 49 | } 50 | #breadcrumbs li { 51 | font-family: Helvetica, Arial, sans-serif; 52 | font-size: 14px; 53 | float: left; 54 | line-height: 2em; 55 | height: 2em; 56 | color: #555753; 57 | } 58 | #breadcrumbs li a:link, li a:visited { 59 | text-decoration: none; 60 | color: #555753; 61 | } 62 | #breadcrumbs a.inside { 63 | padding-right: 16px; 64 | } 65 | #breadcrumbs li a { 66 | display: block; 67 | padding-left: 0.75em; 68 | line-height: 2em; 69 | } 70 | 71 | 72 | 73 | #feature { 74 | margin: 0 auto 0 auto; 75 | overflow: hidden; 76 | position: absolute; 77 | width: 100%; 78 | } 79 | #image { 80 | position: fixed; 81 | top: 0; 82 | left: 0; 83 | z-index: -1; 84 | width: 100%; 85 | background-color: #0078d7; 86 | height: 100vh; 87 | overflow: hidden; 88 | } 89 | #image img { 90 | opacity: .23; 91 | height: 100%; 92 | /*max-height: 90vh;*/ 93 | display: block; 94 | margin: auto; 95 | } 96 | #content { 97 | display: block; 98 | margin: auto; 99 | font-family: "Segoe UI"; 100 | font-weight: normal; 101 | font-size: 4vmin; 102 | color: #fff; 103 | text-align: center; 104 | max-width: 90vw; 105 | } 106 | #title h1 { 107 | font-family: "Segoe UI Light"; 108 | color: #fff; 109 | font-weight: normal; 110 | font-size: 5.5vmin; 111 | margin: 4vmin; 112 | } 113 | #content_body { 114 | text-align: left; 115 | font-size: 3vmin; 116 | } 117 | #content_body p { 118 | padding-bottom: 0.3vmin; 119 | margin: 0.5vmin; 120 | } 121 | .snippet { 122 | margin-left: 6vmin; 123 | padding: 0.3vmin; 124 | background-color: #f6f8fa; 125 | font: 2vmin "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 126 | color: #000; 127 | width: 100%; 128 | } 129 | #clipboard { 130 | height: 2vmin; 131 | margin-left: 1vmin; 132 | margin-right: 0.5vmin; 133 | cursor: pointer; 134 | } 135 | footer { 136 | padding: 11px 0; 137 | background-color: #f6faf2; 138 | border-top: 1px solid #d3d7cf; 139 | border-bottom: 1px solid #f6faf2; 140 | width: 100%; 141 | position: absolute; 142 | bottom: 0; 143 | left: 0; 144 | clear: both; 145 | font-size: 12px; 146 | text-align: right; 147 | } -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/site.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('.snippet').mouseenter(function() { 3 | $('#clipboard').remove(); 4 | span = $(this); 5 | temp = $(this).text(); 6 | snippetLen = $(this).text().length; 7 | $(this).find('img').show(); 8 | $(this).append( 9 | 'Copy to Clipboard'); 10 | 11 | $(this).parent().mouseleave(function() { 12 | $('#clipboard').remove(); 13 | }); 14 | 15 | $('#clipboard').click(function() { 16 | var doc = document, element = span[0], range, selection; 17 | if (doc.body.createTextRange) { 18 | range = document.body.createTextRange(); 19 | range.moveToElementText(element); 20 | range.select(); 21 | } else if (window.getSelection) { 22 | selection = window.getSelection(); 23 | range = document.createRange(); 24 | range.setStart(element, 0) 25 | range.setEndBefore($(this)[0]); 26 | selection.removeAllRanges(); 27 | selection.addRange(range); 28 | } 29 | document.execCommand('copy'); 30 | }); 31 | }); 32 | }); -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-on-azure/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/container-service-for-azure-china/122b8049a59ee620f61a1abc63ad566a607ac769/cicd/script/jenkins/jenkins-on-azure/title.png -------------------------------------------------------------------------------- /cicd/script/jenkins/jenkins-verified-ver: -------------------------------------------------------------------------------- 1 | 2.60.3 -------------------------------------------------------------------------------- /cicd/script/jenkins/run-cli-command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function print_usage() { 4 | cat <&2 echo "Parameter '$name' cannot be empty." 21 | print_usage 22 | exit -1 23 | fi 24 | } 25 | 26 | #set defaults 27 | jenkins_url="http://localhost:8080/" 28 | jenkins_username="admin" 29 | 30 | while [[ $# > 0 ]] 31 | do 32 | key="$1" 33 | shift 34 | case $key in 35 | --command|-c) 36 | command="$1" 37 | shift 38 | ;; 39 | --command_input_file|-cif) 40 | command_input_file="$1" 41 | shift 42 | ;; 43 | --jenkins_url|-j) 44 | jenkins_url="$1" 45 | shift 46 | ;; 47 | --jenkins_username|-ju) 48 | jenkins_username="$1" 49 | shift 50 | ;; 51 | --jenkins_password|-jp) 52 | jenkins_password="$1" 53 | shift 54 | ;; 55 | --help|-help|-h) 56 | print_usage 57 | exit 13 58 | ;; 59 | *) 60 | >&2 echo "ERROR: Unknown argument '$key' to script '$0'" 61 | exit -1 62 | esac 63 | done 64 | 65 | throw_if_empty jenkins_username $jenkins_username 66 | if [ "$jenkins_username" != "admin" ]; then 67 | throw_if_empty jenkins_password $jenkins_password 68 | fi 69 | 70 | function retry_until_successful { 71 | counter=0 72 | "${@}" 73 | while [ $? -ne 0 ]; do 74 | if [[ "$counter" -gt 20 ]]; then 75 | exit 1 76 | else 77 | let counter++ 78 | fi 79 | sleep 15 80 | "${@}" 81 | done; 82 | } 83 | 84 | if [ ! -e jenkins-cli.jar ]; then 85 | >&2 echo "Downloading Jenkins CLI..." 86 | retry_until_successful wget ${jenkins_url}jnlpJars/jenkins-cli.jar -O jenkins-cli.jar 87 | fi 88 | 89 | if [ -z "$jenkins_password" ]; then 90 | # NOTE: Intentionally setting this after the first retry_until_successful to ensure the initialAdminPassword file exists 91 | jenkins_password=`sudo cat /var/lib/jenkins/secrets/initialAdminPassword` 92 | fi 93 | 94 | >&2 echo "Running \"${command}\"..." 95 | if [ -z "$command_input_file" ]; then 96 | retry_until_successful java -jar jenkins-cli.jar -s "${jenkins_url}" -auth "${jenkins_username}":"${jenkins_password}" $command 97 | else 98 | retry_until_successful cat "$command_input_file" | java -jar jenkins-cli.jar -s "${jenkins_url}" -auth "${jenkins_username}":"${jenkins_password}" $command 99 | fi -------------------------------------------------------------------------------- /cicd/script/jenkins/unsecure-jenkins-instance.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo echo "1" > /var/lib/jenkins/jenkins.install.InstallUtil.lastExecVersion 4 | 5 | unsecure_config_xml=$(sed -zr \ 6 | -e "s|.*|false|"\ 7 | -e "s|||"\ 8 | -e "s|||"\ 9 | /var/lib/jenkins/config.xml) 10 | 11 | echo "${unsecure_config_xml}" > /var/lib/jenkins/config.xml 12 | 13 | sudo service jenkins restart 14 | -------------------------------------------------------------------------------- /cicd/script/powershell/Jenkins-Windows-Init-Script-SSH.ps1: -------------------------------------------------------------------------------- 1 | # Download and Install Java 2 | Set-ExecutionPolicy Unrestricted 3 | #Default workspace location 4 | Set-Location C:\ 5 | $source = "http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-windows-x64.exe" 6 | $destination = "C:\jdk-8u131-windows-x64.exe" 7 | $client = new-object System.Net.WebClient 8 | $cookie = "oraclelicense=accept-securebackup-cookie" 9 | $client.Headers.Add([System.Net.HttpRequestHeader]::Cookie, $cookie) 10 | $client.downloadFile($source, $destination) 11 | $proc = Start-Process -FilePath $destination -ArgumentList "/s" -Wait -PassThru 12 | $proc.WaitForExit() 13 | [System.Environment]::SetEnvironmentVariable("JAVA_HOME", "c:\Program Files\Java\jdk1.8.0_131", "Machine") 14 | [System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";c:\Program Files\Java\jdk1.8.0_131\bin", "Machine") 15 | $Env:Path += ";c:\Program Files\Java\jdk1.8.0_131\bin" 16 | #Disable git credential manager, get more details in https://support.cloudbees.com/hc/en-us/articles/221046888-Build-Hang-or-Fail-with-Git-for-Windows 17 | git config --system --unset credential.helper 18 | 19 | 20 | # Install Maven 21 | $source = "http://mirror.reverse.net/pub/apache/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin.zip" 22 | $destination = "C:\maven.zip" 23 | $webClient = New-Object System.Net.WebClient 24 | $webClient.DownloadFile($source, $destination) 25 | $shell_app=new-object -com shell.application 26 | $zip_file = $shell_app.namespace($destination) 27 | mkdir 'C:\Program Files\apache-maven-3.5.0' 28 | $destination = $shell_app.namespace('C:\Program Files') 29 | $destination.Copyhere($zip_file.items(), 0x14) 30 | [System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";C:\Program Files\apache-maven-3.5.0\bin", "Machine") 31 | $Env:Path += ";C:\Program Files\apache-maven-3.5.0\bin" 32 | 33 | 34 | # Install Git 35 | $source = "https://github.com/git-for-windows/git/releases/latest" 36 | $latestRelease = Invoke-WebRequest -UseBasicParsing $source -Headers @{"Accept"="application/json"} 37 | $json = $latestRelease.Content | ConvertFrom-Json 38 | $latestVersion = $json.tag_name 39 | $versionHead = $latestVersion.Substring(1, $latestVersion.IndexOf("windows")-2) 40 | $source = "https://github.com/git-for-windows/git/releases/download/v${versionHead}.windows.1/Git-${versionHead}-64-bit.exe" 41 | $destination = "C:\Git-${versionHead}-64-bit.exe" 42 | $webClient = New-Object System.Net.WebClient 43 | $webClient.DownloadFile($source, $destination) 44 | $proc = Start-Process -FilePath $destination -ArgumentList "/VERYSILENT" -Wait -PassThru 45 | $proc.WaitForExit() 46 | $Env:Path += ";C:\Program Files\Git\cmd" -------------------------------------------------------------------------------- /cicd/script/powershell/Jenkins-Windows-Init-Script-no-secrets.ps1: -------------------------------------------------------------------------------- 1 | # Download and Install Java 2 | Set-ExecutionPolicy Unrestricted 3 | #Default workspace location 4 | Set-Location C:\ 5 | $source = "http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-windows-x64.exe" 6 | $destination = "C:\jdk-8u131-windows-x64.exe" 7 | $client = new-object System.Net.WebClient 8 | $cookie = "oraclelicense=accept-securebackup-cookie" 9 | $client.Headers.Add([System.Net.HttpRequestHeader]::Cookie, $cookie) 10 | $client.downloadFile($source, $destination) 11 | $proc = Start-Process -FilePath $destination -ArgumentList "/s" -Wait -PassThru 12 | $proc.WaitForExit() 13 | $javaHome = "c:\Program Files\Java\jdk1.8.0_131" 14 | [System.Environment]::SetEnvironmentVariable("JAVA_HOME", ${javaHome}, "Machine") 15 | [System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";${javaHome}\bin", "Machine") 16 | $Env:Path += ";${javaHome}\bin" 17 | 18 | 19 | # Install Maven 20 | $source = "http://mirror.reverse.net/pub/apache/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin.zip" 21 | $destination = "C:\maven.zip" 22 | $webClient = New-Object System.Net.WebClient 23 | $webClient.DownloadFile($source, $destination) 24 | $shell_app=new-object -com shell.application 25 | $zip_file = $shell_app.namespace($destination) 26 | mkdir 'C:\Program Files\apache-maven-3.5.0' 27 | $destination = $shell_app.namespace('C:\Program Files') 28 | $destination.Copyhere($zip_file.items(), 0x14) 29 | [System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";C:\Program Files\apache-maven-3.5.0\bin", "Machine") 30 | $Env:Path += ";C:\Program Files\apache-maven-3.5.0\bin" 31 | 32 | 33 | # Install Git 34 | $source = "https://github.com/git-for-windows/git/releases/latest" 35 | $latestRelease = Invoke-WebRequest -UseBasicParsing $source -Headers @{"Accept"="application/json"} 36 | $json = $latestRelease.Content | ConvertFrom-Json 37 | $latestVersion = $json.tag_name 38 | $versionHead = $latestVersion.Substring(1, $latestVersion.IndexOf("windows")-2) 39 | $source = "https://github.com/git-for-windows/git/releases/download/v${versionHead}.windows.1/Git-${versionHead}-64-bit.exe" 40 | $destination = "C:\Git-${versionHead}-64-bit.exe" 41 | $webClient = New-Object System.Net.WebClient 42 | $webClient.DownloadFile($source, $destination) 43 | $proc = Start-Process -FilePath $destination -ArgumentList "/VERYSILENT" -Wait -PassThru 44 | $proc.WaitForExit() 45 | $Env:Path += ";C:\Program Files\Git\cmd" 46 | #Disable git credential manager, get more details in https://support.cloudbees.com/hc/en-us/articles/221046888-Build-Hang-or-Fail-with-Git-for-Windows 47 | git config --system --unset credential.helper 48 | 49 | 50 | # Install Slaves jar and connect via JNLP 51 | # Jenkins plugin will dynamically pass the server name and vm name. 52 | # If your jenkins server is configured for security , make sure to edit command for how slave executes 53 | $jenkinsserverurl = $args[0] 54 | $vmname = $args[1] 55 | $secret = $args[2] 56 | 57 | # Downloading jenkins slaves jar 58 | Write-Output "Downloading jenkins slave jar " 59 | mkdir c:\jenkins 60 | $slaveSource = $jenkinsserverurl + "jnlpJars/slave.jar" 61 | $destSource = "c:\jenkins\slave.jar" 62 | $wc = New-Object System.Net.WebClient 63 | $wc.DownloadFile($slaveSource, $destSource) 64 | 65 | # Download the service wrapper 66 | $wrapperExec = "c:\jenkins\jenkins-slave.exe" 67 | $configFile = "c:\jenkins\jenkins-slave.xml" 68 | $wc.DownloadFile("https://github.com/kohsuke/winsw/releases/download/winsw-v2.1.2/WinSW.NET2.exe", $wrapperExec) 69 | $wc.DownloadFile("https://raw.githubusercontent.com/azure-devops/ci/master/resources/jenkins-slave.exe.config", "c:\jenkins\jenkins-slave.exe.config") 70 | $wc.DownloadFile("https://raw.githubusercontent.com/azure-devops/ci/master/resources/jenkins-slave.xml", $configFile) 71 | 72 | # Prepare config 73 | Write-Output "Executing agent process " 74 | $configExec = "${javaHome}\bin\java.exe" 75 | $configArgs = "-jnlpUrl `"${jenkinsserverurl}/computer/${vmname}/slave-agent.jnlp`" -noReconnect" 76 | if ($secret) { 77 | $configArgs += " -secret `"$secret`"" 78 | } 79 | (Get-Content $configFile).replace('@JAVA@', $configExec) | Set-Content $configFile 80 | (Get-Content $configFile).replace('@ARGS@', $configArgs) | Set-Content $configFile 81 | (Get-Content $configFile).replace('@SLAVE_JAR_URL', $slaveSource) | Set-Content $configFile 82 | 83 | # Install the service 84 | & $wrapperExec install 85 | & $wrapperExec start -------------------------------------------------------------------------------- /cicd/script/powershell/Jenkins-Windows-Init-Script.ps1: -------------------------------------------------------------------------------- 1 | Set-ExecutionPolicy Unrestricted 2 | # Jenkins plugin will dynamically pass the server name and vm name. 3 | # If your jenkins server is configured for security , make sure to edit command for how slave executes 4 | # You may need to pass credentails or secret in the command , Refer to help by running "java -jar slave.jar --help" 5 | $jenkinsserverurl = $args[0] 6 | $vmname = $args[1] 7 | 8 | 9 | # Download the file to a specific location 10 | Write-Output "Downloading zulu SDK " 11 | $source = "http://azure.azulsystems.com/zulu/zulu1.7.0_51-7.3.0.4-win64.zip?jenkins" 12 | mkdir d:\azurecsdir 13 | $destination = "d:\azurecsdir\zuluJDK.zip" 14 | $wc = New-Object System.Net.WebClient 15 | $wc.DownloadFile($source, $destination) 16 | 17 | Write-Output "Unzipping JDK " 18 | # Unzip the file to specified location 19 | $shell_app=new-object -com shell.application 20 | $zip_file = $shell_app.namespace($destination) 21 | mkdir d:\java 22 | $destination = $shell_app.namespace("d:\java") 23 | $destination.Copyhere($zip_file.items()) 24 | Write-Output "Successfully downloaded and extracted JDK " 25 | 26 | # Downloading jenkins slaves jar 27 | Write-Output "Downloading jenkins slave jar " 28 | $slaveSource = $jenkinsserverurl + "jnlpJars/slave.jar" 29 | $destSource = "d:\java\slave.jar" 30 | $wc = New-Object System.Net.WebClient 31 | $wc.DownloadFile($slaveSource, $destSource) 32 | 33 | # execute slave 34 | Write-Output "Executing slave process " 35 | $java="d:\java\zulu1.7.0_51-7.3.0.4-win64\bin\java.exe" 36 | $jar="-jar" 37 | $jnlpUrl="-jnlpUrl" 38 | $serverURL=$jenkinsserverurl+"computer/" + $vmname + "/slave-agent.jnlp" 39 | $jnlpCredentialsFlag="-jnlpCredentials" 40 | # syntax for credentials username:apitoken or username:password 41 | # you can get api token by clicking on your username --> configure --> show api token 42 | $credentials="username:apitoken" 43 | & $java $jar $destSource $jnlpCredentialsFlag $credentials $jnlpUrl $serverURL 44 | 45 | -------------------------------------------------------------------------------- /cicd/script/powershell/README.md: -------------------------------------------------------------------------------- 1 | ## Jenkins Azure Agent initialization script 2 | > [Jenkins-Windows-Init-Script.ps1](Jenkins-Windows-Init-Script.ps1) 3 | 4 | Sample script on how to setup your Windows Azure Jenkins Agent to communicate through JNLP with the Jenkins master. 5 | Before deploying using this initialization script remember to update this line with your credentials (you can get api token by clicking on your username --> configure --> show api token): 6 | ```powershell 7 | $credentials="username:apitoken" 8 | ``` 9 | More information about the Azure VM Agents plugin can be found [here](https://wiki.jenkins-ci.org/display/JENKINS/Azure+VM+Agents+Plugin). 10 | 11 | ## Azure Classic VM Image migration 12 | > [Migrate-Image-From-Classic.ps1](Migrate-Image-From-Classic.ps1) 13 | 14 | Migrates an image from the classic image model to the new Azure Resource Manager model. 15 | 16 | | Argument | Description | 17 | |----------------------|---------------------------------------------------------------------------------------------------| 18 | | ImageName | Original image name | 19 | | TargetStorageAccount | Target account to copy to | 20 | | TargetResourceGroup | Resource group of the target storage account | 21 | | TargetContainer | Target container to put the VHD | 22 | | TargetVirtualPath | Virtual path to put the blob in. If not specified, defaults to the virtual path of the source URI | 23 | | TargetBlobName | Blob name to copy to. If not specified, defaults to the blob name of the source URI | 24 | 25 | ## Questions/Comments? azdevopspub@microsoft.com -------------------------------------------------------------------------------- /cicd/script/quickstart_template/101-spinnaker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function print_usage() { 4 | cat <&2 21 | print_usage 22 | exit -1 23 | fi 24 | } 25 | 26 | function run_util_script() { 27 | local script_path="$1" 28 | shift 29 | curl --silent "${artifacts_location}${script_path}${artifacts_location_sas_token}" | sudo bash -s -- "$@" 30 | local return_value=$? 31 | if [ $return_value -ne 0 ]; then 32 | >&2 echo "Failed while executing script '$script_path'." 33 | exit $return_value 34 | fi 35 | } 36 | 37 | while [[ $# > 0 ]] 38 | do 39 | key="$1" 40 | shift 41 | case $key in 42 | --storage_account_name|-san) 43 | storage_account_name="$1";; 44 | --storage_account_key|-sak) 45 | storage_account_key="$1";; 46 | --username|-u) 47 | username="$1";; 48 | --artifacts_location|-al) 49 | artifacts_location="$1";; 50 | --sas_token|-st) 51 | artifacts_location_sas_token="$1";; 52 | --help|-help|-h) 53 | print_usage 54 | exit 13;; 55 | *) 56 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 57 | exit -1 58 | esac 59 | shift 60 | done 61 | 62 | throw_if_empty storage_account_name $storage_account_name 63 | throw_if_empty storage_account_key $storage_account_key 64 | throw_if_empty username $username 65 | 66 | run_util_script "spinnaker/install_halyard/install_halyard.sh" -san "$storage_account_name" -sak "$storage_account_key" -u "$username" 67 | 68 | sudo hal deploy apply 69 | 70 | # Wait for Spinnaker services to be up before returning 71 | timeout=180 72 | echo "while !(nc -z localhost 8084) || !(nc -z localhost 9000); do sleep 1; done" | timeout $timeout bash 73 | return_value=$? 74 | if [ $return_value -ne 0 ]; then 75 | >&2 echo "Failed to connect to Spinnaker within '$timeout' seconds." 76 | exit $return_value 77 | fi -------------------------------------------------------------------------------- /cicd/script/quickstart_template/201-jenkins-acr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | function print_usage() { 3 | cat <&2 25 | print_usage 26 | exit -1 27 | fi 28 | } 29 | 30 | function run_util_script() { 31 | local script_path="$1" 32 | shift 33 | curl --silent "${artifacts_location}${script_path}${artifacts_location_sas_token}" | sudo bash -s -- "$@" 34 | local return_value=$? 35 | if [ $return_value -ne 0 ]; then 36 | >&2 echo "Failed while executing script '$script_path'." 37 | exit $return_value 38 | fi 39 | } 40 | 41 | #defaults 42 | artifacts_location="https://raw.githubusercontent.com/Azure/azure-devops-utils/master/" 43 | while [[ $# > 0 ]] 44 | do 45 | key="$1" 46 | shift 47 | case $key in 48 | --vm_user_name|-u) 49 | vm_user_name="$1" 50 | shift 51 | ;; 52 | --git_url|-g) 53 | git_url="$1" 54 | shift 55 | ;; 56 | --registry|-r) 57 | registry="$1" 58 | shift 59 | ;; 60 | --registry_user_name|-ru) 61 | registry_user_name="$1" 62 | shift 63 | ;; 64 | --registry_password|-rp) 65 | registry_password="$1" 66 | shift 67 | ;; 68 | --repository|-rr) 69 | repository="$1" 70 | shift 71 | ;; 72 | --jenkins_fqdn|-jf) 73 | jenkins_fqdn="$1" 74 | shift 75 | ;; 76 | --artifacts_location|-al) 77 | artifacts_location="$1" 78 | shift 79 | ;; 80 | --sas_token|-st) 81 | artifacts_location_sas_token="$1" 82 | shift 83 | ;; 84 | --help|-help|-h) 85 | print_usage 86 | exit 13 87 | ;; 88 | *) 89 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 90 | exit -1 91 | esac 92 | done 93 | 94 | throw_if_empty --vm_user_name $vm_user_name 95 | throw_if_empty --git_url $git_url 96 | throw_if_empty --registry $registry 97 | throw_if_empty --registry_user_name $registry_user_name 98 | throw_if_empty --registry_password $registry_password 99 | throw_if_empty --jenkins_fqdn $jenkins_fqdn 100 | 101 | if [ -z "$repository" ]; then 102 | repository="${vm_user_name}/myfirstapp" 103 | fi 104 | 105 | #install jenkins 106 | run_util_script "jenkins/install_jenkins.sh" -jf "${jenkins_fqdn}" -al "${artifacts_location}" -st "${artifacts_location_sas_token}" 107 | 108 | #install git 109 | sudo apt-get install git --yes 110 | 111 | #install docker if not already installed 112 | if !(command -v docker >/dev/null); then 113 | sudo curl -sSL https://get.docker.com/ | sh 114 | fi 115 | 116 | #make sure jenkins has access to docker cli 117 | sudo gpasswd -a jenkins docker 118 | skill -KILL -u jenkins 119 | sudo service jenkins restart 120 | 121 | echo "Including the pipeline" 122 | run_util_script "jenkins/add-docker-build-job.sh" -j "http://localhost:8080/" -ju "admin" -g "${git_url}" -r "${registry}" -ru "${registry_user_name}" -rp "${registry_password}" -rr "$repository" -sps "* * * * *" -al "$artifacts_location" -st "$artifacts_location_sas_token" 123 | -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/VM-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": {}, 5 | "parameters": { 6 | "adminPassword": { 7 | "type": "securestring" 8 | }, 9 | "adminSSHPublicKey": { 10 | "type": "securestring" 11 | }, 12 | "adminUserName": { 13 | "type": "string" 14 | }, 15 | "networkInterfaceId": { 16 | "type": "string" 17 | }, 18 | "osDiskVHDUri": { 19 | "type": "string" 20 | }, 21 | "ubuntuSku": { 22 | "type": "string" 23 | }, 24 | "vmLocation": { 25 | "type": "string" 26 | }, 27 | "vmName": { 28 | "type": "string" 29 | }, 30 | "vmSize": { 31 | "type": "string" 32 | } 33 | }, 34 | "resources": [ 35 | { 36 | "apiVersion": "2016-03-30", 37 | "dependsOn": [], 38 | "location": "[parameters('vmLocation')]", 39 | "name": "[parameters('vmName')]", 40 | "properties": { 41 | "hardwareProfile": { 42 | "vmSize": "[parameters('vmSize')]" 43 | }, 44 | "networkProfile": { 45 | "networkInterfaces": [ 46 | { 47 | "id": "[parameters('networkInterfaceId')]" 48 | } 49 | ] 50 | }, 51 | "osProfile": { 52 | "adminPassword": "[parameters('adminPassword')]", 53 | "adminUsername": "[parameters('adminUserName')]", 54 | "computerName": "[parameters('vmName')]" 55 | }, 56 | "storageProfile": { 57 | "imageReference": { 58 | "offer": "UbuntuServer", 59 | "publisher": "Canonical", 60 | "sku": "[parameters('ubuntuSku')]", 61 | "version": "latest" 62 | }, 63 | "osDisk": { 64 | "caching": "ReadWrite", 65 | "createOption": "FromImage", 66 | "name": "osDisk", 67 | "vhd": { 68 | "uri": "[parameters('osDiskVHDUri')]" 69 | } 70 | } 71 | } 72 | }, 73 | "resources": [], 74 | "tags": { 75 | "displayName": "[parameters('vmName')]" 76 | }, 77 | "type": "Microsoft.Compute/virtualMachines" 78 | } 79 | ], 80 | "variables": {} 81 | } -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/VM-sshPublicKey.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": {}, 5 | "parameters": { 6 | "adminPassword": { 7 | "type": "securestring" 8 | }, 9 | "adminSSHPublicKey": { 10 | "type": "securestring" 11 | }, 12 | "adminUserName": { 13 | "type": "string" 14 | }, 15 | "networkInterfaceId": { 16 | "type": "string" 17 | }, 18 | "osDiskVHDUri": { 19 | "type": "string" 20 | }, 21 | "ubuntuSku": { 22 | "type": "string" 23 | }, 24 | "vmLocation": { 25 | "type": "string" 26 | }, 27 | "vmName": { 28 | "type": "string" 29 | }, 30 | "vmSize": { 31 | "type": "string" 32 | } 33 | }, 34 | "resources": [ 35 | { 36 | "apiVersion": "2016-03-30", 37 | "dependsOn": [], 38 | "location": "[parameters('vmLocation')]", 39 | "name": "[parameters('vmName')]", 40 | "properties": { 41 | "hardwareProfile": { 42 | "vmSize": "[parameters('vmSize')]" 43 | }, 44 | "networkProfile": { 45 | "networkInterfaces": [ 46 | { 47 | "id": "[parameters('networkInterfaceId')]" 48 | } 49 | ] 50 | }, 51 | "osProfile": { 52 | "adminUsername": "[parameters('adminUserName')]", 53 | "computerName": "[parameters('vmName')]", 54 | "linuxConfiguration": { 55 | "disablePasswordAuthentication": "true", 56 | "ssh": { 57 | "publicKeys": [ 58 | { 59 | "keyData": "[parameters('adminSSHPublicKey')]", 60 | "path": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]" 61 | } 62 | ] 63 | } 64 | } 65 | }, 66 | "storageProfile": { 67 | "imageReference": { 68 | "offer": "UbuntuServer", 69 | "publisher": "Canonical", 70 | "sku": "[parameters('ubuntuSku')]", 71 | "version": "latest" 72 | }, 73 | "osDisk": { 74 | "caching": "ReadWrite", 75 | "createOption": "FromImage", 76 | "name": "osDisk", 77 | "vhd": { 78 | "uri": "[parameters('osDiskVHDUri')]" 79 | } 80 | } 81 | } 82 | }, 83 | "resources": [], 84 | "tags": { 85 | "displayName": "[parameters('vmName')]" 86 | }, 87 | "type": "Microsoft.Compute/virtualMachines" 88 | } 89 | ], 90 | "variables": {} 91 | } -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/publicIP-existing.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": { 5 | "fqdn": { 6 | "type": "string", 7 | "value": "[reference(resourceId(parameters('publicIPResourceGroup'),'Microsoft.Network/publicIPAddresses',parameters('publicIPName')),'2016-03-30').dnsSettings.fqdn]" 8 | } 9 | }, 10 | "parameters": { 11 | "dnsPrefix": { 12 | "type": "string" 13 | }, 14 | "publicIPLocation": { 15 | "type": "string" 16 | }, 17 | "publicIPName": { 18 | "type": "string" 19 | }, 20 | "publicIPResourceGroup": { 21 | "type": "string" 22 | } 23 | }, 24 | "resources": [], 25 | "variables": {} 26 | } -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/publicIP-new.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": { 5 | "fqdn": { 6 | "type": "string", 7 | "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses',parameters('publicIPName')),'2016-03-30').dnsSettings.fqdn]" 8 | } 9 | }, 10 | "parameters": { 11 | "dnsPrefix": { 12 | "type": "string" 13 | }, 14 | "publicIPLocation": { 15 | "type": "string" 16 | }, 17 | "publicIPName": { 18 | "type": "string" 19 | }, 20 | "publicIPResourceGroup": { 21 | "type": "string" 22 | } 23 | }, 24 | "resources": [ 25 | { 26 | "apiVersion": "2016-03-30", 27 | "location": "[parameters('publicIPLocation')]", 28 | "name": "[parameters('publicIPName')]", 29 | "properties": { 30 | "dnsSettings": { 31 | "domainNameLabel": "[parameters('dnsPrefix')]" 32 | }, 33 | "publicIPAllocationMethod": "Dynamic" 34 | }, 35 | "type": "Microsoft.Network/publicIPAddresses" 36 | } 37 | ], 38 | "variables": {} 39 | } -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/spinnaker-VM-Init.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": {}, 5 | "parameters": { 6 | "location": { 7 | "type": "string" 8 | }, 9 | "vmName": { 10 | "type": "string" 11 | }, 12 | "_extensionScript": { 13 | "type": "string" 14 | }, 15 | "storageAccountName": { 16 | "type": "string" 17 | }, 18 | "storageAccountResourceGroup": { 19 | "type": "string" 20 | }, 21 | "adminUsername": { 22 | "type": "string" 23 | }, 24 | "_artifactsLocation": { 25 | "type": "string" 26 | }, 27 | "_artifactsLocationSasToken": { 28 | "type": "string" 29 | } 30 | }, 31 | "resources": [ 32 | { 33 | "apiVersion": "2015-06-15", 34 | "dependsOn": [], 35 | "location": "[parameters('location')]", 36 | "name": "[concat(parameters('vmName'), '/Init')]", 37 | "properties": { 38 | "autoUpgradeMinorVersion": true, 39 | "protectedSettings": { 40 | "commandToExecute": "[concat('./', parameters('_extensionScript'), ' -san \"', parameters('storageAccountName'), '\" -sak \"', listKeys(resourceId(parameters('storageAccountResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2016-01-01').keys[0].value, '\" -u \"', parameters('adminUsername'), '\" -al \"', parameters('_artifactsLocation'), '\" -st \"', parameters('_artifactsLocationSasToken'), '\"')]" 41 | }, 42 | "publisher": "Microsoft.Azure.Extensions", 43 | "settings": { 44 | "fileUris": [ 45 | "[concat(parameters('_artifactsLocation'), 'quickstart_template/', parameters('_extensionScript'), parameters('_artifactsLocationSasToken'))]" 46 | ] 47 | }, 48 | "type": "CustomScript", 49 | "typeHandlerVersion": "2.0" 50 | }, 51 | "type": "Microsoft.Compute/virtualMachines/extensions" 52 | } 53 | ], 54 | "variables": {} 55 | } -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/storageAccount-existing.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": { 5 | "primaryEndpointBlob": { 6 | "type": "string", 7 | "value": "[reference(resourceId(parameters('storageAccountResourceGroup'),'Microsoft.Storage/storageAccounts',parameters('storageAccountName')),'2016-01-01').primaryEndpoints.blob]" 8 | } 9 | }, 10 | "parameters": { 11 | "storageAccountLocation": { 12 | "type": "string" 13 | }, 14 | "storageAccountName": { 15 | "type": "string" 16 | }, 17 | "storageAccountType": { 18 | "type": "string" 19 | }, 20 | "storageAccountResourceGroup": { 21 | "type": "string" 22 | } 23 | }, 24 | "resources": [], 25 | "variables": {} 26 | } -------------------------------------------------------------------------------- /cicd/script/solution_template/nested/storageAccount-new.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "outputs": { 5 | "primaryEndpointBlob": { 6 | "type": "string", 7 | "value": "[reference(resourceId('Microsoft.Storage/storageAccounts',parameters('storageAccountName')),'2016-01-01').primaryEndpoints.blob]" 8 | } 9 | }, 10 | "parameters": { 11 | "storageAccountLocation": { 12 | "type": "string" 13 | }, 14 | "storageAccountName": { 15 | "type": "string" 16 | }, 17 | "storageAccountType": { 18 | "type": "string" 19 | }, 20 | "storageAccountResourceGroup": { 21 | "type": "string" 22 | } 23 | }, 24 | "resources": [ 25 | { 26 | "apiVersion": "2016-01-01", 27 | "dependsOn": [], 28 | "kind": "Storage", 29 | "location": "[parameters('storageAccountLocation')]", 30 | "name": "[parameters('storageAccountName')]", 31 | "sku": { 32 | "name": "[parameters('storageAccountType')]" 33 | }, 34 | "type": "Microsoft.Storage/storageAccounts" 35 | } 36 | ], 37 | "variables": {} 38 | } -------------------------------------------------------------------------------- /cicd/script/spinnaker/add_k8s_pipeline/README.md: -------------------------------------------------------------------------------- 1 | # Add Kubernetes Pipeline 2 | 3 | Adds a Kubernetes pipeline with three main stages: 4 | 5 | 1. Deploy to a development environment 6 | 1. Wait for manual judgement 7 | 1. Deploy to a production environment 8 | 9 | The pipeline will be triggered by any new tag pushed to the target repository and will also clean up previous deployments. 10 | 11 | ## Prerequisites 12 | This must be executed on a machine with a running Spinnaker instance. 13 | 14 | ## Arguments 15 | | Name | Description | 16 | |---|---| 17 | | --account_name
-an | The Spinnaker account name for your registry | 18 | | --registry
-rg | The Azure Container Registry url, for example 'sample-microsoft.azurecr.io'. | 19 | | --repository
-rp | The repository, for example 'Fabrikam/app1'. Any new tag pushed to this repository will trigger the pipeline. | 20 | | --port
-p | (optional) The port used when creating load balancers for the pipeline. The container deployed by your pipeline is expected to be listening on this port. The default is '8000'. | 21 | | --user_name
-un | (optional) The user name for creating the pipeline. The default is '[anonymous]'. | 22 | | --user_email
-ue | (optional) The user email for creating the pipeline. The default is 'anonymous@Fabrikam.com'. | 23 | | --artifacts_location
-al | (optional) The url for referencing other scripts/artifacts. The default is this github repository. | 24 | | --sas_token
-st | (optional) A sas token needed if the artifacts location is private. | 25 | 26 | ## Example usage 27 | ```bash 28 | ./add_k8s_pipeline.sh --acount-name "azure-container-registry" --registry "sample-microsoft.azurecr.io" --repository "Fabrikam/application1" 29 | ``` 30 | 31 | ## Questions/Comments? azdevopspub@microsoft.com -------------------------------------------------------------------------------- /cicd/script/spinnaker/add_k8s_pipeline/application.json: -------------------------------------------------------------------------------- 1 | { 2 | "job": [ 3 | { 4 | "type": "createApplication", 5 | "account": "my-kubernetes-account", 6 | "application": { 7 | "accounts": "my-kubernetes-account", 8 | "cloudProviders": "kubernetes", 9 | "instancePort": 80, 10 | "name": "REPLACE_APP_NAME", 11 | "email": "REPLACE_USER_EMAIL" 12 | }, 13 | "user": "REPLACE_USER_NAME" 14 | } 15 | ], 16 | "application": "REPLACE_APP_NAME", 17 | "description": "Create Application: REPLACE_APP_NAME" 18 | } -------------------------------------------------------------------------------- /cicd/script/spinnaker/add_k8s_pipeline/load_balancer.json: -------------------------------------------------------------------------------- 1 | { 2 | "job": [ 3 | { 4 | "provider": "kubernetes", 5 | "stack": "REPLACE_STACK", 6 | "detail": "", 7 | "serviceType": "REPLACE_SERVICE_TYPE", 8 | "account": "my-kubernetes-account", 9 | "namespace": "default", 10 | "ports": [ 11 | { 12 | "protocol": "TCP", 13 | "port": 80, 14 | "name": "http", 15 | "targetPort": REPLACE_PORT 16 | } 17 | ], 18 | "externalIps": [], 19 | "sessionAffinity": "None", 20 | "clusterIp": "", 21 | "loadBalancerIp": "", 22 | "name": "REPLACE_APP_NAME-REPLACE_STACK", 23 | "serviceAnnotations": {}, 24 | "cloudProvider": "kubernetes", 25 | "availabilityZones": { 26 | "default": [ 27 | "default" 28 | ] 29 | }, 30 | "type": "upsertLoadBalancer", 31 | "user": "REPLACE_USER_NAME" 32 | } 33 | ], 34 | "application": "REPLACE_APP_NAME", 35 | "description": "Create Load Balancer: REPLACE_APP_NAME-REPLACE_STACK" 36 | } -------------------------------------------------------------------------------- /cicd/script/spinnaker/copy_kube_config/README.md: -------------------------------------------------------------------------------- 1 | # Copy kubeconfig file 2 | 3 | Programatically copies a kubeconfig file from an Azure Container Service Kubernetes cluster to a Spinnaker machine. 4 | 5 | >**Note:** This script is only intended for use when copying the kubeconfig programatically with a Service Principal (aka when you do not have access to the ssh private key). If you want to do this manually, you can simply use 'scp'. 6 | 7 | ## Prerequisites 8 | This must be executed on a machine with an existing Spinnaker instance. The 'az' cli must be installed and you must already be logged in with the correct subscription set. 9 | 10 | ## Arguments 11 | | Name | Description | 12 | |---|---| 13 | | --user_name
-un | The admin user name for the Kubernetes cluster. | 14 | | --resource_group
-rg | The resource group containing the Kubernetes cluster. | 15 | | --master_fqdn
-mf | The FQDN for the master VMs in the Kubernetes cluster. | 16 | 17 | ## Example usage 18 | ```bash 19 | ./copy_kube_config.sh --user_name "adminuser" --resource_group "resourcegroup" --master_fqdn "samplemgmt.westus.cloudapp.azure.com" 20 | ``` 21 | 22 | ## Questions/Comments? azdevopspub@microsoft.com -------------------------------------------------------------------------------- /cicd/script/spinnaker/copy_kube_config/copy_kube_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function print_usage() { 4 | cat <&2 22 | print_usage 23 | exit -1 24 | fi 25 | } 26 | 27 | while [[ $# > 0 ]] 28 | do 29 | key="$1" 30 | shift 31 | case $key in 32 | --user_name|-un) 33 | admin_user_name="$1" 34 | shift 35 | ;; 36 | --resource_group|-rg) 37 | resource_group="$1" 38 | shift 39 | ;; 40 | --master_fqdn|-mf) 41 | master_fqdn="$1" 42 | shift 43 | ;; 44 | --help|-help|-h) 45 | print_usage 46 | exit 13 47 | ;; 48 | *) 49 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 50 | exit -1 51 | esac 52 | done 53 | 54 | throw_if_empty --user-name $admin_user_name 55 | throw_if_empty --resource_group $resource_group 56 | throw_if_empty --master_fqdn $master_fqdn 57 | 58 | config_path="/home/$admin_user_name/.kube/config" 59 | 60 | # Setup temporary credentials to access kubernetes master vms 61 | temp_user_name=$(uuidgen | sed 's/-//g') 62 | temp_key_path=$(mktemp -d)/temp_key 63 | ssh-keygen -t rsa -N "" -f $temp_key_path -V "+1d" 64 | temp_pub_key=$(cat ${temp_key_path}.pub) 65 | 66 | master_vm_ids=$(az vm list -g "$resource_group" --query "[].id" -o tsv | grep "k8s-master-") 67 | >&2 echo "Master VM ids: $master_vm_ids" 68 | 69 | # Enable temporary credentials on every kubernetes master vm (since we don't know which vm will be used when we scp) 70 | az vm user update -u "$temp_user_name" --ssh-key-value "$temp_pub_key" --ids "$master_vm_ids" 71 | 72 | # Copy kube config over from master kubernetes cluster and mark readable 73 | sudo mkdir -p $(dirname "$config_path") 74 | sudo sh -c "ssh -o StrictHostKeyChecking=no -i \"$temp_key_path\" $temp_user_name@$master_fqdn sudo cat \"$config_path\" > \"$config_path\"" 75 | 76 | # Remove temporary credentials on every kubernetes master vm 77 | az vm user delete -u "$temp_user_name" --ids "$master_vm_ids" 78 | 79 | # Delete temp key on spinnaker vm 80 | rm $temp_key_path 81 | rm ${temp_key_path}.pub 82 | 83 | if [ ! -s "$config_path" ]; then 84 | >&2 echo "Failed to copy kubeconfig for kubernetes cluster." 85 | exit -1 86 | fi 87 | 88 | sudo chmod +r "$config_path" -------------------------------------------------------------------------------- /cicd/script/spinnaker/install_halyard/README.md: -------------------------------------------------------------------------------- 1 | # Install Spinnaker 2 | 3 | Install Halyard and automatically configure Spinnaker to use Azure Storage (azs) as its persistent storage. 4 | 5 | ## Prerequisites 6 | This must be executed on a linux VM. You must run 'hal deploy apply' to finish deployment of Spinnaker. 7 | 8 | ## Arguments 9 | | Name | Description | 10 | |---|---| 11 | | --storage_account_name
-san | The storage account name used for Spinnaker's persistent storage service (front50). | 12 | | --storage_account_key
-sak | The storage account key used for Spinnaker's persistent storage service (front50). | 13 | | --username
-u | User for which to install Halyard. | 14 | 15 | ## Example usage 16 | ```bash 17 | ./install_spinnaker.sh --storage_account_name "sample" --storage_account_key "password" 18 | ``` 19 | 20 | ## Questions/Comments? azdevopspub@microsoft.com -------------------------------------------------------------------------------- /cicd/script/spinnaker/install_halyard/install_halyard.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function print_usage() { 4 | cat <&2 19 | print_usage 20 | exit -1 21 | fi 22 | } 23 | 24 | while [[ $# > 0 ]] 25 | do 26 | key="$1" 27 | shift 28 | case $key in 29 | --storage_account_name|-san) 30 | storage_account_name="$1";; 31 | --storage_account_key|-sak) 32 | storage_account_key="$1";; 33 | --username|-u) 34 | username="$1";; 35 | --help|-help|-h) 36 | print_usage 37 | exit 13;; 38 | *) 39 | echo "ERROR: Unknown argument '$key' to script '$0'" 1>&2 40 | exit -1 41 | esac 42 | shift 43 | done 44 | 45 | throw_if_empty storage_account_name $storage_account_name 46 | throw_if_empty storage_account_key $storage_account_key 47 | throw_if_empty username $username 48 | 49 | # Install Halyard 50 | curl --silent "https://raw.githubusercontent.com/spinnaker/halyard/master/install/stable/InstallHalyard.sh" | sudo bash -s -- --user "$username" -y 51 | 52 | # Set Halyard to use the latest released/validated version of Spinnaker 53 | hal config version edit --version $(hal version latest -q) 54 | 55 | # Configure Spinnaker persistent store 56 | hal config storage azs edit --storage-account-name "$storage_account_name" --storage-account-key "$storage_account_key" 57 | hal config storage edit --type azs -------------------------------------------------------------------------------- /doc/imgs/cicd_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/container-service-for-azure-china/122b8049a59ee620f61a1abc63ad566a607ac769/doc/imgs/cicd_architecture.png -------------------------------------------------------------------------------- /doc/imgs/monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/container-service-for-azure-china/122b8049a59ee620f61a1abc63ad566a607ac769/doc/imgs/monitor.png -------------------------------------------------------------------------------- /monitoring/k8s/controller/manual_config.sh: -------------------------------------------------------------------------------- 1 | # manually config controller machine 2 | 3 | # instructions 4 | # 1. [required] set K8S_MASTER_NODE_HOSTNAME with kubernetes cluster master node hostname 5 | # 2. [required] set K8S_MASTER_NODE_USERNAME with kubernetes cluster master node username 6 | # 3. [required] set K8S_MASTER_NODE_IDENTITY_FILE_PATH with kubernetes cluster master node identity file path 7 | # 4. [required] set K8S_UI_ADMIN_USERNAME with admin username to access kubernetes ui 8 | # 5. [required] set K8S_UI_ADMIN_PASSWORD with admin password to access kubernetes ui 9 | # 6. [optional] set MONITOR_CLUSTER_NS, ENABLE_ELK_STACK, ENABLE_HIG_STACK on demand 10 | # 7. save changes and execute this script. 11 | 12 | # constants 13 | CONFIG_SCRIPT_PATH="./config.sh" 14 | K8S_MASTER_NODE_HOSTNAME=".chinaeast.cloudapp.azure.cn" 15 | K8S_MASTER_NODE_USERNAME="" 16 | K8S_MASTER_NODE_IDENTITY_FILE_PATH="" 17 | K8S_UI_ADMIN_USERNAME="" 18 | K8S_UI_ADMIN_PASSWORD="" 19 | AZURE_CLOUD_ENV="AzureChinaCloud" 20 | MONITOR_CLUSTER_NS="monitor-cluster-ns" 21 | ENABLE_ELK_STACK="enabled" 22 | ENABLE_HIG_STACK="enabled" 23 | 24 | K8S_MASTER_NODE_IDENTITY_FILE_BASE64="$(base64 $K8S_MASTER_NODE_IDENTITY_FILE_PATH -w 0)" 25 | 26 | bash "$CONFIG_SCRIPT_PATH" \ 27 | --azure-cloud-env "$AZURE_CLOUD_ENV" \ 28 | --k8s-master-node-hostname "$K8S_MASTER_NODE_HOSTNAME" \ 29 | --k8s-master-node-username "$K8S_MASTER_NODE_USERNAME" \ 30 | --k8s-master-node-id-file-base64 "$K8S_MASTER_NODE_IDENTITY_FILE_BASE64" \ 31 | --k8s-ui-admin-username "$K8S_UI_ADMIN_USERNAME" \ 32 | --k8s-ui-admin-password "$K8S_UI_ADMIN_PASSWORD" \ 33 | --monitor-cluster-ns "$MONITOR_CLUSTER_NS" \ 34 | --enable-elk-stack "$ENABLE_ELK_STACK" \ 35 | --enable-hig-stack "$ENABLE_HIG_STACK" -------------------------------------------------------------------------------- /monitoring/k8s/controller/nginx-config/nginx-site.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | 5 | server_name _; 6 | 7 | location / { 8 | proxy_pass http://localhost:8080; 9 | auth_basic "Restrict Access"; 10 | auth_basic_user_file /etc/nginx/.htpasswd; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /monitoring/k8s/deployment/AzureChinaCloud/controller_parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmDnsName": { 6 | "value": "" 7 | }, 8 | "vmSize": { 9 | "value": "Standard_A1" 10 | }, 11 | "vmAdminUsername": { 12 | "value": "azureuser" 13 | }, 14 | "vmAdminPassword": { 15 | "value": "" 16 | }, 17 | "k8sMasterNodeHostname": { 18 | "value": "" 19 | }, 20 | "k8sMasterNodeUsername": { 21 | "value": "" 22 | }, 23 | "k8sMasterNodeIdentityFileBase64": { 24 | "value": "" 25 | }, 26 | "monitorClusterNamespace": { 27 | "value": "monitor-cluster-ns" 28 | }, 29 | "azureCloudEnvironment": { 30 | "value": "AzureChinaCloud" 31 | }, 32 | "enableElkStack": { 33 | "value": "enabled" 34 | }, 35 | "enableHigStack": { 36 | "value": "enabled" 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /monitoring/k8s/deployment/AzureCloud/controller_parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "vmDnsName": { 6 | "value": "" 7 | }, 8 | "vmSize": { 9 | "value": "Standard_A1" 10 | }, 11 | "vmAdminUsername": { 12 | "value": "azureuser" 13 | }, 14 | "vmAdminPassword": { 15 | "value": "" 16 | }, 17 | "k8sMasterNodeHostname": { 18 | "value": "" 19 | }, 20 | "k8sMasterNodeUsername": { 21 | "value": "" 22 | }, 23 | "k8sMasterNodeIdentityFileBase64": { 24 | "value": "" 25 | }, 26 | "monitorClusterNamespace": { 27 | "value": "monitor-cluster-ns" 28 | }, 29 | "azureCloudEnvironment": { 30 | "value": "AzureCloud" 31 | }, 32 | "enableElkStack": { 33 | "value": "enabled" 34 | }, 35 | "enableHigStack": { 36 | "value": "enabled" 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/configs/elk_azure_china_cloud.yaml: -------------------------------------------------------------------------------- 1 | # full global config file could be found in helm-charts/elk/values.yaml 2 | global: 3 | busybox: 4 | image: 5 | repository: crproxy.trafficmanager.net:5000/library/busybox 6 | 7 | # full elastic search config file could be found in helm-charts/elk/charts/elastic_search_chart/values.yaml 8 | elasticsearch: 9 | image: 10 | repository: crproxy.trafficmanager.net:5000/ccgmsref/elasticsearch 11 | client: 12 | replicas: 2 13 | master: 14 | replicas: 3 15 | data: 16 | replicas: 2 17 | 18 | # full logstash config file could be found in helm-charts/elk/charts/logstash_chart/values.yaml 19 | logstash: 20 | image: 21 | repository: crproxy.trafficmanager.net:5000/ccgmsref/logstash 22 | replicaCount: 1 23 | 24 | # full kibana config file could be found in helm-charts/elk/charts/kibana_chart/values.yaml 25 | kibana: 26 | image: 27 | repository: crproxy.trafficmanager.net:5000/ccgmsref/kibana 28 | replicaCount: 1 29 | 30 | # full filebeat config file could be found in helm-charts/elk/charts/filebeat_chart/values.yaml 31 | filebeat: 32 | image: 33 | repository: crproxy.trafficmanager.net:5000/ccgmsref/filebeat -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/configs/heapster.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repository: crproxy.trafficmanager.net:6000/google_containers/heapster 3 | tag: v1.3.0 4 | 5 | command: 6 | - "/heapster" 7 | - "--source=kubernetes:https://kubernetes.default" 8 | - "--sink=influxdb:http://influxdb-influxdb.{MONITOR_CLUSTER_NS}:8086" 9 | 10 | resizer: 11 | image: 12 | repository: crproxy.trafficmanager.net:6000/google_containers/addon-resizer 13 | tag: 1.7 14 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/configs/heartbeat-config/heartbeat.yml: -------------------------------------------------------------------------------- 1 | heartbeat.monitors: 2 | - type: http 3 | 4 | schedule: '@every 10s' 5 | 6 | #urls: ["http://mooncaketest.default:80"] 7 | urls: [] 8 | 9 | ipv4: true 10 | ipv6: true 11 | mode: any 12 | 13 | output.elasticsearch: 14 | hosts: ["elasticsearch.{MONITOR_CLUSTER_NS}:9200"] 15 | 16 | template.enabled: true 17 | template.name: "heartbeat" 18 | template.path: "heartbeat.template.json" 19 | template.overwrite: false 20 | 21 | dashboards.enabled: true 22 | dashboards.beat: heartbeat -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/configs/heartbeat.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repository: crproxy.trafficmanager.net:5000/ccgmsref/heartbeat 3 | tag: 5.5.1 4 | 5 | 6 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/configs/influxdb.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repo: "crproxy.trafficmanager.net:5000/library/influxdb" 3 | tag: "1.2-alpine" 4 | 5 | service: 6 | type: LoadBalancer 7 | 8 | persistence: 9 | enabled: true 10 | 11 | config: 12 | admin: 13 | enabled: true -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: helm chart for ELK 3 | name: elk-chart 4 | version: 0.0.1 5 | engine: gotpl 6 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: helm chart for elasticSearch 3 | name: elasticsearch 4 | version: 0.0.1 5 | engine: gotpl 6 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_client_deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }}-client 5 | labels: 6 | component: {{ template "fullname" . }} 7 | role: client 8 | spec: 9 | replicas: {{ .Values.client.replicas }} 10 | template: 11 | metadata: 12 | labels: 13 | component: {{ template "fullname" . }} 14 | role: client 15 | spec: 16 | securityContext: 17 | runAsUser: 1000 18 | fsGroup: 1000 19 | # Elasticsearch uses a hybrid mmapfs / niofs directory by default to 20 | # store its indices. The default operating system limits on mmap counts 21 | # is likely to be too low, which may result in out of memory exceptions, 22 | # so we use vm.max_map_count=262144 to increase that value. 23 | initContainers: 24 | - name: init-sysctl 25 | image: "{{ .Values.global.busybox.image.repository }}" 26 | imagePullPolicy: IfNotPresent 27 | command: ['sh', '-c', 'sysctl -w vm.max_map_count=262144'] 28 | securityContext: 29 | runAsUser: 0 30 | privileged: true 31 | containers: 32 | - name: es-client 33 | securityContext: 34 | privileged: false 35 | capabilities: 36 | add: 37 | - IPC_LOCK 38 | - SYS_RESOURCE 39 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 40 | imagePullPolicy: {{ .Values.image.pullPolicy }} 41 | env: 42 | - name: NAMESPACE 43 | value: "{{ .Release.Namespace }}" 44 | - name: CHART_INFO 45 | value: "{{ .Chart.Name}} - {{ .Chart.Version }} - {{ .Release.Name }}" 46 | - name: NODE_NAME 47 | valueFrom: 48 | fieldRef: 49 | fieldPath: metadata.name 50 | - name: DISCOVERY_SERVICE 51 | value: {{ template "fullname" . }}-discovery 52 | {{- range $key, $value := .Values.global.env }} 53 | - name: {{ $key | upper | replace "-" "_" }} 54 | value: {{ $value | quote }} 55 | {{- end }} 56 | {{- range $key, $value := .Values.common.env }} 57 | - name: {{ $key | upper | replace "-" "_" }} 58 | value: {{ $value | quote }} 59 | {{- end }} 60 | {{- range $key, $value := .Values.client.env }} 61 | - name: {{ $key | upper | replace "-" "_" }} 62 | value: {{ $value | quote }} 63 | {{- end }} 64 | ports: 65 | - containerPort: 9200 66 | name: http 67 | protocol: TCP 68 | - containerPort: 9300 69 | name: transport 70 | protocol: TCP 71 | volumeMounts: 72 | - name: esdata 73 | mountPath: /usr/share/elasticsearch/esdata/ 74 | - name: config 75 | mountPath: /usr/share/elasticsearch/config/elasticsearch.yml 76 | subPath: elasticsearch.yml 77 | volumes: 78 | - name: "esdata" 79 | emptyDir: 80 | medium: "" 81 | - name: "config" 82 | configMap: 83 | name: {{ .Values.configmap.name }} 84 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Values.configmap.name }} 5 | data: 6 | elasticsearch.yml: | 7 | {{ toYaml .Values.configmap.data | indent 4 }} 8 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_data_service.yaml: -------------------------------------------------------------------------------- 1 | # Headless Service 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{template "fullname" .}}-data 6 | labels: 7 | component: {{template "fullname" .}} 8 | role: data 9 | spec: 10 | ports: 11 | - port: 9300 12 | name: transport 13 | clusterIP: None 14 | selector: 15 | component: {{template "fullname" .}} 16 | role: data -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_data_statefullset.yaml: -------------------------------------------------------------------------------- 1 | # StatefulSet 2 | apiVersion: apps/v1beta1 3 | kind: StatefulSet 4 | metadata: 5 | name: {{ template "fullname" . }}-data 6 | labels: 7 | component: {{ template "fullname" . }} 8 | role: data 9 | spec: 10 | serviceName: {{ template "fullname" . }}-data 11 | replicas: {{ .Values.data.replicas }} 12 | template: 13 | metadata: 14 | labels: 15 | component: {{ template "fullname" . }} 16 | role: data 17 | spec: 18 | securityContext: 19 | runAsUser: 1000 20 | fsGroup: 1000 21 | # Elasticsearch uses a hybrid mmapfs / niofs directory by default to 22 | # store its indices. The default operating system limits on mmap counts 23 | # is likely to be too low, which may result in out of memory exceptions, 24 | # so we use vm.max_map_count=262144 to increase that value. 25 | initContainers: 26 | - name: init-sysctl 27 | image: "{{ .Values.global.busybox.image.repository }}" 28 | imagePullPolicy: IfNotPresent 29 | command: ['sh', '-c', 'sysctl -w vm.max_map_count=262144'] 30 | securityContext: 31 | runAsUser: 0 32 | privileged: true 33 | containers: 34 | - name: {{ template "fullname" . }}-data 35 | securityContext: 36 | privileged: false 37 | capabilities: 38 | add: 39 | - IPC_LOCK 40 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 41 | imagePullPolicy: {{ .Values.image.pullPolicy }} 42 | env: 43 | - name: NAMESPACE 44 | value: "{{ .Release.Namespace }}" 45 | - name: CHART_INFO 46 | value: "{{ .Chart.Name}} - {{ .Chart.Version }} - {{ .Release.Name }}" 47 | - name: NODE_NAME 48 | valueFrom: 49 | fieldRef: 50 | fieldPath: metadata.name 51 | - name: DISCOVERY_SERVICE 52 | value: {{ template "fullname" .}}-discovery 53 | {{- range $key, $value := .Values.global.env }} 54 | - name: {{ $key | upper | replace "-" "_" }} 55 | value: {{ $value | quote }} 56 | {{- end }} 57 | {{- range $key, $value := .Values.common.env }} 58 | - name: {{ $key | upper | replace "-" "_" }} 59 | value: {{ $value | quote }} 60 | {{- end }} 61 | {{- range $key, $value := .Values.data.env }} 62 | - name: {{ $key | upper | replace "-" "_" }} 63 | value: {{ $value | quote }} 64 | {{- end }} 65 | ports: 66 | - containerPort: 9300 67 | name: transport 68 | protocol: TCP 69 | volumeMounts: 70 | - name: esdata 71 | mountPath: /usr/share/elasticsearch/esdata/ 72 | readOnly: false 73 | - name: config 74 | mountPath: /usr/share/elasticsearch/config/elasticsearch.yml 75 | subPath: elasticsearch.yml 76 | volumes: 77 | - name: "config" 78 | configMap: 79 | name: {{ .Values.configmap.name }} 80 | volumeClaimTemplates: 81 | - metadata: 82 | name: esdata 83 | annotations: 84 | volume.beta.kubernetes.io/storage-class: default 85 | spec: 86 | accessModes: [ "ReadWriteOnce" ] 87 | resources: 88 | requests: 89 | storage: 10Gi #todo -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_discovery_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{template "fullname" .}}-discovery 5 | labels: 6 | component: {{template "fullname" .}} 7 | role: master 8 | spec: 9 | selector: 10 | component: {{template "fullname" .}} 11 | role: master 12 | ports: 13 | - name: transport 14 | port: 9300 15 | protocol: TCP 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_master_deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }}-master 5 | labels: 6 | component: {{ template "fullname" . }} 7 | role: master 8 | spec: 9 | replicas: {{ .Values.master.replicas }} 10 | template: 11 | metadata: 12 | labels: 13 | component: {{ template "fullname" . }} 14 | role: master 15 | spec: 16 | securityContext: 17 | runAsUser: 1000 18 | fsGroup: 1000 19 | # Elasticsearch uses a hybrid mmapfs / niofs directory by default to 20 | # store its indices. The default operating system limits on mmap counts 21 | # is likely to be too low, which may result in out of memory exceptions, 22 | # so we use vm.max_map_count=262144 to increase that value. 23 | initContainers: 24 | - name: init-sysctl 25 | image: "{{ .Values.global.busybox.image.repository }}" 26 | imagePullPolicy: IfNotPresent 27 | command: ['sh', '-c', 'sysctl -w vm.max_map_count=262144'] 28 | securityContext: 29 | runAsUser: 0 30 | privileged: true 31 | containers: 32 | - name: es-master 33 | securityContext: 34 | privileged: false 35 | capabilities: 36 | add: 37 | - IPC_LOCK 38 | - SYS_RESOURCE 39 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 40 | imagePullPolicy: {{ .Values.image.pullPolicy }} 41 | env: 42 | - name: NAMESPACE 43 | value: "{{ .Release.Namespace }}" 44 | - name: CHART_INFO 45 | value: "{{ .Chart.Name}} - {{ .Chart.Version }} - {{ .Release.Name }}" 46 | - name: NODE_NAME 47 | valueFrom: 48 | fieldRef: 49 | fieldPath: metadata.name 50 | - name: DISCOVERY_SERVICE 51 | value: {{ template "fullname" .}}-discovery 52 | {{- range $key, $value := .Values.global.env }} 53 | - name: {{ $key | upper | replace "-" "_" }} 54 | value: {{ $value | quote }} 55 | {{- end }} 56 | {{- range $key, $value := .Values.common.env }} 57 | - name: {{ $key | upper | replace "-" "_" }} 58 | value: {{ $value | quote }} 59 | {{- end }} 60 | {{- range $key, $value := .Values.master.env }} 61 | - name: {{ $key | upper | replace "-" "_" }} 62 | value: {{ $value | quote }} 63 | {{- end }} 64 | ports: 65 | - containerPort: 9300 66 | name: transport 67 | protocol: TCP 68 | volumeMounts: 69 | - name: esdata 70 | mountPath: /usr/share/elasticsearch/esdata/ 71 | - name: config 72 | mountPath: /usr/share/elasticsearch/config/elasticsearch.yml 73 | subPath: elasticsearch.yml 74 | volumes: 75 | - name: "esdata" 76 | emptyDir: 77 | medium: "" 78 | - name: "config" 79 | configMap: 80 | name: {{ .Values.configmap.name }} 81 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/templates/es_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | component: {{template "fullname" .}} 7 | role: client 8 | spec: 9 | type: {{ .Values.service.type }} 10 | selector: 11 | component: {{ template "fullname" . }} 12 | role: client 13 | ports: 14 | - name: http 15 | port: {{ .Values.service.httpPort }} 16 | targetPort: 9200 17 | protocol: TCP 18 | - name: transport 19 | port: {{ .Values.service.transportPort }} 20 | targetPort: 9300 21 | protocol: TCP 22 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/elastic_search_chart/values.yaml: -------------------------------------------------------------------------------- 1 | nameOverride: elasticsearch 2 | 3 | image: 4 | repository: docker.elastic.co/elasticsearch/elasticsearch 5 | tag: 5.5.1 6 | pullPolicy: Always 7 | 8 | configmap: 9 | name: es-config 10 | data: 11 | cluster.name: ${CLUSTER_NAME} 12 | node.master: ${NODE_MASTER} 13 | node.name: ${NODE_NAME} 14 | node.data: ${NODE_DATA} 15 | node.ingest: ${NODE_INGEST} 16 | network.host: ${NETWORK_HOST} 17 | path.data: /usr/share/elasticsearch/esdata/data 18 | path.logs: /usr/share/elasticsearch/esdata/log 19 | http.enabled: ${HTTP_ENABLE} 20 | http.compression: true 21 | discovery.zen.ping.unicast.hosts: ${DISCOVERY_SERVICE} 22 | discovery.zen.minimum_master_nodes: ${NUMBER_OF_MASTERS} 23 | xpack.graph.enabled: false 24 | xpack.ml.enabled: false 25 | xpack.monitoring.enabled: false 26 | xpack.security.enabled: false 27 | xpack.watcher.enabled: false 28 | 29 | common: 30 | env: 31 | NETWORK_HOST: "_eth0_" 32 | DISCOVERY_SERVICE: "elasticsearch-discovery" 33 | ES_JAVA_OPTS: "-Xms256m -Xmx256m" 34 | 35 | # The default value for this environment variable is 2, meaning a cluster 36 | # will need a minimum of 2 master nodes to operate. If you have 3 masters 37 | # and one dies, the cluster still works. 38 | NUMBER_OF_MASTERS: "2" 39 | 40 | # Data nodes hold the shards that contain the documents you have indexed. Data 41 | # nodes handle data related operations like CRUD, search, and aggregations. 42 | # These operations are I/O-, memory-, and CPU-intensive. It is important to 43 | # monitor these resources and to add more data nodes if they are overloaded. 44 | # 45 | # The main benefit of having dedicated data nodes is the separation of the 46 | # master and data roles. 47 | data: 48 | # This count will depend on your data and computation needs. 49 | replicas: 2 50 | env: 51 | NODE_MASTER: "false" 52 | NODE_DATA: "true" 53 | NODE_INGEST: "false" 54 | HTTP_ENABLE: "false" 55 | 56 | # The master node is responsible for lightweight cluster-wide actions such as 57 | # creating or deleting an index, tracking which nodes are part of the 58 | # cluster, and deciding which shards to allocate to which nodes. It is 59 | # important for cluster health to have a stable master node. 60 | master: 61 | # Master replica count should be (#clients / 2) + 1, and generally at least 3. 62 | replicas: 3 63 | env: 64 | NODE_MASTER: "true" 65 | NODE_DATA: "false" 66 | NODE_INGEST: "false" 67 | HTTP_ENABLE: "false" 68 | 69 | # Client/ingest nodes can execute pre-processing pipelines, composed of 70 | # one or more ingest processors. Depending on the type of operations 71 | # performed by the ingest processors and the required resources, it may make 72 | # sense to have dedicated ingest nodes, that will only perform this specific task. 73 | client: 74 | # It isn't common to need more than 2 client nodes. 75 | replicas: 2 76 | env: 77 | NODE_MASTER: "false" 78 | NODE_DATA: "false" 79 | NODE_INGEST: "true" 80 | HTTP_ENABLE: "true" 81 | 82 | service: 83 | type: ClusterIP 84 | httpPort: 9200 85 | transportPort: 9300 -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/filebeat_chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: helm chart for filebeat 3 | name: filebeat 4 | version: 0.0.1 5 | engine: gotpl 6 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/filebeat_chart/templates/filebeat_configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Values.configmap.name }} 5 | data: 6 | filebeat.yml: | 7 | {{ toYaml .Values.configmap.data | indent 4 }} -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/filebeat_chart/templates/filebeat_deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: DaemonSet 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | component: {{ template "fullname" . }} 7 | spec: 8 | template: 9 | metadata: 10 | labels: 11 | component: {{ template "fullname" . }} 12 | spec: 13 | securityContext: 14 | runAsUser: 0 15 | containers: 16 | - name: {{ .Chart.Name }} 17 | securityContext: 18 | privileged: true 19 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 20 | imagePullPolicy: {{ .Values.image.pullPolicy }} 21 | command: [ "filebeat" ] 22 | args: [ "-e", "-c", "/etc/filebeat/filebeat.yml"] 23 | env: 24 | - name: NAMESPACE 25 | value: "{{ .Release.Namespace }}" 26 | - name: CHART_INFO 27 | value: "{{ .Chart.Name}} - {{ .Chart.Version }} - {{ .Release.Name }}" 28 | - name: NODE_NAME 29 | valueFrom: 30 | fieldRef: 31 | fieldPath: metadata.name 32 | {{- range $key, $value := .Values.global.env }} 33 | - name: {{ $key | upper | replace "-" "_" }} 34 | value: {{ $value | quote }} 35 | {{- end }} 36 | {{- range $key, $value := .Values.env }} 37 | - name: {{ $key | upper | replace "-" "_" }} 38 | value: {{ $value | quote }} 39 | {{- end }} 40 | volumeMounts: 41 | - name: config 42 | mountPath: /etc/filebeat/filebeat.yml 43 | subPath: filebeat.yml 44 | - name: varlog 45 | mountPath: /var/log/containers 46 | - name: varlogpods 47 | mountPath: /var/log/pods 48 | readOnly: true 49 | - name: varlibdockercontainers 50 | mountPath: /var/lib/docker/containers 51 | readOnly: true 52 | terminationGracePeriodSeconds: 30 53 | volumes: 54 | - name: "config" 55 | configMap: 56 | name: {{ .Values.configmap.name }} 57 | - name: "varlog" 58 | hostPath: 59 | path: /var/log/containers 60 | - name: "varlogpods" 61 | hostPath: 62 | path: /var/log/pods 63 | - name: "varlibdockercontainers" 64 | hostPath: 65 | path: /var/lib/docker/containers -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/filebeat_chart/values.yaml: -------------------------------------------------------------------------------- 1 | nameOverride: filebeat 2 | 3 | image: 4 | repository: docker.elastic.co/beats/filebeat 5 | tag: 5.5.1 6 | pullPolicy: Always 7 | 8 | configmap: 9 | name: filebeat-config 10 | data: 11 | filebeat.prospectors: 12 | - input_type: log 13 | paths: 14 | - "/var/log/containers/*.log" 15 | exclude_files: ['filebeat.*log','kube.*log'] 16 | symlinks: true 17 | json.message_key: log 18 | json.keys_under_root: true 19 | json.add_error_key: true 20 | multiline.pattern: '^\s' 21 | multiline.match: after 22 | document_type: kube-logs 23 | output.logstash: 24 | hosts: ${LOGSTASH_HOSTS} 25 | timeout: 15 26 | logging.level: ${LOG_LEVEL} 27 | 28 | env: 29 | LOGSTASH_HOSTS: logstash:5043 30 | LOG_LEVEL: debug -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/kibana_chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: helm chart for kibana 3 | name: kibana 4 | version: 0.0.1 5 | engine: gotpl 6 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/kibana_chart/templates/kibana_configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Values.configmap.name }} 5 | data: 6 | kibana.yml: | 7 | {{ toYaml .Values.configmap.data | indent 4 }} 8 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/kibana_chart/templates/kibana_deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | component: {{ template "fullname" . }} 7 | spec: 8 | replicas: {{ .Values.replicaCount }} 9 | template: 10 | metadata: 11 | labels: 12 | component: {{ template "fullname" . }} 13 | spec: 14 | securityContext: 15 | runAsUser: 1000 16 | fsGroup: 1000 17 | containers: 18 | - name: {{ .Chart.Name }} 19 | securityContext: 20 | privileged: false 21 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 22 | imagePullPolicy: {{ .Values.image.pullPolicy }} 23 | env: 24 | - name: NAMESPACE 25 | value: "{{ .Release.Namespace }}" 26 | - name: CHART_INFO 27 | value: "{{ .Chart.Name}} - {{ .Chart.Version }} - {{ .Release.Name }}" 28 | - name: NODE_NAME 29 | valueFrom: 30 | fieldRef: 31 | fieldPath: metadata.name 32 | {{- range $key, $value := .Values.global.env }} 33 | - name: {{ $key | upper | replace "-" "_" }} 34 | value: {{ $value | quote }} 35 | {{- end }} 36 | ports: 37 | - containerPort: 5601 38 | name: kibana 39 | protocol: TCP 40 | volumeMounts: 41 | - name: config 42 | mountPath: /usr/share/kibana/config/kibana.yml 43 | subPath: kibana.yml 44 | volumes: 45 | - name: "config" 46 | configMap: 47 | name: {{ .Values.configmap.name }} -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/kibana_chart/templates/kibana_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | component: {{ template "fullname" . }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - name: http 11 | port: {{ .Values.service.port }} 12 | targetPort: 5601 13 | protocol: TCP 14 | selector: 15 | component: {{ template "fullname" . }} 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/kibana_chart/values.yaml: -------------------------------------------------------------------------------- 1 | nameOverride: kibana 2 | 3 | image: 4 | repository: docker.elastic.co/kibana/kibana 5 | tag: 5.5.1 6 | pullPolicy: Always 7 | 8 | configmap: 9 | name: kibana-config 10 | data: 11 | server.name: kibana 12 | server.host: "0" 13 | elasticsearch.url: http://elasticsearch:9200 14 | xpack.graph.enabled: false 15 | xpack.ml.enabled: false 16 | xpack.monitoring.enabled: false 17 | xpack.reporting.enabled: false 18 | xpack.security.enabled: false 19 | 20 | replicaCount: 2 21 | 22 | service: 23 | type: LoadBalancer 24 | port: 80 -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/logstash_chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: helm chart for logstash 3 | name: logstash 4 | version: 0.0.1 5 | engine: gotpl 6 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/logstash_chart/pipeline/logstash.conf: -------------------------------------------------------------------------------- 1 | input { 2 | beats { 3 | host => "0.0.0.0" 4 | port => 5043 5 | } 6 | } 7 | 8 | filter { 9 | if [type] == "kube-logs" { 10 | 11 | mutate { 12 | rename => ["log", "message"] 13 | } 14 | 15 | date { 16 | match => ["time", "ISO8601"] 17 | remove_field => ["time"] 18 | } 19 | 20 | grok { 21 | match => { "source" => "/var/log/containers/%{DATA:pod_name}_%{DATA:namespace}_%{GREEDYDATA:container_name}-%{DATA:container_id}.log" } 22 | remove_field => ["source"] 23 | } 24 | } 25 | } 26 | 27 | output { 28 | elasticsearch { 29 | hosts => "${ES_URL}" 30 | manage_template => false 31 | index => "%{[@metadata][beat]}-%{+YYYY.MM.dd}" 32 | document_type => "%{[@metadata][type]}" 33 | } 34 | } -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/logstash_chart/templates/logstash_configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ .Values.configmap.name }} 5 | data: 6 | logstash.conf: | 7 | {{ .Files.Get "pipeline/logstash.conf" | printf "%s" | indent 4 }} 8 | 9 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/logstash_chart/templates/logstash_deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | component: {{ template "fullname" . }} 7 | spec: 8 | replicas: {{ .Values.replicaCount }} 9 | template: 10 | metadata: 11 | labels: 12 | component: {{ template "fullname" . }} 13 | spec: 14 | securityContext: 15 | runAsUser: 1000 16 | fsGroup: 1000 17 | containers: 18 | - name: {{ .Chart.Name }} 19 | securityContext: 20 | privileged: false 21 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 22 | imagePullPolicy: {{ .Values.image.pullPolicy }} 23 | env: 24 | - name: NAMESPACE 25 | value: "{{ .Release.Namespace }}" 26 | - name: CHART_INFO 27 | value: "{{ .Chart.Name}} - {{ .Chart.Version }} - {{ .Release.Name }}" 28 | - name: NODE_NAME 29 | valueFrom: 30 | fieldRef: 31 | fieldPath: metadata.name 32 | {{- range $key, $value := .Values.global.env }} 33 | - name: {{ $key | upper | replace "-" "_" }} 34 | value: {{ $value | quote }} 35 | {{- end }} 36 | {{- range $key, $value := .Values.env }} 37 | - name: {{ $key | upper | replace "-" "_" }} 38 | value: {{ $value | quote }} 39 | {{- end }} 40 | ports: 41 | - containerPort: 5043 42 | name: http 43 | protocol: TCP 44 | volumeMounts: 45 | - name: pipeline 46 | mountPath: /usr/share/logstash/pipeline/logstash.conf 47 | subPath: logstash.conf 48 | volumes: 49 | - name: "pipeline" 50 | configMap: 51 | name: {{ .Values.configmap.name }} -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/logstash_chart/templates/logstash_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | component: {{ template "fullname" . }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - name: {{ .Values.service.name }} 11 | port: {{ .Values.service.port }} 12 | targetPort: 5043 13 | protocol: TCP 14 | selector: 15 | component: {{ template "fullname" . }} 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/charts/logstash_chart/values.yaml: -------------------------------------------------------------------------------- 1 | nameOverride: logstash 2 | 3 | image: 4 | repository: docker.elastic.co/logstash/logstash 5 | tag: 5.5.1 6 | pullPolicy: Always 7 | 8 | replicaCount: 2 9 | 10 | configmap: 11 | name: logstash-config 12 | 13 | env: 14 | HTTP_HOST: 0.0.0.0 15 | ES_URL: http://elasticsearch:9200 16 | XPACK_MONITORING_ENABLED: false 17 | 18 | service: 19 | name: logstash 20 | type: ClusterIP 21 | port: 5043 -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 53 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 53 chars (63 - len("-discovery")) because some Kubernetes name fields are limited to 63 (by the DNS naming spec). 12 | */}} 13 | {{- define "fullname" -}} 14 | {{- default .Chart.Name .Values.nameOverride | trunc 53 | trimSuffix "-" -}} 15 | {{- end -}} 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/elk/values.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | env: 3 | CLUSTER_NAME: "elk-k8s-cluster" 4 | busybox: 5 | image: 6 | repository: busybox -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: grafana 2 | version: 0.4.1 3 | description: The leading tool for querying and visualizing time series and metrics. 4 | home: https://grafana.net 5 | icon: https://raw.githubusercontent.com/grafana/grafana/master/public/img/logo_transparent_400x.png 6 | sources: 7 | - https://github.com/grafana/grafana 8 | maintainers: 9 | - name: Ming Hsieh 10 | email: zanhsieh@gmail.com 11 | engine: gotpl 12 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/README.md: -------------------------------------------------------------------------------- 1 | # Grafana Helm Chart 2 | 3 | * Installs the web dashboarding system [Grafana](http://grafana.org/) 4 | 5 | ## TL;DR; 6 | 7 | ```console 8 | $ helm install stable/grafana 9 | ``` 10 | 11 | ## Installing the Chart 12 | 13 | To install the chart with the release name `my-release`: 14 | 15 | ```console 16 | $ helm install --name my-release stable/grafana 17 | ``` 18 | 19 | ## Uninstalling the Chart 20 | 21 | To uninstall/delete the my-release deployment: 22 | 23 | ```console 24 | $ helm delete my-release 25 | ``` 26 | 27 | The command removes all the Kubernetes components associated with the chart and deletes the release. 28 | 29 | 30 | ## Configuration 31 | 32 | | Parameter | Description | Default | 33 | |----------------------------------------|-------------------------------------|---------------------------------------------------| 34 | | `server.image` | Container image to run | grafana/grafana:latest | 35 | | `server.adminUser` | Admin user username | admin | 36 | | `server.adminPassword` | Admin user password | admin | 37 | | `server.persistentVolume.enabled` | Create a volume to store data | true | 38 | | `server.persistentVolume.size` | Size of persistent volume claim | 1Gi RW | 39 | | `server.persistentVolume.storageClass` | Type of persistent volume claim | `nil` (uses alpha storage class annotation) | 40 | | `server.persistentVolume.accessMode` | ReadWriteOnce or ReadOnly | [ReadWriteOnce] | 41 | | `server.persistentVolume.existingClaim`| Existing persistent volume claim | null | 42 | | `server.persistentVolume.subPath` | Subdirectory of pvc to mount | null | 43 | | `server.resources` | Server resource requests and limits | requests: {cpu: 100m, memory: 100Mi} | 44 | | `server.serviceType` | ClusterIP, NodePort, or LoadBalancer| ClusterIP | 45 | | `server.setDatasource.enabled` | Creates grafana datasource with job | false | 46 | | `server.service.annotations` | Service annotations | null | 47 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get your '{{ .Values.server.adminUser }}' user password by running: 2 | 3 | kubectl get secret --namespace {{ .Release.Namespace }} {{ template "grafana.server.fullname" . }} -o jsonpath="{.data.grafana-admin-password}" | base64 --decode ; echo 4 | 5 | 2. The Grafana server can be accessed via port {{ .Values.server.httpPort }} on the following DNS name from within your cluster: 6 | 7 | {{ template "grafana.server.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local 8 | {{ if .Values.server.ingress.enabled }} 9 | From outside the cluster, the server URL(s) are: 10 | {{- range .Values.server.ingress.hosts }} 11 | http://{{ . }} 12 | {{- end }} 13 | {{ else }} 14 | Get the Grafana URL to visit by running these commands in the same shell: 15 | {{ if contains "NodePort" .Values.server.serviceType -}} 16 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "grafana.server.fullname" . }}) 17 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 18 | echo http://$NODE_IP:$NODE_PORT 19 | {{ else if contains "LoadBalancer" .Values.server.serviceType -}} 20 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 21 | You can watch the status of by running 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "grafana.server.fullname" . }}' 22 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "grafana.server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') 23 | echo http://$SERVICE_IP:{{ .Values.server.httpPort -}} 24 | {{ else if contains "ClusterIP" .Values.server.serviceType }} 25 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "grafana.fullname" . }},component={{ .Values.server.name }}" -o jsonpath="{.items[0].metadata.name}") 26 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 3000 27 | {{- end }} 28 | {{- end }} 29 | 30 | 3. Login with the password from step 1 and the username: {{ .Values.server.adminUser }} 31 | 32 | {{- if .Values.server.persistentVolume.enabled }} 33 | {{- else }} 34 | ################################################################################# 35 | ###### WARNING: Persistence is disabled!!! You will lose your data when ##### 36 | ###### the Grafana pod is terminated. ##### 37 | ################################################################################# 38 | {{- end }} 39 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "grafana.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | */}} 13 | {{- define "grafana.fullname" -}} 14 | {{- $name := default "grafana" .Values.nameOverride -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | 18 | {{/* 19 | Create a fully qualified server name. 20 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 21 | */}} 22 | {{- define "grafana.server.fullname" -}} 23 | {{- printf "%s-%s" .Release.Name "grafana" | trunc 63 | trimSuffix "-" -}} 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | labels: 5 | app: {{ template "grafana.fullname" . }} 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | component: "{{ .Values.server.name }}" 8 | heritage: "{{ .Release.Service }}" 9 | release: "{{ .Release.Name }}" 10 | name: {{ template "grafana.server.fullname" . }}-config 11 | data: 12 | {{- if .Values.server.installPlugins }} 13 | grafana-install-plugins: {{ .Values.server.installPlugins | quote }} 14 | {{- end }} 15 | {{ toYaml .Values.serverConfigFile | indent 2 }} 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/dashboards-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | labels: 5 | app: {{ template "grafana.fullname" . }} 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | component: "{{ .Values.server.name }}" 8 | heritage: "{{ .Release.Service }}" 9 | release: "{{ .Release.Name }}" 10 | name: {{ template "grafana.server.fullname" . }}-dashs 11 | data: 12 | {{ toYaml .Values.serverDashboardFiles | indent 2 }} 13 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: {{ template "grafana.fullname" . }} 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | component: "{{ .Values.server.name }}" 8 | heritage: "{{ .Release.Service }}" 9 | release: "{{ .Release.Name }}" 10 | name: {{ template "grafana.server.fullname" . }} 11 | spec: 12 | replicas: 1 13 | template: 14 | metadata: 15 | annotations: 16 | {{- range $key, $value := .Values.server.annotations }} 17 | {{ $key }}: {{ $value }} 18 | {{- end }} 19 | labels: 20 | app: {{ template "grafana.fullname" . }} 21 | component: "{{ .Values.server.name }}" 22 | release: "{{ .Release.Name }}" 23 | spec: 24 | nodeSelector: 25 | {{ toYaml .Values.server.nodeSelector | indent 12 }} 26 | containers: 27 | - name: {{ template "grafana.name" . }} 28 | image: "{{ .Values.server.image }}" 29 | imagePullPolicy: {{ default "Always" .Values.server.imagePullPolicy }} 30 | env: 31 | - name: GF_SECURITY_ADMIN_USER 32 | valueFrom: 33 | secretKeyRef: 34 | name: {{ template "grafana.server.fullname" . }} 35 | key: grafana-admin-user 36 | - name: GF_SECURITY_ADMIN_PASSWORD 37 | valueFrom: 38 | secretKeyRef: 39 | name: {{ template "grafana.server.fullname" . }} 40 | key: grafana-admin-password 41 | {{- if .Values.server.installPlugins }} 42 | - name: GF_INSTALL_PLUGINS 43 | valueFrom: 44 | configMapKeyRef: 45 | name: {{ template "grafana.server.fullname" . }}-config 46 | key: grafana-install-plugins 47 | {{- end }} 48 | ports: 49 | - containerPort: 3000 50 | readinessProbe: 51 | httpGet: 52 | path: /login 53 | port: 3000 54 | initialDelaySeconds: 30 55 | timeoutSeconds: 30 56 | resources: 57 | {{ toYaml .Values.server.resources | indent 12 }} 58 | volumeMounts: 59 | - name: config-volume 60 | mountPath: {{ default "/etc/grafana" .Values.server.configLocalPath | quote }} 61 | - name: dashboard-volume 62 | mountPath: {{ default "/var/lib/grafana/dashboards" .Values.server.dashboardLocalPath | quote }} 63 | - name: storage-volume 64 | mountPath: {{ default "/var/lib/grafana/data" .Values.server.storageLocalPath | quote }} 65 | subPath: "{{ .Values.server.persistentVolume.subPath }}" 66 | terminationGracePeriodSeconds: {{ default 300 .Values.server.terminationGracePeriodSeconds }} 67 | volumes: 68 | - name: config-volume 69 | configMap: 70 | name: {{ template "grafana.server.fullname" . }}-config 71 | - name: dashboard-volume 72 | configMap: 73 | name: {{ template "grafana.server.fullname" . }}-dashs 74 | - name: storage-volume 75 | {{- if .Values.server.persistentVolume.enabled }} 76 | persistentVolumeClaim: 77 | claimName: {{ if .Values.server.persistentVolume.existingClaim }}{{ .Values.server.persistentVolume.existingClaim }}{{- else }}{{ template "grafana.server.fullname" . }}{{- end }} 78 | {{- else }} 79 | emptyDir: {} 80 | {{- end -}} 81 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.ingress.enabled -}} 2 | {{- $releaseName := .Release.Name -}} 3 | {{- $servicePort := .Values.server.httpPort -}} 4 | apiVersion: extensions/v1beta1 5 | kind: Ingress 6 | metadata: 7 | annotations: 8 | {{- range $key, $value := .Values.server.ingress.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | labels: 12 | app: {{ template "grafana.fullname" . }} 13 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 14 | component: "{{ .Values.server.name }}" 15 | heritage: "{{ .Release.Service }}" 16 | release: "{{ .Release.Name }}" 17 | name: {{ template "grafana.server.fullname" . }} 18 | spec: 19 | rules: 20 | {{- range .Values.server.ingress.hosts }} 21 | - host: {{ . }} 22 | http: 23 | paths: 24 | - backend: 25 | serviceName: {{ printf "%s-%s" $releaseName "grafana" | trunc 63 }} 26 | servicePort: {{ $servicePort }} 27 | {{- end -}} 28 | {{- if .Values.server.ingress.tls }} 29 | tls: 30 | {{ toYaml .Values.server.ingress.tls | indent 4 }} 31 | {{- end -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/job.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.setDatasource.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | labels: 6 | app: {{ template "grafana.fullname" . }} 7 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 8 | component: "{{ .Values.server.name }}" 9 | heritage: "{{ .Release.Service }}" 10 | release: "{{ .Release.Name }}" 11 | name: {{ template "grafana.server.fullname" . }}-set-datasource 12 | spec: 13 | activeDeadlineSeconds: {{ default 300 .Values.server.setDatasource.activeDeadlineSeconds }} 14 | template: 15 | metadata: 16 | labels: 17 | app: {{ template "grafana.fullname" . }} 18 | component: "{{ .Values.server.name }}" 19 | release: "{{ .Release.Name }}" 20 | spec: 21 | containers: 22 | - name: {{ template "grafana.server.fullname" . }}-set-datasource 23 | image: "{{ .Values.server.setDatasource.image }}" 24 | env: 25 | - name: ADMIN_USER 26 | valueFrom: 27 | secretKeyRef: 28 | name: {{ template "grafana.server.fullname" . }} 29 | key: grafana-admin-user 30 | - name: ADMIN_PASSWORD 31 | valueFrom: 32 | secretKeyRef: 33 | name: {{ template "grafana.server.fullname" . }} 34 | key: grafana-admin-password 35 | args: 36 | - "http://$(ADMIN_USER):$(ADMIN_PASSWORD)@{{ template "grafana.fullname" . }}:{{ .Values.server.httpPort }}/api/datasources" 37 | - "--max-time" 38 | - "10" 39 | - "-H" 40 | - "Content-Type: application/json;charset=UTF-8" 41 | - "--data-binary" 42 | {{- with .Values.server.setDatasource.datasource }} 43 | - "{\"name\":\"{{ .name }}\",\"type\":\"{{ .type }}\",\"url\":\"{{ .url }}\",\"database\":\"{{ .database }}\",\"jsonData\":{ {{ .jsonData }} },\"access\":\"{{ .access }}\",\"isDefault\":{{ .isDefault }}}" 44 | {{- end }} 45 | restartPolicy: {{ .Values.server.setDatasource.restartPolicy }} 46 | {{- end -}} 47 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.persistentVolume.enabled -}} 2 | {{- if not .Values.server.persistentVolume.existingClaim -}} 3 | apiVersion: v1 4 | kind: PersistentVolumeClaim 5 | metadata: 6 | annotations: 7 | {{- if .Values.server.persistentVolume.storageClass }} 8 | volume.beta.kubernetes.io/storage-class: {{ .Values.server.persistentVolume.storageClass | quote }} 9 | {{- else }} 10 | volume.alpha.kubernetes.io/storage-class: default 11 | {{- end }} 12 | {{- if .Values.server.persistentVolume.annotations }} 13 | {{ toYaml .Values.server.persistentVolume.annotations | indent 4 }} 14 | {{- end }} 15 | labels: 16 | app: {{ template "grafana.fullname" . }} 17 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 18 | component: "{{ .Values.server.name }}" 19 | heritage: "{{ .Release.Service }}" 20 | release: "{{ .Release.Name }}" 21 | name: {{ template "grafana.server.fullname" . }} 22 | spec: 23 | accessModes: 24 | {{- range .Values.server.persistentVolume.accessModes }} 25 | - {{ . | quote }} 26 | {{- end }} 27 | resources: 28 | requests: 29 | storage: {{ .Values.server.persistentVolume.size | quote }} 30 | {{- end -}} 31 | {{- end -}} 32 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | labels: 5 | app: {{ template "grafana.fullname" . }} 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | heritage: "{{ .Release.Service }}" 8 | release: "{{ .Release.Name }}" 9 | name: {{ template "grafana.server.fullname" . }} 10 | type: Opaque 11 | data: 12 | {{- if .Values.server.adminPassword }} 13 | grafana-admin-password: {{ .Values.server.adminPassword | b64enc | quote }} 14 | {{- else }} 15 | grafana-admin-password: {{ randAlphaNum 10 | b64enc | quote }} 16 | {{- end }} 17 | grafana-admin-user: {{ .Values.server.adminUser | b64enc | quote }} 18 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/grafana/templates/svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | {{- if .Values.server.service.annotations }} 5 | annotations: 6 | {{ toYaml .Values.server.service.annotations | indent 4 }} 7 | {{- end }} 8 | labels: 9 | app: {{ template "grafana.fullname" . }} 10 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 11 | component: "{{ .Values.server.name }}" 12 | heritage: "{{ .Release.Service }}" 13 | release: "{{ .Release.Name }}" 14 | name: {{ template "grafana.server.fullname" . }} 15 | spec: 16 | ports: 17 | - name: {{ default "http" .Values.server.httpPortName | quote }} 18 | port: {{ .Values.server.httpPort }} 19 | protocol: TCP 20 | targetPort: 3000 21 | {{- if contains "NodePort" .Values.server.serviceType }} 22 | {{- if .Values.server.nodePort }} 23 | nodePort: {{ .Values.server.nodePort }} 24 | {{- end }} 25 | {{- end }} 26 | selector: 27 | app: {{ template "grafana.fullname" . }} 28 | component: "{{ .Values.server.name }}" 29 | type: "{{ .Values.server.serviceType }}" 30 | {{- if contains "LoadBalancer" .Values.server.serviceType }} 31 | {{- if .Values.server.loadBalancerIP }} 32 | loadBalancerIP: {{ .Values.server.loadBalancerIP }} 33 | {{- end -}} 34 | {{- if .Values.server.loadBalancerSourceRanges }} 35 | loadBalancerSourceRanges: 36 | {{- range .Values.server.loadBalancerSourceRanges }} 37 | - {{ . }} 38 | {{- end }} 39 | {{- end -}} 40 | {{- end -}} 41 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: Heapster enables Container Cluster Monitoring and Performance Analysis. 3 | name: heapster 4 | version: 0.1.1 5 | sources: 6 | - https://github.com/kubernetes/heapster 7 | - https://github.com/kubernetes/contrib/tree/master/addon-resizer 8 | keywords: 9 | - metrics 10 | - cadvisor 11 | - monitoring 12 | maintainers: 13 | - name: Jose Aguirre 14 | email: jose.g.aguirre@intel.com 15 | engine: gotpl 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/README.md: -------------------------------------------------------------------------------- 1 | # Heapster 2 | 3 | [Heapster](https://github.com/kubernetes/heapster) enables Container Cluster Monitoring and Performance Analysis. It collects and interprets various signals like compute resource usage, lifecycle events, etc, and exports cluster metrics via REST endpoints. 4 | 5 | ## QuickStart 6 | 7 | ```bash 8 | $ helm install stable/heapster 9 | ``` 10 | 11 | ## Installing the Chart 12 | 13 | To install the chart with the release name `my-release`: 14 | 15 | ```bash 16 | $ helm install --name my-release stable/heapster 17 | ``` 18 | 19 | ## Uninstalling the Chart 20 | 21 | To uninstall/delete the `my-release` deployment: 22 | 23 | ```bash 24 | $ helm delete my-release --purge 25 | ``` 26 | 27 | The command removes all the Kubernetes components associated with the chart and deletes the release. 28 | 29 | ## Configuration 30 | 31 | The default configuration values for this chart are listed in `values.yaml`. 32 | 33 | | Parameter | Description | Default | 34 | |---------------------------------------|-------------------------------------|---------------------------------------------------| 35 | | `image.repository` | Repository for container image | gcr.io/google_containers/heapster | 36 | | `image.tag` | Container image tag | v1.3.0 | 37 | | `image.pullPolicy` | Image pull policy | IfNotPresent | 38 | | `service.name` | Service port name | api | 39 | | `service.type` | Type for the service | ClusterIP | 40 | | `service.externalPort` | Service external port | 8082 | 41 | | `service.internalPort` | Service internal port | 8082 | 42 | | `resources.limits` | Server resource limits | requests: {cpu: 100m, memory: 128Mi} | 43 | | `resources.requests` | Server resource requests | requests: {cpu: 100m, memory: 128Mi} | 44 | | `command` | Commands for heapster pod | "/heapster --source=kubernetes.summary_api:'' | 45 | | `resizer.enabled` | If enabled, scale resources | true | 46 | 47 | The table below is only applicable if `resizer.enabled` is `true`. More information on resizer can be found [here](https://github.com/kubernetes/contrib/blob/master/addon-resizer/README.md). 48 | 49 | | Parameter | Description | Default | 50 | |---------------------------------------|-------------------------------------|---------------------------------------------------| 51 | | `resizer.image.repository` | Repository for container image | gcr.io/google_containers/addon-resizer | 52 | | `resizer.image.tag` | Container image tag | 1.7 | 53 | | `resizer.image.pullPolicy` | Image pull policy | IfNotPresent | 54 | | `resizer.resources.limits` | Server resource limits | requests: {cpu: 50m, memory: 90Mi} | 55 | | `resizer.resources.requests` | Server resource requests | requests: {cpu: 50m, memory: 90Mi} | 56 | | `resizer.flags` | Flags for pod nanny command | Defaults set in values.yaml | 57 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if contains "NodePort" .Values.service.type }} 3 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "service.fullname" . }}) 4 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 5 | echo http://$NODE_IP:$NODE_PORT/ 6 | {{- else if contains "LoadBalancer" .Values.service.type }} 7 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 8 | You can watch the status of by running 'kubectl get svc -w {{ template "service.fullname" . }}' 9 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "service.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') 10 | echo http://$SERVICE_IP:{{ .Values.service.externalPort }} 11 | {{- else if contains "ClusterIP" .Values.service.type }} 12 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "service.fullname" . }}" -o jsonpath="{.items[0].metadata.name}") 13 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME {{ .Values.service.externalPort }} 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | */}} 13 | {{- define "fullname" -}} 14 | {{- $name := default .Chart.Name .Values.nameOverride -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | 18 | {{/* 19 | Create a service name that defaults to app name. 20 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 21 | */}} 22 | {{- define "service.fullname" -}} 23 | {{- .Values.service.nameOverride | default .Chart.Name }} 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | {{- range $key, $value := .Values.labels }} 8 | {{ $key }}: {{ $value }} 9 | {{- end }} 10 | spec: 11 | replicas: {{ .Values.replicaCount }} 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ template "fullname" . }} 16 | spec: 17 | containers: 18 | - name: {{ .Chart.Name }} 19 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 20 | imagePullPolicy: {{ .Values.image.pullPolicy }} 21 | ports: 22 | - containerPort: {{ .Values.service.internalPort }} 23 | livenessProbe: 24 | httpGet: 25 | path: /healthz 26 | port: {{ .Values.service.internalPort }} 27 | initialDelaySeconds: 180 28 | timeoutSeconds: 5 29 | resources: 30 | {{ toYaml .Values.resources | indent 12 }} 31 | command: 32 | {{- range .Values.command }} 33 | - {{ . | quote }} 34 | {{- end }} 35 | {{ if .Values.resizer.enabled }} 36 | - name: {{ .Chart.Name }}-nanny 37 | {{ with .Values.resizer }} 38 | image: "{{ .image.repository }}:{{ .image.tag }}" 39 | imagePullPolicy: {{ .image.pullPolicy }} 40 | resources: 41 | {{ toYaml .resources | indent 12 }} 42 | env: 43 | - name: MY_POD_NAME 44 | valueFrom: 45 | fieldRef: 46 | fieldPath: metadata.name 47 | - name: MY_POD_NAMESPACE 48 | valueFrom: 49 | fieldRef: 50 | fieldPath: metadata.namespace 51 | {{- end }} 52 | command: 53 | - "/pod_nanny" 54 | - "--deployment={{ template "fullname" . }}" 55 | - "--container={{ .Chart.Name }}" 56 | {{- range .Values.resizer.flags }} 57 | - {{ . | quote }} 58 | {{- end }} 59 | {{- end -}} 60 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "service.fullname" . }} 5 | labels: 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | app: {{ template "fullname" . }} 8 | heritage: "{{ .Release.Service }}" 9 | release: "{{ .Release.Name }}" 10 | {{- range $key, $value := .Values.service.labels }} 11 | {{ $key }}: {{ $value }} 12 | {{- end }} 13 | spec: 14 | type: {{ .Values.service.type }} 15 | ports: 16 | - port: {{ .Values.service.externalPort }} 17 | targetPort: {{ .Values.service.internalPort }} 18 | protocol: TCP 19 | selector: 20 | app: {{ template "fullname" . }} 21 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heapster/values.yaml: -------------------------------------------------------------------------------- 1 | ## Default values for heapster. 2 | ## 3 | replicaCount: 1 4 | image: 5 | repository: gcr.io/google_containers/heapster 6 | tag: v1.3.0 7 | pullPolicy: IfNotPresent 8 | ## Here labels can be added to the heapster deployment 9 | # labels: 10 | # kubernetes.io/cluster-service: "true" 11 | # kubernetes.io/name: "Heapster" 12 | labels: 13 | 14 | service: 15 | type: ClusterIP 16 | externalPort: 8082 17 | internalPort: 8082 18 | ## This allows an overide of the heapster service name 19 | ## Default: {{ .Chart.Name }} 20 | # nameOverride: 21 | 22 | ## Here labels can be added to the heapster service 23 | # labels: 24 | # kubernetes.io/cluster-service: "true" 25 | # kubernetes.io/name: "Heapster" 26 | labels: 27 | 28 | resources: 29 | limits: 30 | cpu: 100m 31 | memory: 128Mi 32 | requests: 33 | cpu: 100m 34 | memory: 128Mi 35 | 36 | ## Heapster command and arguments 37 | ## Default source=kubernetes.summary_api:'' 38 | ## ref: https://github.com/kubernetes/heapster/blob/master/docs/source-configuration.md 39 | ## 40 | ## By default sink not set 41 | ## ref: https://github.com/kubernetes/heapster/blob/master/docs/sink-configuration.md 42 | ## 43 | command: 44 | - "/heapster" 45 | - "--source=kubernetes.summary_api:''" 46 | 47 | ## Resizer scales resources linearly with the number of nodes in the cluster 48 | ## Resizer is enabled by default 49 | ## 50 | resizer: 51 | enabled: true 52 | image: 53 | repository: gcr.io/google_containers/addon-resizer 54 | tag: 1.7 55 | pullPolicy: IfNotPresent 56 | resources: 57 | limits: 58 | cpu: 50m 59 | memory: 90Mi 60 | requests: 61 | cpu: 50m 62 | memory: 90Mi 63 | 64 | ## Flags used for /pod_nanny command 65 | ## container and deployment flags already determined chart name 66 | ## ref: https://github.com/kubernetes/contrib/blob/master/addon-resizer/README.md 67 | ## 68 | flags: 69 | - "--cpu=150m" 70 | - "--extra-cpu=10m" 71 | - "--memory=200Mi" 72 | - "--extra-memory=6Mi" 73 | - "--threshold=5" 74 | - "--poll-period=300000" 75 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heartbeat/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: helm chart for heartbeat 3 | name: heartbeat 4 | version: 0.0.1 5 | maintainers: 6 | - name: Miao Zou 7 | email: mizo@microsoft.com -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heartbeat/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | */}} 13 | {{- define "fullname" -}} 14 | {{- default .Chart.Name .Values.nameOverride | trunc 53 | trimSuffix "-" -}} 15 | {{- end -}} 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heartbeat/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | data: 3 | heartbeat.yml: | 4 | {{ .Files.Get "config/heartbeat.yml" | printf "%s" | indent 4 }} 5 | kind: ConfigMap 6 | metadata: 7 | name: {{ template "fullname" . }} 8 | 9 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heartbeat/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 7 | {{- range $key, $value := .Values.labels }} 8 | {{ $key }}: {{ $value }} 9 | {{- end }} 10 | spec: 11 | replicas: {{ .Values.replicaCount }} 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ template "fullname" . }} 16 | annotations: 17 | checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 18 | spec: 19 | containers: 20 | - name: {{ .Chart.Name }} 21 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 22 | imagePullPolicy: {{ .Values.image.pullPolicy }} 23 | command: ["heartbeat"] 24 | args: ["-e", "-c", "/etc/heartbeat/heartbeat.yml"] 25 | volumeMounts: 26 | - mountPath: /etc/heartbeat 27 | name: config 28 | resources: 29 | {{ toYaml .Values.resources | indent 12 }} 30 | volumes: 31 | - name: config 32 | configMap: 33 | name: {{ template "fullname" . }} 34 | items: 35 | - key: heartbeat.yml 36 | path: heartbeat.yml 37 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/heartbeat/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for heartbeat. 2 | 3 | ## Replica count for heartbeat, by default use 1 4 | replicaCount: 1 5 | 6 | ## Heartbeat image repository 7 | ## If not in Azure Mooncake, use offical image from elastic 8 | ## repository: docker.elastic.co/beats/heartbeat 9 | ## 10 | ## If in Azure Mooncake, use the mirror image 11 | ## repository: mirror.azure.cn:5000/beats/heartbeat 12 | ## 13 | image: 14 | repository: docker.elastic.co/beats/heartbeat 15 | tag: 5.5.1 16 | pullPolicy: IfNotPresent 17 | 18 | ## Here labels can be added to the heartbeat deployment 19 | labels: 20 | feature: "monitoring" 21 | component: "heartbeat" 22 | 23 | ## Manage the resources of the heartbeat deployment 24 | resources: 25 | limits: 26 | cpu: 100m 27 | memory: 128Mi 28 | requests: 29 | cpu: 100m 30 | memory: 128Mi 31 | 32 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/Chart.yaml: -------------------------------------------------------------------------------- 1 | name: influxdb 2 | version: 0.4.2 3 | description: Scalable datastore for metrics, events, and real-time analytics. 4 | keywords: 5 | - influxdb 6 | - database 7 | - timeseries 8 | home: https://www.influxdata.com/time-series-platform/influxdb/ 9 | sources: 10 | - https://github.com/influxdata/influxdb 11 | maintainers: 12 | - name: Jack Zampolin 13 | email: jack@influxdb.com 14 | engine: gotpl 15 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/README.md: -------------------------------------------------------------------------------- 1 | # InfluxDB 2 | 3 | ## An Open-Source Time Series Database 4 | 5 | [InfluxDB](https://github.com/influxdata/influxdb) is an open source time series database built by the folks over at [InfluxData](https://influxdata.com) with no external dependencies. It's useful for recording metrics, events, and performing analytics. 6 | 7 | ## QuickStart 8 | 9 | ```bash 10 | $ helm install stable/influxdb --name foo --namespace bar 11 | ``` 12 | 13 | ## Introduction 14 | 15 | This chart bootstraps an InfluxDB deployment and service on a Kubernetes cluster using the Helm Package manager. 16 | 17 | ## Prerequisites 18 | 19 | - Kubernetes 1.4+ 20 | - PV provisioner support in the underlying infrastructure (optional) 21 | 22 | ## Installing the Chart 23 | 24 | To install the chart with the release name `my-release`: 25 | 26 | ```bash 27 | $ helm install --name my-release stable/influxdb 28 | ``` 29 | 30 | The command deploys InfluxDB on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. 31 | 32 | > **Tip**: List all releases using `helm list` 33 | 34 | ## Uninstalling the Chart 35 | 36 | To uninstall/delete the `my-release` deployment: 37 | 38 | ```bash 39 | $ helm delete my-release --purge 40 | ``` 41 | 42 | The command removes all the Kubernetes components associated with the chart and deletes the release. 43 | 44 | ## Configuration 45 | 46 | The default configuration values for this chart are listed in `values.yaml`. 47 | 48 | The [full image documentation](https://hub.docker.com/_/influxdb/) contains more information about running InfluxDB in docker. 49 | 50 | Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, 51 | 52 | ```bash 53 | $ helm install --name my-release \ 54 | --set persistence.enabled=true,persistence.size=200Gi \ 55 | stable/influxdb 56 | ``` 57 | 58 | The above command enables persistence and changes the size of the requested data volume to 200GB. 59 | 60 | Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, 61 | 62 | ```bash 63 | $ helm install --name my-release -f values.yaml stable/influxdb 64 | ``` 65 | 66 | > **Tip**: You can use the default [values.yaml](values.yaml) 67 | 68 | ## Persistence 69 | 70 | The [InfluxDB](https://hub.docker.com/_/influxdb/) image stores data in the `/var/lib/influxdb` directory in the container. 71 | 72 | The chart mounts a [Persistent Volume](http://kubernetes.io/docs/user-guide/persistent-volumes/) volume at this location. The volume is created using dynamic volume provisioning. 73 | 74 | ## Starting with authentication 75 | 76 | In `values.yaml` change `.Values.config.http.auth_enabled` to `true`. 77 | 78 | Influxdb requires also a user to be set in order for authentication to be enforced. See more details [here](https://docs.influxdata.com/influxdb/v1.2/query_language/authentication_and_authorization/#set-up-authentication). 79 | 80 | To handle this setup on startup, a job can be enabled in `values.yaml` by setting `.Values.setDefaultUser.enabled` to `true`. 81 | 82 | Make sure to uncomment or configure the job settings after enabling it. If a password is not set, a random password will be generated. 83 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | InfluxDB can be accessed via port {{ .Values.config.http.bind_address }} on the following DNS name from within your cluster: 2 | 3 | - http://{{ template "fullname" . }}.{{ .Release.Namespace }}:{{ .Values.config.http.bind_address }} 4 | 5 | You can easily connect to the remote instance with your local influx cli. To forward the API port to localhost:8086 run the following: 6 | 7 | - kubectl port-forward --namespace {{ .Release.Namespace }} $(kubectl get pods --namespace {{ .Release.Namespace }} -l app={{ template "fullname" . }} -o jsonpath='{ .items[0].metadata.name }') 8086:{{ .Values.config.http.bind_address }} 8 | 9 | You can also connect to the influx cli from inside the container. To open a shell session in the InfluxDB pod run the following: 10 | 11 | - kubectl exec -i -t --namespace {{ .Release.Namespace }} $(kubectl get pods --namespace {{ .Release.Namespace }} -l app={{ template "fullname" . }} -o jsonpath='{.items[0].metadata.name}') /bin/sh 12 | 13 | To tail the logs for the InfluxDB pod run the following: 14 | 15 | - kubectl logs -f --namespace {{ .Release.Namespace }} $(kubectl get pods --namespace {{ .Release.Namespace }} -l app={{ template "fullname" . }} -o jsonpath='{ .items[0].metadata.name }') 16 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | */}} 13 | {{- define "fullname" -}} 14 | {{- $name := default .Chart.Name .Values.nameOverride -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | app: {{ template "fullname" . }} 7 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 8 | release: "{{ .Release.Name }}" 9 | heritage: "{{ .Release.Service }}" 10 | spec: 11 | replicas: 1 12 | template: 13 | metadata: 14 | labels: 15 | app: {{ template "fullname" . }} 16 | spec: 17 | containers: 18 | - name: {{ template "fullname" . }} 19 | image: "{{ .Values.image.repo }}:{{ .Values.image.tag }}" 20 | imagePullPolicy: {{ .Values.image.pullPolicy | quote }} 21 | resources: 22 | {{ toYaml .Values.resources | indent 10 }} 23 | ports: 24 | - name: api 25 | containerPort: {{ .Values.config.http.bind_address }} 26 | {{ if .Values.config.admin.enabled -}} 27 | - name: admin 28 | containerPort: {{ .Values.config.admin.bind_address }} 29 | {{- end }} 30 | {{ if .Values.config.graphite.enabled -}} 31 | - name: graphite 32 | containerPort: {{ .Values.config.graphite.bind_address }} 33 | {{- end }} 34 | {{ if .Values.config.collectd.enabled -}} 35 | - name: collectd 36 | containerPort: {{ .Values.config.collectd.bind_address }} 37 | {{- end }} 38 | {{ if .Values.config.udp.enabled -}} 39 | - name: udp 40 | containerPort: {{ .Values.config.udp.bind_address }} 41 | {{- end }} 42 | {{ if .Values.config.opentsdb.enabled -}} 43 | - name: opentsdb 44 | containerPort: {{ .Values.config.opentsdb.bind_address }} 45 | {{- end }} 46 | livenessProbe: 47 | httpGet: 48 | path: /ping 49 | port: api 50 | initialDelaySeconds: 30 51 | timeoutSeconds: 5 52 | readinessProbe: 53 | httpGet: 54 | path: /ping 55 | port: api 56 | initialDelaySeconds: 5 57 | timeoutSeconds: 1 58 | volumeMounts: 59 | - name: data 60 | mountPath: {{ .Values.config.storage_directory }} 61 | - name: config 62 | mountPath: /etc/influxdb 63 | volumes: 64 | - name: data 65 | {{- if .Values.persistence.enabled }} 66 | {{- if not (empty .Values.persistence.name) }} 67 | persistentVolumeClaim: 68 | claimName: {{ .Values.persistence.name }} 69 | {{- else }} 70 | persistentVolumeClaim: 71 | claimName: {{ template "fullname" . }} 72 | {{- end }} 73 | {{- else }} 74 | emptyDir: {} 75 | {{- end }} 76 | - name: config 77 | configMap: 78 | name: {{ template "fullname" . }} 79 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/post-install-set-auth.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.setDefaultUser.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | labels: 6 | app: {{ template "fullname" . }} 7 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 8 | release: "{{ .Release.Name }}" 9 | heritage: "{{ .Release.Service }}" 10 | name: {{ template "fullname" . }}-set-auth 11 | annotations: 12 | "helm.sh/hook": post-install 13 | spec: 14 | activeDeadlineSeconds: {{ default 300 .Values.setDefaultUser.activeDeadlineSeconds }} 15 | template: 16 | metadata: 17 | labels: 18 | app: {{ template "fullname" . }} 19 | release: "{{ .Release.Name }}" 20 | spec: 21 | containers: 22 | - name: {{ template "fullname" . }}-set-auth 23 | image: "{{ .Values.setDefaultUser.image }}" 24 | env: 25 | - name: INFLUXDB_USER 26 | valueFrom: 27 | secretKeyRef: 28 | name: {{ template "fullname" . }}-auth 29 | key: influxdb-user 30 | - name: INFLUXDB_PASSWORD 31 | valueFrom: 32 | secretKeyRef: 33 | name: {{ template "fullname" . }}-auth 34 | key: influxdb-password 35 | args: 36 | - "/bin/sh" 37 | - "-c" 38 | - | 39 | curl -X POST http://{{ template "fullname" . }}:{{ .Values.config.http.bind_address }}/query \ 40 | --data-urlencode \ 41 | "q=CREATE USER \"${INFLUXDB_USER}\" WITH PASSWORD '${INFLUXDB_PASSWORD}' {{ .Values.setDefaultUser.user.privileges }}" 42 | restartPolicy: {{ .Values.setDefaultUser.restartPolicy }} 43 | {{- end -}} 44 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (.Values.persistence.enabled) (not .Values.persistence.useExisting) }} 2 | kind: PersistentVolumeClaim 3 | apiVersion: v1 4 | metadata: 5 | name: "{{- if not (empty .Values.persistence.name) }}{{ .Values.persistence.name }}{{- else }}{{ template "fullname" . }}{{- end }}" 6 | labels: 7 | app: "{{- if not (empty .Values.persistence.name) }}{{ .Values.persistence.name }}{{- else }}{{ template "fullname" . }}{{- end }}" 8 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 9 | release: "{{ .Release.Name }}" 10 | heritage: "{{ .Release.Service }}" 11 | annotations: 12 | {{- if .Values.persistence.storageClass }} 13 | volume.beta.kubernetes.io/storage-class: {{ .Values.persistence.storageClass | quote }} 14 | {{- else }} 15 | volume.alpha.kubernetes.io/storage-class: default 16 | {{- end }} 17 | spec: 18 | accessModes: 19 | - {{ .Values.persistence.accessMode | quote }} 20 | resources: 21 | requests: 22 | storage: {{ .Values.persistence.size | quote }} 23 | {{- end }} 24 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.setDefaultUser.enabled -}} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | labels: 6 | app: {{ template "fullname" . }} 7 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 8 | heritage: "{{ .Release.Service }}" 9 | release: "{{ .Release.Name }}" 10 | name: {{ template "fullname" . }}-auth 11 | data: 12 | {{- if .Values.setDefaultUser.user.password }} 13 | influxdb-password: {{ .Values.setDefaultUser.user.password | b64enc | quote }} 14 | {{- else }} 15 | influxdb-password: {{ randAscii 10 | b64enc | quote }} 16 | {{- end }} 17 | influxdb-user: {{ .Values.setDefaultUser.user.username | b64enc | quote }} 18 | {{- end -}} 19 | -------------------------------------------------------------------------------- /monitoring/k8s/helm-charts/influxdb/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | app: {{ template "fullname" . }} 7 | chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" 8 | release: "{{ .Release.Name }}" 9 | heritage: "{{ .Release.Service }}" 10 | spec: 11 | type: {{ .Values.service.type }} 12 | ports: 13 | {{- if .Values.config.http.enabled }} 14 | - name: api 15 | port: {{ .Values.config.http.bind_address }} 16 | targetPort: {{ .Values.config.http.bind_address }} 17 | {{- end }} 18 | {{- if .Values.config.admin.enabled }} 19 | - name: admin 20 | port: {{ .Values.config.admin.bind_address }} 21 | targetPort: {{ .Values.config.admin.bind_address }} 22 | {{- end }} 23 | {{- if .Values.config.graphite.enabled }} 24 | - name: graphite 25 | port: {{ .Values.config.graphite.bind_address }} 26 | targetPort: {{ .Values.config.graphite.bind_address }} 27 | {{- end }} 28 | {{- if .Values.config.collectd.enabled }} 29 | - name: collectd 30 | port: {{ .Values.config.collectd.bind_address }} 31 | targetPort: {{ .Values.config.collectd.bind_address }} 32 | {{- end }} 33 | {{- if .Values.config.udp.enabled }} 34 | - name: udp 35 | port: {{ .Values.config.udp.bind_address }} 36 | targetPort: {{ .Values.config.udp.bind_address }} 37 | {{- end }} 38 | {{- if .Values.config.opentsdb.enabled }} 39 | - name: opentsdb 40 | port: {{ .Values.config.opentsdb.bind_address }} 41 | targetPort: {{ .Values.config.opentsdb.bind_address }} 42 | {{- end }} 43 | selector: 44 | app: {{ template "fullname" . }} 45 | -------------------------------------------------------------------------------- /monitoring/k8s/licenses/elk-acs-kubernetes.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /private-docker-registry/README.md: -------------------------------------------------------------------------------- 1 | # Azure Docker Registry Template 2 | ## Deprecated: since **Azure Container Registry** is already available in China North region, following manual steps are not necessary now. 3 | This is a Azure ARM template to deploy Docker registry on Azure China. ***Some urls are hard coded to Azure China now, so this template is NOT workable on Global Azure.*** 4 | 5 | ## Overview 6 | 7 | This template deploy a simple Docker registry cluster based on Swarm Mode with TLS. The following is the architecture of the resources: 8 | 9 | ![arch](images/1.png) 10 | 11 | The default VM node is 2 and this value can be set when deploying. 12 | 13 | ## Prerequisite 14 | * Azure China Cloud subscription 15 | * Linux dev machine with [Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) installed 16 | * Login into the subscription with commands below 17 | ``` 18 | $ az cloud set -n AzureChinaCloud 19 | $ az login -u 20 | ``` 21 | * Clone the repo to dev machine with commands below 22 | ``` 23 | $ mkdir -p /path/to/project 24 | $ cd /path/to/project 25 | $ git clone https://github.com/Azure/devops-sample-solution-for-azure-china.git 26 | $ cd /path/to/project/devops-sample-solution-for-azure-china/private-docker-registry 27 | ``` 28 | 29 | ## Parameters in azuredeploy.parameters.json 30 | | Parameter | Descrption | Default Value | 31 | |-------------------|----------------------------------------------------|----------------| 32 | | adminUsername | Admin username | azureuser | 33 | | adminPassword | Password for the Virtual Machine | | 34 | | dnsNameforLBIP | DNS for Load Balancer IP | myhub01 | 35 | | registryPort | Port of registry | 5000 | 36 | | numberOfInstances | Number of Virtual Machine instances | 2 | 37 | | vmSize | The size of the Virtual Machine | Standard_D2_v2 | 38 | | sshRSAPublicKey | SSH public key used for auth to all Linux machines | | 39 | 40 | ## A. Deploy a plain HTTP registry 41 | For test purpose, you can deploy a plain HTTP registry. Notice that this is very insecure and not recommended. 42 | 1. Edit azuredeploy.parameters.json, and run command below 43 | ``` 44 | $ bash ./deploy-docker-registry.sh -n -l -m mirror.kaiyuanshe.cn 45 | ``` 46 | 2. Once deployment completed, on each machine that wants to access the registry, following the [instruction](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry) to configure client. 47 | E.g. for linux, edit /etc/docker/daemon.json with 48 | ``` 49 | { 50 | "insecure-registries" : [":5000"] 51 | } 52 | ``` 53 | and then restart docker with `sudo service docker restart`. 54 | 55 | Could also run below command to config the insecure registry settings in docker for each k8s nodes: 56 | ``` 57 | $ bash ./config-insecure-registry.sh -r -m -u -k 58 | ``` 59 | 60 | ## B. Deploy a TLS enabled registry with a self-signed certificate 61 | To be more secure than plain HTTP solution, you can [deploy with a self-signed certificate](https://docs.docker.com/registry/insecure/#use-self-signed-certificates). 62 | 1. Generate your own certificate following the link above, and replace certs/server.crt and certs/server.key. 63 | 2. Edit cloud-config-template.yml, and un-comment the lines below 64 | ``` 65 | - REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt 66 | - REGISTRY_HTTP_TLS_KEY=/certs/server.key 67 | ``` 68 | 3. Edit azuredeploy.parameters.json, and run command below 69 | ``` 70 | $ bash ./deploy-docker-registry.sh -n -l -m mirror.kaiyuanshe.cn 71 | ``` 72 | 4. Once deployment completed, on each machine that wants to access the registry, following the [instruction](https://docs.docker.com/registry/insecure/#use-self-signed-certificates). 73 | E.g. for linux, copy server.crt file to /etc/docker/certs.d/< dns of the public IP created >:5000/server.crt 74 | 75 | ## C. Deploy a TLS enabled registry with a CA certificate 76 | This is the secure way to deploy a TLS enabled registry in production. Similar to self-signed certification solution, without the last step on each client to access the registry. 77 | 78 | 79 | -------------------------------------------------------------------------------- /private-docker-registry/README_CN.md: -------------------------------------------------------------------------------- 1 | # 基于Azure的容器私有仓库 2 | 使用ARM模板在中国区Azure上部署容器私有仓库(Docker Private Registry)。***这个模板只适用于中国区Azure*** 3 | 4 | ## 概述 5 | 6 | 运行模板会在Azure中使用Swarm模式搭建一个简单的容器仓库集群。使用的Azure资源和架构如下: 7 | 8 | ![arch](images/1.png) 9 | 10 | 默认2个虚拟机节点,节点数可以在部署时在azuredeploy.parameters.json中更改。 11 | 12 | ## 前期准备 13 | * 中国区Azure订阅 14 | * Linux开发机,并安装[Azure CLI 2.0](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) 15 | * 使用Azure CLI登陆Azure订阅 16 | ``` 17 | $ az cloud set -n AzureChinaCloud 18 | $ az login -u 19 | ``` 20 | * 将代码下载到开发机上 21 | ``` 22 | $ mkdir -p /path/to/project 23 | $ cd /path/to/project 24 | $ git clone https://github.com/Azure/devops-sample-solution-for-azure-china.git 25 | $ cd /path/to/project/devops-sample-solution-for-azure-china/private-docker-registry 26 | ``` 27 | 28 | ## azuredeploy.parameters.json中的参数 29 | | 参数 | 描述 | 默认值 | 30 | |-------------------|----------------------------------------------------|----------------| 31 | | adminUsername | 虚拟机管理员用户名 | azureuser | 32 | | adminPassword | 虚拟机管理员密码 | | 33 | | dnsNameforLBIP | 负载均衡的公有IP的DNS前缀 | myhub01 | 34 | | registryPort | 仓库端口 | 5000 | 35 | | numberOfInstances | 虚拟机实例数量 | 2 | 36 | | vmSize | 虚拟机实例大小 | Standard_D2_v2 | 37 | | sshRSAPublicKey | 虚拟机SSH公钥 | | 38 | 39 | ## A. 部署使用HTTP的仓库 40 | 为了测试需求,可以部署一个使用HTTP的仓库。这种方法是不安全的,因此并不推荐。 41 | 1. 编辑azuredeploy.parameters.json中的参数,运行命令 42 | ``` 43 | $ bash ./deploy-docker-registry.sh -n -l -m mirror.kaiyuanshe.cn 44 | ``` 45 | 2. 部署完成后,在每个需要访问仓库的客户端上,[进行配置](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry) 。 46 | 例如,在Linux客户端上,编辑/etc/docker/daemon.json,添加 47 | ``` 48 | { 49 | "insecure-registries" : [":5000"] 50 | } 51 | ``` 52 | 然后使用`sudo service docker restart`命令重启容器。 53 | 54 | 也可以通过运行一下命令自动修改每个Kubernetes节点上的docker设置: 55 | ``` 56 | $ bash ./config-insecure-registry.sh -r -m -u -k 57 | ``` 58 | 59 | ## B. 用自签名证书部署使用TLS的仓库 60 | 用户可以[用自签名的证书部署使用TLS的仓库](https://docs.docker.com/registry/insecure/#use-self-signed-certificates),这种方法比使用HTTP的仓库更安全,但是同样也只推荐在测试环境中使用。 61 | 1. 参考上面的链接生成自签名的证书,替换掉certs/server.crt和certs/server.key。 62 | 2. 编辑cloud-config-template.yml,将下面行的注释删掉 63 | ``` 64 | - REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt 65 | - REGISTRY_HTTP_TLS_KEY=/certs/server.key 66 | ``` 67 | 3. 编辑azuredeploy.parameters.json中的参数,运行命令 68 | ``` 69 | $ bash ./deploy-docker-registry.sh -n -l -m mirror.kaiyuanshe.cn 70 | ``` 71 | 4. 部署完成后,在每个需要访问仓库的客户端上,[进行配置](https://docs.docker.com/registry/insecure/#use-self-signed-certificates)。 72 | 例如,在Linux客户端上,将server.crt拷贝到/etc/docker/certs.d/< dns of the public IP created >:5000/server.crt 73 | 74 | ## C. 用CA证书部署使用TLS的仓库 75 | 推荐在产品环境中使用这种方法,具体步骤和使用自签名证书类似,但是不需要最后一步客户端的配置。 76 | 77 | 78 | -------------------------------------------------------------------------------- /private-docker-registry/azuredeploy.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "adminUsername": { 3 | "value": "azureuser" 4 | }, 5 | "adminPassword": { 6 | "value": "" 7 | }, 8 | "dnsNameforLBIP": { 9 | "value": "" 10 | }, 11 | "registryPort": { 12 | "value": 5000 13 | }, 14 | "numberOfInstances": { 15 | "value": 2 16 | }, 17 | "vmSize": { 18 | "value": "Standard_D2_v2" 19 | }, 20 | "sshRSAPublicKey": { 21 | "value": "" 22 | } 23 | } -------------------------------------------------------------------------------- /private-docker-registry/certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGXjCCBEagAwIBAgIJAM1eZnLMq8jSMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNV 3 | BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQxNTAzBgNVBAMTLG15aHViMDEuY2hpbmFub3J0aC5jbG91 5 | ZGFwcC5jaGluYWNsb3VkYXBpLmNuMB4XDTE3MDMzMDA2MjQyM1oXDTE4MDMzMDA2 6 | MjQyM1owfDELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV 7 | BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDE1MDMGA1UEAxMsbXlodWIwMS5j 8 | aGluYW5vcnRoLmNsb3VkYXBwLmNoaW5hY2xvdWRhcGkuY24wggIiMA0GCSqGSIb3 9 | DQEBAQUAA4ICDwAwggIKAoICAQC6TbNPosu8v75lFpJdTwlXbnZK1hpNHob/aUHp 10 | zpzfajqfzur8E0lIqWDDmRIKafZYECxY0W6m+J3CBjxpacTEcSftiluTMXRichBM 11 | ryB4iQ5akjpctOqhP2rDG27+L6cetVNXBsfxwtQA1p+YcuSj1w7KPhlLsUUD6fAn 12 | lntz7e7kO9CKZgkig+OJfahEX3CqYiCzJH3rV/nCpRMW3wTTyL1HT74zGPkZ/8Q9 13 | Vopfsif0xuVi/llCUw1W+htde6CFvz/Hni25jBM72V/fmfRPygXh/52S2CuEECjA 14 | WzYqaHp1mfFoeiS6bQXLiPGFwXUTLs0YDghb1o1esS3+afCxNpGpxHDlLDeHvckN 15 | UjYsJ1h1pJLR7uRC7mQHsqbm6cr2+LXMa2P3CKP/h1XMqoLYUQleoDFg02rLxDNj 16 | PGMz8otNKZ993bVe4nTT9A6B4A+JX795Fm0jj3ZULYLWUIEEmoeZPhuXoIJ+cYZZ 17 | sJFQ+BnmvLnMji2KNVX1WJ1HWiFoay/PN70pHKK4/Zzv+sO4/GmrEeylVPU1clzg 18 | 4HfmXoReYGIrm+5svX7jMFmrXNSM0ijUSvB+VMbTYwBjUTt+kZETlmk8aExNgVgp 19 | DTv4c6rWb+yus79yMiWJI8tV9cSyIUCcLakWbHlPm/dY8ktKI0zeD9oHfq4njiYj 20 | CzqczQIDAQABo4HiMIHfMB0GA1UdDgQWBBShE7COAClegxJhLyUk4+dVYWghdDCB 21 | rwYDVR0jBIGnMIGkgBShE7COAClegxJhLyUk4+dVYWghdKGBgKR+MHwxCzAJBgNV 22 | BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX 23 | aWRnaXRzIFB0eSBMdGQxNTAzBgNVBAMTLG15aHViMDEuY2hpbmFub3J0aC5jbG91 24 | ZGFwcC5jaGluYWNsb3VkYXBpLmNuggkAzV5mcsyryNIwDAYDVR0TBAUwAwEB/zAN 25 | BgkqhkiG9w0BAQsFAAOCAgEANMfcU3pJNzI+luxSaYVTns8f5CWArzpg4MzRWgh9 26 | eQv4Pgbo++s7s+A6cUuGbOqxeqQ2aP6rlUMZpu82/Wi+ZLIG/uxp6XxMiPGTTly7 27 | wIL7hhuuG8e5U1cvqP9e9MQtfGAW/Ip6Hj3DIma87RPgza4+pp6qwDwtolXkeUUX 28 | E2iS/5eySYf6uB269tleWV5CAoEOz+MlYcEtNsqIdYgSiHO3ZZOsLIhDt5yvY4Ax 29 | sNOo/5xFibdOqSbXD7/KeezoVts0WbMOUsLyNl9WRmnqanKeRDdFSCosT/jb4eD4 30 | pSJOY+qYNdidmPhAFMrQtjbqAcghxSLzA6Z8bh0hj0v7G9crCyhCiEdqUK7c+jZ9 31 | QVOVWFo/7Rx3K/zgpYW3l3SRzXeNgrQo4PNICJzvLlFOmIIDtDw2hgv26FU8LB2M 32 | 72YVaDNEXKBz7gcXS9WaCmxUrUsEi91LMPMbfSduaL2N7Xco2mhFyV/3xp0ZQg5B 33 | pczdz5D0fCjZr4YMoU8HsKNrpBy/5JrWjdiIfXj7KwGSVh7YiWv5S7jSq3Ud+Tv5 34 | bGvH1sh45Rm/3ckJ831fSjKc8YSoTjJAPVtmOSMU2h3BvtcJyCM5W8Gn6ZkplAZC 35 | vcUOOe2xfOQ9fASMTxJTO2RCbudDZS+5zyk7GIVfl53eGGVVefeZI0oblZEhtYzv 36 | ryc= 37 | -----END CERTIFICATE----- 38 | -------------------------------------------------------------------------------- /private-docker-registry/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKAIBAAKCAgEAuk2zT6LLvL++ZRaSXU8JV252StYaTR6G/2lB6c6c32o6n87q 3 | /BNJSKlgw5kSCmn2WBAsWNFupvidwgY8aWnExHEn7YpbkzF0YnIQTK8geIkOWpI6 4 | XLTqoT9qwxtu/i+nHrVTVwbH8cLUANafmHLko9cOyj4ZS7FFA+nwJ5Z7c+3u5DvQ 5 | imYJIoPjiX2oRF9wqmIgsyR961f5wqUTFt8E08i9R0++Mxj5Gf/EPVaKX7In9Mbl 6 | Yv5ZQlMNVvobXXughb8/x54tuYwTO9lf35n0T8oF4f+dktgrhBAowFs2Kmh6dZnx 7 | aHokum0Fy4jxhcF1Ey7NGA4IW9aNXrEt/mnwsTaRqcRw5Sw3h73JDVI2LCdYdaSS 8 | 0e7kQu5kB7Km5unK9vi1zGtj9wij/4dVzKqC2FEJXqAxYNNqy8QzYzxjM/KLTSmf 9 | fd21XuJ00/QOgeAPiV+/eRZtI492VC2C1lCBBJqHmT4bl6CCfnGGWbCRUPgZ5ry5 10 | zI4tijVV9VidR1ohaGsvzze9KRyiuP2c7/rDuPxpqxHspVT1NXJc4OB35l6EXmBi 11 | K5vubL1+4zBZq1zUjNIo1ErwflTG02MAY1E7fpGRE5ZpPGhMTYFYKQ07+HOq1m/s 12 | rrO/cjIliSPLVfXEsiFAnC2pFmx5T5v3WPJLSiNM3g/aB36uJ44mIws6nM0CAwEA 13 | AQKCAgBGZ9zOyKgUIaZTT49qodbW6tDbgUQZRuMfnOii8kkIiX20LR9Sufsk8ZW2 14 | 9Z8Cvn6xUxNfUW5uvV/pFjA4ahdJYbYEKBhpbPQdzBtqz3gG9UyuX7qclGZjH7M6 15 | HqD4gIu4qC/hoJdpPwaddn6Dv0+2tyxIs+UdXNXHH955J35qFk4EhLJPyzXCjHMt 16 | 34X6qNLMIR9Yc/7+NJYXwAiRySBq5N7bF0C60MI62BSSVaUfexVshMnlelfDH93X 17 | s9cpofHM+bShvJ5tE4mlQYXg266fhKpqeQ5Uk0sGspCj+RRkPG2jCdVYdWhx54ec 18 | Hpmfwbd702EAqTTxeAie83h9QA4MVJCx/YgU5DDRsAgVzG/ZEohP48xdK4R6AaZV 19 | zc7lXcetJQQAcyWr+xrQLQNjU3Dvz3ZcEMh3tKcHGnVv8vrxsuE91G9Hz3hdIvj3 20 | gw6GXSrgN7S1FTE29egElOP6i3/1mCZrVsR/3Hq8LV2z9CPnAbWXDSxGk8WyTMmO 21 | apeD2PrRYQKnvnqO5avIo4IopZHly4AfTIH3cUURXmvYGUKI8ssAabrjeokL5+q/ 22 | qUQ4g/Mnm/9ClvXX1BcKgYCRqQSdbFuuNm8jWIRa1UPw907VgsqICBuU3yoYadKw 23 | MRhAm9tRD8VCgJOPiY2deeDR9pE01y2Ile5bX+eWw01U2UIXoQKCAQEA89Pl3sr1 24 | pIKcV0/CctoVviDv5wNfDp/gUKWgfQ1Fn/wRKaXBgrwFfB8+0U1VwYvjJhME96DW 25 | XEsnANTHEU2i6DAyPZxs1E5uuB3Vz5VGfTX2A4iePAJDpvY3k8KOth2hw1ioJ/+p 26 | qcucVLfCrDJ82YoA5NmxtPdLFs6dz/zSC4FD2bGYtmVQwwD/6z2hS3cL9hI3CZON 27 | v3Zf5abvjc3XQVzUxY3/pxAuaeiyXGjoLwblXlskdEV0pgrbp4cP2Fk2/TJRGGpr 28 | Pkjp0+dU3GQyYd5sV3mR7cwkiA/GMqNGMq8ksS8Ef6MqT/SWPaKJFFqVIKGxo8uM 29 | Nh1Z8NEzpn36+QKCAQEAw5qlnp28DWZdWX5j2Zsk7fuuVyfZFTvyAscknGNCVO39 30 | e3NWxqXygzKDlXJ1yP3evoMAab7FL088D7fusxnmm0BQ/qBnWQLAitwEMGFxl9I2 31 | UR0j6VRphmC5vq1RgBZefOKPv0Z1AhapzJPdquPoSiJIkWtpBY1MZX010KatGPkd 32 | QydRYNpZCP2unmPvukgKmxe4s2FvHrR7xgYDS/W1YXpm21hXGziJgMfcdmslmYgy 33 | 0Mpc4x5x925YlAJP0+cfbvuJDU4Ws0B5NkaFFZE9jRRbbpYZ4bbRy2srpBgyx8m5 34 | 2iMJk9nTim73PzyN4tkoHKPWUMzdBWktVyryh5dxdQKCAQARjKXV5EvL3G6+Rgpb 35 | 0+COv7YkrXRxDAbMJy+m8IabXjwqADkuXLQUW/dcfzF17ciam/HWlOf42pvjDm2J 36 | jEn2Zkmnb5PRsBd9/v+9oiPhrTmYxYOGFC+kW8JiSzWUXAuhkMcBogAnLXWCD3ve 37 | gv/DdJBd6GFHAimQaayoJK1FkLc+eu7f6ejnMDI7T0NFuDrPKj513P3t0upSEDLb 38 | xP4CQVk7It5MuvhsPQhhaFeV0uw9X1f/WmRr8woeQ7VbQAiaLr3xgO9ZG0xhKRxN 39 | hJSvwJ+RqDldoTzb4i7ExEWwLjT438Z2HVtVR+hsZT9yjJaBM8IiZOshlfk8QQJz 40 | sEuZAoIBAGXJvBXmj02Jz1oa42sByR3usrK4EcdzAmVfrDWVkZcQoa/0PVvyT1jm 41 | mILUpWaKdbc+BKECnSoZWW/0j0q0V8TCm2NlpWI0hG2+QI/MpYgT5CAhweZR/vfm 42 | rcID/z1gZpsmaxdmWs1Tbdj/uYKMRv0NCiZidqxk8zR9C9wgYEN2nzuq4jY8aci7 43 | +nqCFuYhRyOeHId8VI7t7NsHlf+ZRWIMiCnstqd7rFJPrvIQn+hdb9Qm+l9WIIhZ 44 | 685ZxaDHzRu72X4K/NUa3/jWibrHcfhQd6P8iEtlD5eDlZo23XYKC6TwRrOhzutj 45 | A1bs9AjwaGc++u/hK8L9EJMjzkGxFWECggEBAKXpkpZpqx0qD0GXF7k+rTjEo+tc 46 | vx+Yetgq4ABLyPWen5arcODGum+MWjxy047zXsCmX5c6yCdOTKXRIorpmK5wzzj1 47 | 9nsNEi8+1Gl6ePa2Onmv2EMwHAoM6+5ShQmhWB67QUJlDjabeVpOqug2gT/WpYpt 48 | hQBg58fdzQ2j67h8E8xq2u0TG6Ay7EMhRaNmyNvx+uAwtrZGEOiN3sPQX9yTszSH 49 | Y9RmxEpGb4OUxjLX4ECQHjL3WI9zcAa0Cu5PilsPBAIn5M9lpxhQ4iVEbPfn7tHl 50 | hTvmmDOD0wWxhSfT74TKzOdB6Bbogs3JmhJPh9x0FoogUn5PeHdLaGP6ACE= 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /private-docker-registry/config-insecure-registry-in-master.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | 3 | function main() { 4 | sudo apt-get -q -y install jq moreutils 5 | 6 | daemon_file="/etc/docker/daemon.json" 7 | 8 | echo "original daemon file:" 9 | cat $daemon_file 10 | 11 | sudo cat "$daemon_file" | jq '."insecure-registries"[0]="{{{REG_FQDN}}}:{{{REG_PORT}}}"' | sudo sponge "$daemon_file" 12 | sudo service docker restart 13 | 14 | echo "updated daemon file:" 15 | cat $daemon_file 16 | 17 | local_name=`hostname` 18 | temp_daemon_file="/tmp/daemon.json" 19 | for node_name in `kubectl get nodes -o=jsonpath={.items[*].metadata.name}` 20 | do 21 | if [ "$local_name" != "$node_name" ] ; then 22 | sudo scp -i "{{{ID_RSA_FILE}}}" -oStrictHostKeyChecking=no "$daemon_file" {{{K8S_USER}}}@$node_name:$temp_daemon_file 23 | ssh -i "{{{ID_RSA_FILE}}}" -oStrictHostKeyChecking=no {{{K8S_USER}}}@$node_name sudo mv $temp_daemon_file "$daemon_file" 24 | ssh -i "{{{ID_RSA_FILE}}}" -oStrictHostKeyChecking=no {{{K8S_USER}}}@$node_name sudo service docker restart 25 | 26 | echo "copy daemon file to node '$node_name'" 27 | fi 28 | done 29 | } 30 | 31 | main 2>&1 | sudo tee -a "{{{LOG_IN_MASTER}}}" -------------------------------------------------------------------------------- /private-docker-registry/config-insecure-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | 3 | usage(){ 4 | echo "Invalid option: -$OPTARG" 5 | echo "Usage: config-insecure-registry -r [Registry fqdn]" 6 | echo " -p [Registry port, default value: 5000]" 7 | echo " -m [k8s master node fqdn]" 8 | echo " -u [user name for SSH to k8s nodes]" 9 | echo " -k [id_rsa file for SSH to k8s nodes]" 10 | exit 1 11 | } 12 | 13 | while getopts ":r:p:m:k:u:" opt; do 14 | case $opt in 15 | r)REG_FQDN=$OPTARG;; 16 | p)REG_PORT=$OPTARG;; 17 | m)K8S_MASTER=$OPTARG;; 18 | u)K8S_USER=$OPTARG;; 19 | k)ID_RSA_FILE=$OPTARG;; 20 | *)usage;; 21 | esac 22 | done 23 | 24 | function upload_to_master() { 25 | src_path=$1 26 | dest_path=$2 27 | 28 | sudo scp -i "$ID_RSA_FILE" -oStrictHostKeyChecking=no "$src_path" $K8S_USER@$K8S_MASTER:$dest_path 29 | } 30 | 31 | function download_from_master() { 32 | src_path=$1 33 | dest_path=$2 34 | 35 | sudo scp -i "$ID_RSA_FILE" -oStrictHostKeyChecking=no $K8S_USER@$K8S_MASTER:$src_path "$dest_path" 36 | } 37 | 38 | function run_in_master() { 39 | cmd="$*" 40 | 41 | ssh -i "$ID_RSA_FILE" -oStrictHostKeyChecking=no $K8S_USER@$K8S_MASTER $cmd 42 | } 43 | 44 | function main() { 45 | log_in_master="/var/log/config-insecure-reg.log" 46 | 47 | id_rsa_in_master="/tmp/k8s_id_rsa" 48 | upload_to_master $ID_RSA_FILE $id_rsa_in_master 49 | run_in_master sudo chmod 400 $id_rsa_in_master 50 | run_in_master sudo chown $K8S_USER:$K8S_USER $id_rsa_in_master 51 | echo "uploaded id_rsa file from '$ID_RSA_FILE' to '$id_rsa_in_master' in master" 52 | 53 | temp_script="config-insecure-reg.sh" 54 | cp "config-insecure-registry-in-master.sh" $temp_script 55 | sed -i "s/{{{REG_FQDN}}}/$REG_FQDN/" $temp_script 56 | sed -i "s/{{{REG_PORT}}}/${REG_PORT:-5000}/" $temp_script 57 | sed -i "s/{{{K8S_USER}}}/$K8S_USER/" $temp_script 58 | sed -i "s|{{{ID_RSA_FILE}}}|$id_rsa_in_master|" $temp_script 59 | sed -i "s|{{{LOG_IN_MASTER}}}|$log_in_master|" $temp_script 60 | 61 | temp_script_in_master="/tmp/$temp_script" 62 | upload_to_master $temp_script $temp_script_in_master 63 | echo "uploaded script to '$temp_script_in_master' in master" 64 | echo "script content:" 65 | cat $temp_script 66 | 67 | rm -f $temp_script 68 | 69 | echo "running script '$temp_script_in_master' in master" 70 | run_in_master bash $temp_script_in_master 71 | 72 | echo "downloading log in master from '$log_in_master'" 73 | master_log="config-insecure-registry-in-master.log" 74 | download_from_master $log_in_master $master_log 75 | 76 | echo "cleaning up in master" 77 | run_in_master sudo rm -f $id_rsa_in_master 78 | run_in_master sudo rm -f $temp_script_in_master 79 | 80 | echo "config insecure registry done." 81 | } 82 | 83 | main 2>&1 | tee -a config-insecure-registry.log -------------------------------------------------------------------------------- /private-docker-registry/deploy-docker-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage(){ 4 | echo "Invalid option: -$OPTARG" 5 | echo "Usage: deploy-docker-registry -n [Resource group name]" 6 | echo " -l [Resource group location]" 7 | echo " -m [Azure mirror site]" 8 | exit 1 9 | } 10 | 11 | while getopts ":n:l:m:" opt; do 12 | case $opt in 13 | n)GROUP_NAME=$OPTARG;; 14 | l)LOCATION=$OPTARG;; 15 | m)MIRROR=$OPTARG;; 16 | *)usage;; 17 | esac 18 | done 19 | 20 | if [ -z $GROUP_NAME ] || [ -z $LOCATION ]; then 21 | usage 22 | exit 1 23 | fi 24 | 25 | if [ -z $MIRROR ] ; then 26 | MIRROR="mirror.kaiyuanshe.cn" 27 | fi 28 | 29 | ARMTEMPLATE="azuredeploy-template.json" 30 | TEMPLATE="azuredeploy.json" 31 | PARAMETERS="azuredeploy.parameters.json" 32 | CLOUDINIT="cloud-config-template.yml" 33 | CERTFILE="./certs/server.crt" 34 | KEYFILE="./certs/server.key" 35 | 36 | CERTFILECONTENT=`cat "$CERTFILE"|base64 -w 0` 37 | KEYFILECONTENT=`cat "$KEYFILE"|base64 -w 0` 38 | 39 | cp -f $ARMTEMPLATE $TEMPLATE 40 | cp -f $CLOUDINIT cloud-config.yml 41 | sed -i "s|{{{serverCertificate}}}|$CERTFILECONTENT|g; s|{{{serverKey}}}|$KEYFILECONTENT|g;" cloud-config.yml 42 | sed -i "s|{{{azureMirror}}}|$MIRROR|g;" cloud-config.yml 43 | 44 | sed -i 's/\r$//' cloud-config.yml 45 | sed -i 's/\\/\\\\/g' cloud-config.yml 46 | sed -i ':a;N;$!ba;s/\n/\\n/g' cloud-config.yml 47 | sed -i 's/\\n/\\\\n/g' cloud-config.yml 48 | sed -i 's/"/\\"/g' cloud-config.yml 49 | sed -i "s/<<<\([^>]*\)>>>/',\1,'/g" cloud-config.yml 50 | 51 | INITCONTENT=$(cat cloud-config.yml) 52 | echo "[base64(concat('$INITCONTENT'))]" > updatepattern.txt 53 | sed -i "s/<<<[^>]*>>>/$(sed 's:/:\\/:g; s:&:\\&:g; s:\\\":\\\\\":g;' updatepattern.txt)/g" $TEMPLATE 54 | 55 | if type az >/dev/null 2>&1 ; then 56 | echo "azure cli 2.0 already installed" 57 | 58 | az group create --name "$GROUP_NAME" --location "$LOCATION" 59 | az group deployment create -g "$GROUP_NAME" --template-file $TEMPLATE --parameters $PARAMETERS 60 | else 61 | echo "azure cli 2.0 not found, installing..." 62 | 63 | echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ wheezy main" | sudo tee /etc/apt/sources.list.d/azure-cli.list 64 | sudo apt-key adv --keyserver packages.microsoft.com --recv-keys 417A0893 65 | sudo apt-get install -q -y apt-transport-https 66 | sudo apt-get update 67 | sudo apt-get install -q -y azure-cli 68 | 69 | echo "please az login first, then re-run this script" 70 | fi 71 | 72 | rm $TEMPLATE 73 | rm cloud-config.yml 74 | rm updatepattern.txt -------------------------------------------------------------------------------- /private-docker-registry/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/container-service-for-azure-china/122b8049a59ee620f61a1abc63ad566a607ac769/private-docker-registry/images/1.png -------------------------------------------------------------------------------- /resources/kured-1.1.0.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: kured 6 | rules: 7 | # Allow kured to read spec.unschedulable 8 | # Allow kubectl to drain/uncordon 9 | # 10 | # NB: These permissions are tightly coupled to the bundled version of kubectl; the ones below 11 | # match https://github.com/kubernetes/kubernetes/blob/v1.12.1/pkg/kubectl/cmd/drain.go 12 | # 13 | - apiGroups: [""] 14 | resources: ["nodes"] 15 | verbs: ["get", "patch"] 16 | - apiGroups: [""] 17 | resources: ["pods"] 18 | verbs: ["list","delete","get"] 19 | - apiGroups: ["extensions"] 20 | resources: ["daemonsets"] 21 | verbs: ["get"] 22 | - apiGroups: [""] 23 | resources: ["pods/eviction"] 24 | verbs: ["create"] 25 | --- 26 | apiVersion: rbac.authorization.k8s.io/v1 27 | kind: ClusterRoleBinding 28 | metadata: 29 | name: kured 30 | roleRef: 31 | apiGroup: rbac.authorization.k8s.io 32 | kind: ClusterRole 33 | name: kured 34 | subjects: 35 | - kind: ServiceAccount 36 | name: kured 37 | namespace: kube-system 38 | --- 39 | apiVersion: rbac.authorization.k8s.io/v1 40 | kind: Role 41 | metadata: 42 | namespace: kube-system 43 | name: kured 44 | rules: 45 | # Allow kured to lock/unlock itself 46 | - apiGroups: ["extensions"] 47 | resources: ["daemonsets"] 48 | resourceNames: ["kured"] 49 | verbs: ["update"] 50 | --- 51 | apiVersion: rbac.authorization.k8s.io/v1 52 | kind: RoleBinding 53 | metadata: 54 | namespace: kube-system 55 | name: kured 56 | subjects: 57 | - kind: ServiceAccount 58 | namespace: kube-system 59 | name: kured 60 | roleRef: 61 | apiGroup: rbac.authorization.k8s.io 62 | kind: Role 63 | name: kured 64 | --- 65 | apiVersion: v1 66 | kind: ServiceAccount 67 | metadata: 68 | name: kured 69 | namespace: kube-system 70 | --- 71 | apiVersion: apps/v1 72 | kind: DaemonSet 73 | metadata: 74 | name: kured # Must match `--ds-name` 75 | namespace: kube-system # Must match `--ds-namespace` 76 | spec: 77 | selector: 78 | matchLabels: 79 | name: kured 80 | updateStrategy: 81 | type: RollingUpdate 82 | template: 83 | metadata: 84 | labels: 85 | name: kured 86 | spec: 87 | serviceAccountName: kured 88 | tolerations: 89 | - key: node-role.kubernetes.io/master 90 | effect: NoSchedule 91 | hostPID: true # Facilitate entering the host mount namespace via init 92 | restartPolicy: Always 93 | containers: 94 | - name: kured 95 | image: dockerhub.azk8s.cn/weaveworks/kured:1.1.0 96 | imagePullPolicy: IfNotPresent 97 | securityContext: 98 | privileged: true # Give permission to nsenter /proc/1/ns/mnt 99 | env: 100 | # Pass in the name of the node on which this pod is scheduled 101 | # for use with drain/uncordon operations and lock acquisition 102 | - name: KURED_NODE_ID 103 | valueFrom: 104 | fieldRef: 105 | fieldPath: spec.nodeName 106 | command: 107 | - /usr/bin/kured 108 | # - --alert-filter-regexp=^RebootRequired$ 109 | # - --ds-name=kured 110 | # - --ds-namespace=kube-system 111 | # - --lock-annotation=weave.works/kured-node-lock 112 | # - --period=1h 113 | # - --prometheus-url=http://prometheus.monitoring.svc.cluster.local 114 | # - --reboot-sentinel=/var/run/reboot-required 115 | # - --slack-hook-url=https://hooks.slack.com/... 116 | # - --slack-username=prod 117 | --------------------------------------------------------------------------------