[
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "*Issue #, if available:*\n\n*Description of changes:*\n\n\nBy submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nchina/.DS_Store\nglobal/.DS_Store\nresource/china/ecsdemo-crystal\nresource/china/ecsdemo-frontend\nresource/china/ecsdemo-nodejs\nresource/china/s3-echoer\nresource/china/hpa/metrics-server-v0.3.6.tar.gz\nresource/china/hpa/metrics-server-v0.3.6/*"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "## Code of Conduct\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).\nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact\nopensource-codeofconduct@amazon.com with any additional questions or comments.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nThank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional\ndocumentation, we greatly value feedback and contributions from our community.\n\nPlease read through this document before submitting any issues or pull requests to ensure we have all the necessary\ninformation to effectively respond to your bug report or contribution.\n\n\n## Reporting Bugs/Feature Requests\n\nWe welcome you to use the GitHub issue tracker to report bugs or suggest features.\n\nWhen filing an issue, please check [existing open](https://github.com/aws-samples/eks-workshop-greater-china/issues), or [recently closed](https://github.com/aws-samples/eks-workshop-greater-china/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already\nreported the issue. Please try to include as much information as you can. Details like these are incredibly useful:\n\n* A reproducible test case or series of steps\n* The version of our code being used\n* Any modifications you've made relevant to the bug\n* Anything unusual about your environment or deployment\n\n\n## Contributing via Pull Requests\nContributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:\n\n1. You are working against the latest source on the *master* branch.\n2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.\n3. You open an issue to discuss any significant work - we would hate for your time to be wasted.\n\nTo send us a pull request, please:\n\n1. Fork the repository.\n2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.\n3. Ensure local tests pass.\n4. Commit to your fork using clear commit messages.\n5. Send us a pull request, answering any default questions in the pull request interface.\n6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.\n\nGitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and\n[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).\n\n\n## Finding contributions to work on\nLooking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws-samples/eks-workshop-greater-china/labels/help%20wanted) issues is a great place to start.\n\n\n## Code of Conduct\nThis project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).\nFor more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact\nopensource-codeofconduct@amazon.com with any additional questions or comments.\n\n\n## Security issue notifications\nIf you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.\n\n\n## Licensing\n\nSee the [LICENSE](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.\n\nWe may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "## AWS GCR EKS Resource \n\n\n\n[AWS EKS集群使用Karpenter实现EC2工作节点弹性伸缩](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/karpenter_handson/%E4%BD%BF%E7%94%A8Karpenter%E5%AE%9E%E7%8E%B0EKS%E5%B7%A5%E4%BD%9C%E8%8A%82%E7%82%B9%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9.md)\n\n[Kubernetes 节点弹性伸缩开源组件 Karpenter 实践：部署GPU推理应用](https://aws.amazon.com/cn/blogs/china/kubernetes-node-elastic-scaling-open-source-component-karpenter-practice-deploying-gpu-inference-applications/)\n\n[Kubernetes 节点弹性伸缩开源组件 Karpenter 实践：使用 Spot 实例进行成本优化](https://aws.amazon.com/cn/blogs/china/kubernetes-node-elastic-scaling-open-source-component-karpenter-practice-cost-optimization-using-spot-instance/)\n\n[Unreal Engine 像素流送在g4dn上实现容器化部署实践(二)](https://aws.amazon.com/cn/blogs/china/practice-of-container-deployment-of-unreal-engine-pixel-streaming-on-g4dn-ii/)\n\n\n\n\n\n#### China Region  Workshop Resource\n\n***\n#### Tech Day 资料:\n\n[AWS GCR 2020 EKS Launch Hands-on Workshop](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/README.md)\n\n\n1. [步骤1-准备实验环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤1-准备实验环境.md)\n2. [步骤2-创建EKS集群](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤2-创建EKS集群.md)\n3. [步骤3-部署官方的KubernetesDashboard](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤3-部署官方的KubernetesDashboard.md)\n4. [步骤4-部署微服务以及配置ALBIngressController](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤4-部署微服务以及配置ALBIngressController.md) \n5. [步骤5-配置使用EBS](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤5-配置使用EBS.md)\n6. [步骤6-配置使用EFS](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤6-配置使用EFS.md)\n7. [步骤7-在EKS中使用IAMRole进行权限管理](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤7-在EKS中使用IAMRole进行权限管理.md)\n8. [步骤8-对应用Pod和集群进行自动扩展](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤8-对应用Pod和集群进行自动扩展.md)\n9. [步骤9-使用Helm部署应用](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤9-使用Helm部署应用.md)\n10. [步骤10-可用性-健康检查](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤10-可用性-健康检查.md)\n11. [步骤11-使用Calio加固EKS集群安全](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤11-使用Calio加固EKS集群安全.md)\n12. [步骤12 使用EFK收集、处理日志](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤12-EFK日志收集.md)\n13. [步骤13 部署Prometheus & Grafana监控](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤13-Prometheus&Grafana监控.md)\n14. [步骤14 在EKS集群上部署Istio 服务网格](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤14-在EKS集群上部署Istio服务网格.md)\n\n\n\n[2020_GCR_Kuberflow_Workshop](https://github.com/aws-samples/eks-workshop-greater-china/tree/master/china/2020_GCR_Kubeflow_Workshop)\n\n1. [安装kubeflow](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_GCR_Kubeflow_Workshop/%E5%AE%89%E8%A3%85Kubeflow.md)\n2. [创建和使用jupter笔记本.md](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_GCR_Kubeflow_Workshop/%E5%88%9B%E5%BB%BA%E5%92%8C%E4%BD%BF%E7%94%A8jupter%E7%AC%94%E8%AE%B0%E6%9C%AC.md)\n3. [使用Kubeflow fairing](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_GCR_Kubeflow_Workshop/Kubeflow_fairing.md)\n4. [使用Kubeflow pipeline](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_GCR_Kubeflow_Workshop/Kubeflow_Pipelines.md)\n\n\n\n#### Global Region Workshop Resource \n***\n\n\n\n#### Tech Day 资料:\n\n[AWS 2021 Modern Application Development(MAD) Day](https://github.com/aws-samples/eks-workshop-greater-china/tree/master/global/2021_GCR_MAD_Day)\n\n[通过Cloud9搭建准备实验环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/%E9%80%9A%E8%BF%87AWS%20Cloud9%E6%90%AD%E5%BB%BA%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83.md)\n\nLab1  Serverless\n\n1. [步骤1-从头开始写一个 serverless API](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A41-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n2. [步骤2-使用serverless 快速构建Express应用](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab1-serverless/%E6%AD%A5%E9%AA%A41-%E4%BD%BF%E7%94%A8serverless%20%E5%BF%AB%E9%80%9F%E6%9E%84%E5%BB%BAExpress%E5%BA%94%E7%94%A8.md)\n\nLab2 EKS 动手训练营\n\n1.  [步骤1-设置默认region, 安装eksctl, kubectl工具](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A41-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n2.  [步骤2,  创建EKS集群](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A42-%E5%88%9B%E5%BB%BAEKS%E9%9B%86%E7%BE%A4.md)\n3.  [步骤3, 配置aws-load-balancer-controller&部署2048游戏](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A43-%E9%83%A8%E7%BD%B2%E9%85%8D%E7%BD%AEaws-load-balancer-controller%262048%E6%B8%B8%E6%88%8F.md)\n4.  [步骤4-可观测性-日志收集](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A44-%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7-%E6%97%A5%E5%BF%97%E6%94%B6%E9%9B%86.md)\n5.  [步骤5-可观测性-prometheus-grafana.md](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A45-%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7-prometheus-grafana.md)\n6.  [步骤6-使用CodePipeline 实现EKS环境CICD.md](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A46-%E4%BD%BF%E7%94%A8CodePipeline%20%E5%AE%9E%E7%8E%B0EKS%E7%8E%AF%E5%A2%83CICD.md)\n7.  [步骤7 使用Karpenter实现EKS工作节点弹性伸缩](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A47-%E4%BD%BF%E7%94%A8Karpenter%E5%AE%9E%E7%8E%B0EKS%E5%B7%A5%E4%BD%9C%E8%8A%82%E7%82%B9%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9.md)\n\n\n\n[AWS GCR 2020  Container Day](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/README.md)\n\n1.  [步骤1 , 通过Cloud9搭建准备实验环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A41-%E9%80%9A%E8%BF%87AWS%20Cloud9%E6%90%AD%E5%BB%BA%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%8E%AF%E5%A2%83.md)\n\n2.  [步骤2,  安装eksctl, kubectl , jq等工具](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A42-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n\n3.   [步骤3,  创建EKS集群](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A43-%E5%88%9B%E5%BB%BAEKS%E9%9B%86%E7%BE%A4.md)\n\n4.  [步骤4, 使用ALB Ingress](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A44-%E9%85%8D%E7%BD%AEALBIngressController.md)\n\n5.  [步骤5,使用Kubernetes Dashboard](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A45-%E9%83%A8%E7%BD%B2%E5%AE%98%E6%96%B9%E7%9A%84KubernetesDashboard.md)\n\n6.  [步骤6,使用EBS存储](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A46-%E4%BD%BF%E7%94%A8EBS%E5%AD%98%E5%82%A8.md)\n\n7.  [步骤7, IRSA(可选)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A47-%E5%9C%A8EKS%E4%B8%AD%E4%BD%BF%E7%94%A8IAMRole%E8%BF%9B%E8%A1%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86.md)\n\n8.  [步骤8, 实现应用Pod和集群进行自动扩展（可选)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A48-%E5%AE%9E%E7%8E%B0%E5%BA%94%E7%94%A8Pod%E5%92%8C%E9%9B%86%E7%BE%A4%E8%BF%9B%E8%A1%8C%E8%87%AA%E5%8A%A8%E6%89%A9%E5%B1%95.md)\n\n  \n\n[AWS GCR 2019 EKS New Feature Workshop](https://github.com/aws-samples/eks-workshop-greater-china/tree/master/global/2019_GCR_EKS_Workshop)\n\n1. [步骤1: 通过AWSCloud9搭建服务器环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2019_GCR_EKS_Workshop/%E6%AD%A5%E9%AA%A41-%E9%80%9A%E8%BF%87AWS%20Cloud9%E6%90%AD%E5%BB%BA%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%8E%AF%E5%A2%83.md)\n2. [步骤2: 设置默认region, 安装eksctl,kubectl工具](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2019_GCR_EKS_Workshop/%E6%AD%A5%E9%AA%A42-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n3. [步骤3: 创建EKS集群(启用按需实例和Fargate)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2019_GCR_EKS_Workshop/%E6%AD%A5%E9%AA%A43-%E5%88%9B%E5%BB%BAEKS%E9%9B%86%E7%BE%A4(%E5%90%AF%E7%94%A8%E6%8C%89%E9%9C%80%E5%AE%9E%E4%BE%8B%E5%92%8CFargate).md)\n4. [步骤4: 部署示例应用，通过HPA测试Fargate弹性伸缩功能](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2019_GCR_EKS_Workshop/%E6%AD%A5%E9%AA%A44-%E9%83%A8%E7%BD%B2%E7%A4%BA%E4%BE%8B%E5%BA%94%E7%94%A8%EF%BC%8C%E9%80%9A%E8%BF%87HPA%E6%B5%8B%E8%AF%95Fargate%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9%E5%8A%9F%E8%83%BD.md)\n5. [步骤5: 在EKS中使用IAM Role进行权限管理](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2019_GCR_EKS_Workshop/%E6%AD%A5%E9%AA%A45-%E5%9C%A8EKS%E4%B8%AD%E4%BD%BF%E7%94%A8IAM%20Role%E8%BF%9B%E8%A1%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86(%E5%8F%AF%E9%80%89).md)\n\n## Other Resource\n- [Amazon EKS 入门](https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/getting-started.html)\n- [eksworkshop.com](https://eksworkshop.com/)\n- [eksctl doc](https://eksctl.io/)\n\n## License Summary\n\nThis sample code is made available under the MIT-0 license. See the LICENSE file.\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/README.md",
    "content": "# AWS EKS China Region Launch Hands-on Workshop \n* 概要\n    在本练习中，您将学习如何使用创建、管理AWS EKS平台，并学会如何在EKS中创建集群并使用使用托管节点组/非托管节点组，在实验中我们还会学习到如何Kubernets 如何与Amazon IAM一起进行权限管理, 如何使用Horizental Pod Autoscaler (HPA)进行Pod的自动扩展，等等常见EKS操作。\n    \n\n 在此教程中，您将完成以下实验：\n  * [步骤1-准备实验环境](步骤1-准备实验环境.md)\n\n  * [步骤2-创建EKS集群](步骤2-创建EKS集群.md)\n\n  * [步骤3-部署官方的KubernetesDashboard](步骤3-部署官方的KubernetesDashboard.md)\n\n  * [步骤4-部署微服务以及配置ALBIngressController](步骤4-部署微服务以及配置ALBIngressController.md) \n\n  * [步骤5-配置使用EBS](步骤5-配置使用EBS.md)\n\n  * [步骤6-配置使用EFS](步骤6-配置使用EFS.md)\n\n  * [步骤7-在EKS中使用IAMRole进行权限管理](步骤7-在EKS中使用IAMRole进行权限管理.md)\n\n  * [步骤8-对应用Pod和集群进行自动扩展](步骤8-对应用Pod和集群进行自动扩展.md)\n\n  * [步骤9-使用Helm部署应用](步骤9-使用Helm部署应用.md)\n\n  * [步骤10-可用性-健康检查](步骤10-可用性-健康检查.md)\n\n  * [步骤11-使用Calio加固EKS集群安全](步骤11-使用Calio加固EKS集群安全.md)\n  \n  * [步骤12 使用EFK收集、处理日志](步骤12-EFK日志收集.md)\n  \n  * [步骤13 部署Prometheus & Grafana监控](步骤13-Prometheus&Grafana监控.md)  \n  \n  * [步骤14 在EKS集群上部署Istio 服务网格](步骤14-在EKS集群上部署Istio服务网格.md)\n  \n    \n    \n    本实验使用宁夏ZHY(cn-northwest-1)Region\n    \n    本文所需要的资源均在 china/2020_EKS_Lanuch_Workshop/resource/目录\n    >请下载本git repository\n    \n    ```bash\n      git clone https://github.com/aws-samples/eks-workshop-greater-china.git\n    ```\n    \n    **重要说明:** 本实验中使用到的gcr.io/k8s.gcr.io, quay.io镜像如果国内无法直接访问,请使用第三方image镜像或者个人dockerhub仓库,(可参考2.4 中国区镜像处理章节配置自动修改模式或者在实验中自行编辑对应的yaml文件).\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/IRSA/iam-pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: s3-echoer\nspec:\n  serviceAccountName: s3-echoer\n  containers:\n  - name: main\n    image: atlassian/pipelines-awscli\n    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']\n    env:\n    - name: AWS_DEFAULT_REGION\n      value: \"cn-northwest-1\"\n    - name: ENABLE_IRP\n      value: \"true\"\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/alb-ingress-controller/alb-ingress-controller.yaml",
    "content": "# Application Load Balancer (ALB) Ingress Controller Deployment Manifest.\n# This manifest details sensible defaults for deploying an ALB Ingress Controller.\n# GitHub: https://github.com/kubernetes-sigs/aws-alb-ingress-controller\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\n  # Namespace the ALB Ingress Controller should run in. Does not impact which\n  # namespaces it's able to resolve ingress resource for. For limiting ingress\n  # namespace scope, see --watch-namespace.\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app.kubernetes.io/name: alb-ingress-controller\n  template:\n    metadata:\n      labels:\n        app.kubernetes.io/name: alb-ingress-controller\n    spec:\n      containers:\n        - name: alb-ingress-controller\n          args:\n            # Limit the namespace where this ALB Ingress Controller deployment will\n            # resolve ingress resources. If left commented, all namespaces are used.\n            # - --watch-namespace=your-k8s-namespace\n\n            # Setting the ingress-class flag below ensures that only ingress resources with the\n            # annotation kubernetes.io/ingress.class: \"alb\" are respected by the controller. You may\n            # choose any class you'd like for this controller to respect.\n            - --ingress-class=alb\n\n            # REQUIRED\n            # Name of your cluster. Used when naming resources created\n            # by the ALB Ingress Controller, providing distinction between\n            # clusters.\n            - --cluster-name=eksworkshop\n\n            # AWS VPC ID this ingress controller will use to create AWS resources.\n            # If unspecified, it will be discovered from ec2metadata.\n            # - --aws-vpc-id=vpc-xxxxxx\n            - --aws-vpc-id=<你的vpc-id>\n\n            # AWS region this ingress controller will operate in.\n            # If unspecified, it will be discovered from ec2metadata.\n            # List of regions: http://docs.aws.amazon.com/general/latest/gr/rande.html#vpc_region\n            - --aws-region=cn-northwest-1\n\n            # Enables logging on all outbound requests sent to the AWS API.\n            # If logging is desired, set to true.\n            # - --aws-api-debug\n            # Maximum number of times to retry the aws calls.\n            # defaults to 10.\n            # - --aws-max-retries=10\n            # 如果你在中国区使用alb-ingress-controller 1.1.7以及以上版本 需要禁用\n            #- --feature-gates=waf=false,wafv2=false \n          env:\n            - name: AWS_REGION\n              value: cn-northwest-1\n            # AWS key id for authenticating with the AWS API.\n            # This is only here for examples. It's recommended you instead use\n            # a project like kube2iam for granting access.\n            #- name: AWS_ACCESS_KEY_ID\n            #  value: KEYVALUE\n\n            # AWS key secret for authenticating with the AWS API.\n            # This is only here for examples. It's recommended you instead use\n            # a project like kube2iam for granting access.\n            #- name: AWS_SECRET_ACCESS_KEY\n            #  value: SECRETVALUE\n          # Repository location of the ALB Ingress Controller.\n          image: docker.io/amazon/aws-alb-ingress-controller:v1.1.5\n      serviceAccountName: alb-ingress-controller\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/alb-ingress-controller/ingress-iam-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"acm:DescribeCertificate\",\n        \"acm:ListCertificates\",\n        \"acm:GetCertificate\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:AuthorizeSecurityGroupIngress\",\n        \"ec2:CreateSecurityGroup\",\n        \"ec2:CreateTags\",\n        \"ec2:DeleteTags\",\n        \"ec2:DeleteSecurityGroup\",\n        \"ec2:DescribeAccountAttributes\",\n        \"ec2:DescribeAddresses\",\n        \"ec2:DescribeInstances\",\n        \"ec2:DescribeInstanceStatus\",\n        \"ec2:DescribeInternetGateways\",\n        \"ec2:DescribeNetworkInterfaces\",\n        \"ec2:DescribeSecurityGroups\",\n        \"ec2:DescribeSubnets\",\n        \"ec2:DescribeTags\",\n        \"ec2:DescribeVpcs\",\n        \"ec2:ModifyInstanceAttribute\",\n        \"ec2:ModifyNetworkInterfaceAttribute\",\n        \"ec2:RevokeSecurityGroupIngress\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"elasticloadbalancing:AddListenerCertificates\",\n        \"elasticloadbalancing:AddTags\",\n        \"elasticloadbalancing:CreateListener\",\n        \"elasticloadbalancing:CreateLoadBalancer\",\n        \"elasticloadbalancing:CreateRule\",\n        \"elasticloadbalancing:CreateTargetGroup\",\n        \"elasticloadbalancing:DeleteListener\",\n        \"elasticloadbalancing:DeleteLoadBalancer\",\n        \"elasticloadbalancing:DeleteRule\",\n        \"elasticloadbalancing:DeleteTargetGroup\",\n        \"elasticloadbalancing:DeregisterTargets\",\n        \"elasticloadbalancing:DescribeListenerCertificates\",\n        \"elasticloadbalancing:DescribeListeners\",\n        \"elasticloadbalancing:DescribeLoadBalancers\",\n        \"elasticloadbalancing:DescribeLoadBalancerAttributes\",\n        \"elasticloadbalancing:DescribeRules\",\n        \"elasticloadbalancing:DescribeSSLPolicies\",\n        \"elasticloadbalancing:DescribeTags\",\n        \"elasticloadbalancing:DescribeTargetGroups\",\n        \"elasticloadbalancing:DescribeTargetGroupAttributes\",\n        \"elasticloadbalancing:DescribeTargetHealth\",\n        \"elasticloadbalancing:ModifyListener\",\n        \"elasticloadbalancing:ModifyLoadBalancerAttributes\",\n        \"elasticloadbalancing:ModifyRule\",\n        \"elasticloadbalancing:ModifyTargetGroup\",\n        \"elasticloadbalancing:ModifyTargetGroupAttributes\",\n        \"elasticloadbalancing:RegisterTargets\",\n        \"elasticloadbalancing:RemoveListenerCertificates\",\n        \"elasticloadbalancing:RemoveTags\",\n        \"elasticloadbalancing:SetIpAddressType\",\n        \"elasticloadbalancing:SetSecurityGroups\",\n        \"elasticloadbalancing:SetSubnets\",\n        \"elasticloadbalancing:SetWebACL\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iam:CreateServiceLinkedRole\",\n        \"iam:GetServerCertificate\",\n        \"iam:ListServerCertificates\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"cognito-idp:DescribeUserPoolClient\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"tag:GetResources\",\n        \"tag:TagResources\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/alb-ingress-controller/nginx-alb-ingress.yaml",
    "content": "---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment-ingress\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: \"service-nginx-clusterip\"\nspec:\n  selector:\n    app: nginx\n  #type: ClusterIP\n  type: NodePort\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\n---\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: \"alb-ingress\"\n  namespace: \"default\"\n  annotations:\n    kubernetes.io/ingress.class: alb\n    alb.ingress.kubernetes.io/scheme: internet-facing\n    #alb.ingress.kubernetes.io/target-type: ip\n    alb.ingress.kubernetes.io/target-type: instance\n  labels:\n    app: nginx\nspec:\n  rules:\n    - http:\n        paths:\n          - path: /*\n            backend:\n              serviceName: \"service-nginx-clusterip\"\n              servicePort: 80\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/alb-ingress-controller/rbac-role.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\nrules:\n  - apiGroups:\n      - \"\"\n      - extensions\n    resources:\n      - configmaps\n      - endpoints\n      - events\n      - ingresses\n      - ingresses/status\n      - services\n    verbs:\n      - create\n      - get\n      - list\n      - update\n      - watch\n      - patch\n  - apiGroups:\n      - \"\"\n      - extensions\n    resources:\n      - nodes\n      - pods\n      - secrets\n      - services\n      - namespaces\n    verbs:\n      - get\n      - list\n      - watch\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: alb-ingress-controller\nsubjects:\n  - kind: ServiceAccount\n    name: alb-ingress-controller\n    namespace: kube-system\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\n  namespace: kube-system\n...\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/.helmignore",
    "content": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation (prefixed with !). Only one pattern per line.\n.DS_Store\n# Common VCS dirs\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n# Common backup files\n*.swp\n*.bak\n*.tmp\n*~\n# Various IDEs\n.project\n.idea/\n*.tmproj\n.vscode/\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/Chart.yaml",
    "content": "apiVersion: v1\nappVersion: \"0.5.0\"\nname: aws-ebs-csi-driver\ndescription: A Helm chart for AWS EBS CSI Driver\nversion: 0.3.0\nkubeVersion: \">=1.13.0-0\"\nhome: https://github.com/kubernetes-sigs/aws-ebs-csi-driver\nsources:\n  - https://github.com/kubernetes-sigs/aws-ebs-csi-driver\nkeywords:\n  - aws\n  - ebs\n  - csi\nmaintainers:\n  - name: leakingtapan\n    email: chengpan@amazon.com\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/NOTES.txt",
    "content": "To verify that aws-ebs-csi-driver has started, run:\n\n    kubectl get pod -n kube-system -l \"app.kubernetes.io/name={{ include \"aws-ebs-csi-driver.name\" . }},app.kubernetes.io/instance={{ .Release.Name }}\"\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/_helpers.tpl",
    "content": "{{/* vim: set filetype=mustache: */}}\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"aws-ebs-csi-driver.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n\n{{/*\nCreate a default fully qualified app name.\nWe truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).\nIf release name contains chart name it will be used as a full name.\n*/}}\n{{- define \"aws-ebs-csi-driver.fullname\" -}}\n{{- if .Values.fullnameOverride -}}\n{{- .Values.fullnameOverride | trunc 63 | trimSuffix \"-\" -}}\n{{- else -}}\n{{- $name := default .Chart.Name .Values.nameOverride -}}\n{{- if contains $name .Release.Name -}}\n{{- .Release.Name | trunc 63 | trimSuffix \"-\" -}}\n{{- else -}}\n{{- printf \"%s-%s\" .Release.Name $name | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n{{- end -}}\n{{- end -}}\n\n{{/*\nCreate chart name and version as used by the chart label.\n*/}}\n{{- define \"aws-ebs-csi-driver.chart\" -}}\n{{- printf \"%s-%s\" .Chart.Name .Chart.Version | replace \"+\" \"_\" | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n\n{{/*\nCommon labels\n*/}}\n{{- define \"aws-ebs-csi-driver.labels\" -}}\napp.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\nhelm.sh/chart: {{ include \"aws-ebs-csi-driver.chart\" . }}\napp.kubernetes.io/instance: {{ .Release.Name }}\n{{- if .Chart.AppVersion }}\napp.kubernetes.io/version: {{ .Chart.AppVersion | quote }}\n{{- end }}\napp.kubernetes.io/managed-by: {{ .Release.Service }}\n{{- end -}}\n\n{{/*\nConvert the `--extra-volume-tags` command line arg from a map.\n*/}}\n{{- define \"aws-ebs-csi-driver.extra-volume-tags\" -}}\n{{- $result := dict \"pairs\" (list) -}}\n{{- range $key, $value := .Values.extraVolumeTags -}}\n{{- $noop := printf \"%s=%s\" $key $value | append $result.pairs | set $result \"pairs\" -}}\n{{- end -}}\n{{- if gt (len $result.pairs) 0 -}}\n- --extra-volume-tags={{- join \",\" $result.pairs -}}\n{{- end -}}\n{{- end -}}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/csidriver.yaml",
    "content": "apiVersion: storage.k8s.io/v1beta1\nkind: CSIDriver\nmetadata:\n  name: ebs.csi.aws.com\nspec:\n  attachRequired: true\n  podInfoOnMount: false\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/daemonset.yaml",
    "content": "# Node Service\nkind: DaemonSet\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-node\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app: ebs-csi-node\n      app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n      app.kubernetes.io/instance: {{ .Release.Name }}\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-node\n        app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n        app.kubernetes.io/instance: {{ .Release.Name }}\n      {{- if .Values.node.podAnnotations }}\n      annotations: {{ toYaml .Values.node.podAnnotations | nindent 8 }}\n      {{- end }}\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      hostNetwork: true\n      priorityClassName: system-node-critical\n      tolerations:\n        - operator: Exists\n        {{- with .Values.node.tolerations }}\n{{ toYaml . | indent 8 }}\n        {{- end }}\n      containers:\n        - name: ebs-plugin\n          securityContext:\n            privileged: true\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n          args:\n            - node\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:/csi/csi.sock\n          volumeMounts:\n            - name: kubelet-dir\n              mountPath: /var/lib/kubelet\n              mountPropagation: \"Bidirectional\"\n            - name: plugin-dir\n              mountPath: /csi\n            - name: device-dir\n              mountPath: /dev\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n        - name: node-driver-registrar\n          image: {{ printf \"%s:%s\" .Values.sidecars.nodeDriverRegistrarImage.repository .Values.sidecars.nodeDriverRegistrarImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)\n            - --v=5\n          lifecycle:\n            preStop:\n              exec:\n                command: [\"/bin/sh\", \"-c\", \"rm -rf /registration/ebs.csi.aws.com-reg.sock /csi/csi.sock\"]\n          env:\n            - name: ADDRESS\n              value: /csi/csi.sock\n            - name: DRIVER_REG_SOCK_PATH\n              value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n            - name: registration-dir\n              mountPath: /registration\n        - name: liveness-probe\n          image: {{ printf \"%s:%s\" .Values.sidecars.livenessProbeImage.repository .Values.sidecars.livenessProbeImage.tag }}\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n      volumes:\n        - name: kubelet-dir\n          hostPath:\n            path: /var/lib/kubelet\n            type: Directory\n        - name: plugin-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins/ebs.csi.aws.com/\n            type: DirectoryOrCreate\n        - name: registration-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins_registry/\n            type: Directory\n        - name: device-dir\n          hostPath:\n            path: /dev\n            type: Directory\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/deployment.yaml",
    "content": "# Controller Service\nkind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  replicas: {{ .Values.replicaCount }}\n  selector:\n    matchLabels:\n      app: ebs-csi-controller\n      app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n      app.kubernetes.io/instance: {{ .Release.Name }}\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-controller\n        app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n        app.kubernetes.io/instance: {{ .Release.Name }}\n      {{- if .Values.podAnnotations }}\n      annotations: {{ toYaml .Values.podAnnotations | nindent 8 }}\n      {{- end }}\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n        {{- with .Values.nodeSelector }}\n{{ toYaml . | indent 8 }}\n        {{- end }}\n      serviceAccountName: ebs-csi-controller-sa\n      priorityClassName: system-cluster-critical\n      {{- with .Values.affinity }}\n      affinity: {{ toYaml . | nindent 8 }}\n      {{- end }}\n      tolerations:\n        - operator: Exists\n      {{- with .Values.tolerations }}\n{{ toYaml . | indent 8 }}\n      {{- end }}\n      containers:\n        - name: ebs-plugin\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n          imagePullPolicy: {{ .Values.image.pullPolicy }}\n          args:\n            - controller\n            - --endpoint=$(CSI_ENDPOINT)\n            {{ include \"aws-ebs-csi-driver.extra-volume-tags\" . }}\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock\n            - name: AWS_ACCESS_KEY_ID\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: key_id\n                  optional: true\n            - name: AWS_SECRET_ACCESS_KEY\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: access_key\n                  optional: true\n            {{- if .Values.region }}\n            - name: AWS_REGION\n              value: {{ .Values.region }}\n            {{- end }}\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n          {{- with .Values.resources }}\n          resources: {{ toYaml . | nindent 12 }}\n          {{- end }}\n        - name: csi-provisioner\n          image: {{ printf \"%s:%s\" .Values.sidecars.provisionerImage.repository .Values.sidecars.provisionerImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            {{- if .Values.enableVolumeScheduling }}\n            - --feature-gates=Topology=true\n            {{- end}}\n            - --enable-leader-election\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        - name: csi-attacher\n          image: {{ printf \"%s:%s\" .Values.sidecars.attacherImage.repository .Values.sidecars.attacherImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            - --leader-election=true\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        {{- if .Values.enableVolumeSnapshot }}\n        - name: csi-snapshotter\n          image: {{ printf \"%s:%s\" .Values.sidecars.snapshotterImage.repository .Values.sidecars.snapshotterImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --leader-election=true\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        {{- end }}\n        {{- if .Values.enableVolumeResizing }}\n        - name: csi-resizer\n          image: {{ printf \"%s:%s\" .Values.sidecars.resizerImage.repository .Values.sidecars.resizerImage.tag }}\n          imagePullPolicy: Always\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        {{- end }}\n        - name: liveness-probe\n          image: {{ printf \"%s:%s\" .Values.sidecars.livenessProbeImage.repository .Values.sidecars.livenessProbeImage.tag }}\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /csi\n      volumes:\n        - name: socket-dir\n          emptyDir: {}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/rbac.yaml",
    "content": "---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-provisioner-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"delete\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"csinodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"coordination.k8s.io\"]\n    resources: [\"leases\"]\n    verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-provisioner-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-provisioner-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-attacher-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"csi.storage.k8s.io\"]\n    resources: [\"csinodeinfos\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"volumeattachments\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-attacher-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-attacher-role\n  apiGroup: rbac.authorization.k8s.io\n\n{{- if .Values.enableVolumeSnapshot }}\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-snapshotter-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"secrets\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents/status\"]\n    verbs: [\"update\"]\n  - apiGroups: [\"apiextensions.k8s.io\"]\n    resources: [\"customresourcedefinitions\"]\n    verbs: [\"create\", \"list\", \"watch\", \"delete\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshotter-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-snapshotter-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots/status\"]\n    verbs: [\"update\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshot-controller-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-snapshot-controller-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-leaderelection\n  namespace: kube-system \nrules:\n- apiGroups: [\"coordination.k8s.io\"]\n  resources: [\"leases\"]\n  verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: snapshot-controller-leaderelection\n  namespace: kube-system \nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system \nroleRef:\n  kind: Role\n  name: snapshot-controller-leaderelection\n  apiGroup: rbac.authorization.k8s.io\n\n{{- end }}\n\n{{- if .Values.enableVolumeResizing }}\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-resizer-role\nrules:\n  # The following rule should be uncommented for plugins that require secrets\n  # for provisioning.\n  # - apiGroups: [\"\"]\n  #   resources: [\"secrets\"]\n  #   verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims/status\"]\n    verbs: [\"update\", \"patch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-resizer-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-resizer-role\n  apiGroup: rbac.authorization.k8s.io\n{{- end}}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/serviceaccount.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-csi-controller-sa\n  namespace: kube-system\n  {{- with .Values.serviceAccount.controller.annotations }}\n  annotations: {{ toYaml . | nindent 4 }}\n  {{- end }}\n\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-snapshot-controller\n  namespace: kube-system\n  {{- with .Values.serviceAccount.snapshot.annotations }}\n  annotations: {{ toYaml . | nindent 4 }}\n  {{- end }}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/statefulset.yaml",
    "content": "{{- if .Values.enableVolumeSnapshot }}\r\n#Snapshot controller\r\nkind: StatefulSet\r\napiVersion: apps/v1\r\nmetadata:\r\n  name: ebs-snapshot-controller\r\n  namespace: kube-system\r\nspec:\r\n  serviceName: ebs-snapshot-controller\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: ebs-snapshot-controller\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: ebs-snapshot-controller\r\n    spec:\r\n      serviceAccount: ebs-snapshot-controller\r\n      containers:\r\n        - name: snapshot-controller\r\n          image: quay.io/k8scsi/snapshot-controller:v2.0.1\r\n          args:\r\n            - --v=5\r\n            - --leader-election=false\r\n{{- end }}\r\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/aws-ebs-csi-driver/values.yaml",
    "content": "# Default values for aws-ebs-csi-driver.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\nreplicaCount: 2\n\nimage:\n  repository: amazon/aws-ebs-csi-driver\n  tag: \"v0.5.0\"\n  pullPolicy: IfNotPresent\n\nsidecars:\n  provisionerImage:\n    repository: quay.io/k8scsi/csi-provisioner\n    tag: \"v1.5.0\"\n  attacherImage:\n    repository: quay.io/k8scsi/csi-attacher\n    tag: \"v1.2.0\"\n  snapshotterImage:\n    repository: quay.io/k8scsi/csi-snapshotter\n    tag: \"v2.0.1\"\n  livenessProbeImage:\n    repository: quay.io/k8scsi/livenessprobe\n    tag: \"v1.1.0\"\n  resizerImage:\n    repository: quay.io/k8scsi/csi-resizer\n    tag: \"v0.3.0\"\n  nodeDriverRegistrarImage:\n    repository: quay.io/k8scsi/csi-node-driver-registrar\n    tag: \"v1.1.0\"\n\nimagePullSecrets: []\nnameOverride: \"\"\nfullnameOverride: \"\"\n\npodAnnotations: {}\n\n# True if enable volume scheduling for dynamic volume provisioning\nenableVolumeScheduling: false\n\n# True if enable volume resizing\nenableVolumeResizing: false\n\n# True if enable volume snapshot\nenableVolumeSnapshot: false\n\nresources: {}\n  # We usually recommend not to specify default resources and to leave this as a conscious\n  # choice for the user. This also increases chances charts run on environments with little\n  # resources, such as Minikube. If you do want to specify resources, uncomment the following\n  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.\n  # limits:\n  #   cpu: 100m\n  #   memory: 128Mi\n  # requests:\n  #   cpu: 100m\n  #   memory: 128Mi\n\nnodeSelector: {}\n\ntolerations: []\n\naffinity: {}\n\n# Extra volume tags to attach to each dynamically provisioned volume.\n# ---\n# extraVolumeTags:\n#   key1: value1\n#   key2: value2\nextraVolumeTags: {}\n\n# AWS region to use. If not specified then the region will be looked up via the AWS EC2 metadata\n# service.\n# ---\n# region: us-east-1\nregion: \"\"\n\nnode:\n  podAnnotations: {}\n  tolerations: []\n\nserviceAccount:\n  controller:\n    annotations: {}\n  snapshot:\n    annotations: {}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/base/controller.yaml",
    "content": "---\n# Controller Service\nkind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: ebs-csi-controller\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-controller\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      serviceAccount: ebs-csi-controller-sa\n      priorityClassName: system-cluster-critical\n      tolerations:\n        - key: CriticalAddonsOnly\n          operator: Exists\n      containers:\n        - name: ebs-plugin\n          image: amazon/aws-ebs-csi-driver:latest\n          args :\n          # - {all,controller,node} # specify the driver mode\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock\n            - name: AWS_ACCESS_KEY_ID\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: key_id\n                  optional: true\n            - name: AWS_SECRET_ACCESS_KEY\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: access_key\n                  optional: true\n          # overwrite the AWS region instead of looking it up dynamically via the AWS EC2 metadata svc\n          # - name: AWS_REGION\n          #   value: us-east-1\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n        - name: csi-provisioner\n          image: quay.io/k8scsi/csi-provisioner:v1.5.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            - --feature-gates=Topology=true\n            - --enable-leader-election\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        - name: csi-attacher\n          image: quay.io/k8scsi/csi-attacher:v1.2.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            - --leader-election=true\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        - name: liveness-probe\n          image: quay.io/k8scsi/livenessprobe:v1.1.0\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /csi\n      volumes:\n        - name: socket-dir\n          emptyDir: {}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/base/csidriver.yaml",
    "content": "---\n\napiVersion: storage.k8s.io/v1beta1\nkind: CSIDriver\nmetadata:\n  name: ebs.csi.aws.com\nspec:\n  attachRequired: true\n  podInfoOnMount: false\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/base/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nnamespace: kube-system\nresources:\n- controller.yaml\n- node.yaml\n- rbac.yaml\n- csidriver.yaml\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/base/node.yaml",
    "content": "---\n# Node Service\nkind: DaemonSet\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-node\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app: ebs-csi-node\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-node\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      hostNetwork: true\n      priorityClassName: system-node-critical\n      tolerations:\n        - operator: Exists\n      containers:\n        - name: ebs-plugin\n          securityContext:\n            privileged: true\n          image: amazon/aws-ebs-csi-driver:latest\n          args:\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:/csi/csi.sock\n          volumeMounts:\n            - name: kubelet-dir\n              mountPath: /var/lib/kubelet\n              mountPropagation: \"Bidirectional\"\n            - name: plugin-dir\n              mountPath: /csi\n            - name: device-dir\n              mountPath: /dev\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n        - name: node-driver-registrar\n          image: quay.io/k8scsi/csi-node-driver-registrar:v1.1.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)\n            - --v=5\n          lifecycle:\n            preStop:\n              exec:\n                command: [\"/bin/sh\", \"-c\", \"rm -rf /registration/ebs.csi.aws.com-reg.sock /csi/csi.sock\"]\n          env:\n            - name: ADDRESS\n              value: /csi/csi.sock\n            - name: DRIVER_REG_SOCK_PATH\n              value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n            - name: registration-dir\n              mountPath: /registration\n        - name: liveness-probe\n          image: quay.io/k8scsi/livenessprobe:v1.1.0\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n      volumes:\n        - name: kubelet-dir\n          hostPath:\n            path: /var/lib/kubelet\n            type: Directory\n        - name: plugin-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins/ebs.csi.aws.com/\n            type: DirectoryOrCreate\n        - name: registration-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins_registry/\n            type: Directory\n        - name: device-dir\n          hostPath:\n            path: /dev\n            type: Directory\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/base/rbac.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-csi-controller-sa\n  namespace: kube-system\n  #Enable if EKS IAM for SA is used\n  #annotations:\n  #  eks.amazonaws.com/role-arn: arn:aws:iam::586565787010:role/ebs-csi-role\n\n---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-provisioner-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"delete\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"csinodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"coordination.k8s.io\"]\n    resources: [\"leases\"]\n    verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-provisioner-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-provisioner-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-attacher-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"csi.storage.k8s.io\"]\n    resources: [\"csinodeinfos\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"volumeattachments\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-attacher-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-attacher-role\n  apiGroup: rbac.authorization.k8s.io\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/cluster/crd_snapshotter.yaml",
    "content": "---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: (devel)\n    api-approved.kubernetes.io: \"https://github.com/kubernetes-csi/external-snapshotter/pull/139\"\n  creationTimestamp: null\n  name: volumesnapshotclasses.snapshot.storage.k8s.io\nspec:\n  group: snapshot.storage.k8s.io\n  names:\n    kind: VolumeSnapshotClass\n    listKind: VolumeSnapshotClassList\n    plural: volumesnapshotclasses\n    singular: volumesnapshotclass\n  scope: Cluster\n  preserveUnknownFields: false\n  validation:\n    openAPIV3Schema:\n      description: VolumeSnapshotClass specifies parameters that a underlying storage\n        system uses when creating a volume snapshot. A specific VolumeSnapshotClass\n        is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses\n        are non-namespaced\n      properties:\n        apiVersion:\n          description: 'APIVersion defines the versioned schema of this representation\n            of an object. Servers should convert recognized schemas to the latest\n            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'\n          type: string\n        deletionPolicy:\n          description: deletionPolicy determines whether a VolumeSnapshotContent created\n            through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot\n            is deleted. Supported values are \"Retain\" and \"Delete\". \"Retain\" means\n            that the VolumeSnapshotContent and its physical snapshot on underlying\n            storage system are kept. \"Delete\" means that the VolumeSnapshotContent\n            and its physical snapshot on underlying storage system are deleted. Required.\n          enum:\n          - Delete\n          - Retain\n          type: string\n        driver:\n          description: driver is the name of the storage driver that handles this\n            VolumeSnapshotClass. Required.\n          type: string\n        kind:\n          description: 'Kind is a string value representing the REST resource this\n            object represents. Servers may infer this from the endpoint the client\n            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n          type: string\n        parameters:\n          additionalProperties:\n            type: string\n          description: parameters is a key-value map with storage driver specific\n            parameters for creating snapshots. These values are opaque to Kubernetes.\n          type: object\n      required:\n      - deletionPolicy\n      - driver\n      type: object\n  version: v1beta1\n  versions:\n  - name: v1beta1\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n\n---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: (devel)\n    api-approved.kubernetes.io: \"https://github.com/kubernetes-csi/external-snapshotter/pull/139\"\n  creationTimestamp: null\n  name: volumesnapshotcontents.snapshot.storage.k8s.io\nspec:\n  group: snapshot.storage.k8s.io\n  names:\n    kind: VolumeSnapshotContent\n    listKind: VolumeSnapshotContentList\n    plural: volumesnapshotcontents\n    singular: volumesnapshotcontent\n  scope: Cluster\n  subresources:\n    status: {}\n  preserveUnknownFields: false\n  validation:\n    openAPIV3Schema:\n      description: VolumeSnapshotContent represents the actual \"on-disk\" snapshot\n        object in the underlying storage system\n      properties:\n        apiVersion:\n          description: 'APIVersion defines the versioned schema of this representation\n            of an object. Servers should convert recognized schemas to the latest\n            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'\n          type: string\n        kind:\n          description: 'Kind is a string value representing the REST resource this\n            object represents. Servers may infer this from the endpoint the client\n            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n          type: string\n        spec:\n          description: spec defines properties of a VolumeSnapshotContent created\n            by the underlying storage system. Required.\n          properties:\n            deletionPolicy:\n              description: deletionPolicy determines whether this VolumeSnapshotContent\n                and its physical snapshot on the underlying storage system should\n                be deleted when its bound VolumeSnapshot is deleted. Supported values\n                are \"Retain\" and \"Delete\". \"Retain\" means that the VolumeSnapshotContent\n                and its physical snapshot on underlying storage system are kept. \"Delete\"\n                means that the VolumeSnapshotContent and its physical snapshot on\n                underlying storage system are deleted. In dynamic snapshot creation\n                case, this field will be filled in with the \"DeletionPolicy\" field\n                defined in the VolumeSnapshotClass the VolumeSnapshot refers to. For\n                pre-existing snapshots, users MUST specify this field when creating\n                the VolumeSnapshotContent object. Required.\n              enum:\n              - Delete\n              - Retain\n              type: string\n            driver:\n              description: driver is the name of the CSI driver used to create the\n                physical snapshot on the underlying storage system. This MUST be the\n                same as the name returned by the CSI GetPluginName() call for that\n                driver. Required.\n              type: string\n            source:\n              description: source specifies from where a snapshot will be created.\n                This field is immutable after creation. Required.\n              properties:\n                snapshotHandle:\n                  description: snapshotHandle specifies the CSI \"snapshot_id\" of a\n                    pre-existing snapshot on the underlying storage system. This field\n                    is immutable.\n                  type: string\n                volumeHandle:\n                  description: volumeHandle specifies the CSI \"volume_id\" of the volume\n                    from which a snapshot should be dynamically taken from. This field\n                    is immutable.\n                  type: string\n              type: object\n            volumeSnapshotClassName:\n              description: name of the VolumeSnapshotClass to which this snapshot\n                belongs.\n              type: string\n            volumeSnapshotRef:\n              description: volumeSnapshotRef specifies the VolumeSnapshot object to\n                which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName\n                field must reference to this VolumeSnapshotContent's name for the\n                bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent\n                object, name and namespace of the VolumeSnapshot object MUST be provided\n                for binding to happen. This field is immutable after creation. Required.\n              properties:\n                apiVersion:\n                  description: API version of the referent.\n                  type: string\n                fieldPath:\n                  description: 'If referring to a piece of an object instead of an\n                    entire object, this string should contain a valid JSON/Go field\n                    access statement, such as desiredState.manifest.containers[2].\n                    For example, if the object reference is to a container within\n                    a pod, this would take on a value like: \"spec.containers{name}\"\n                    (where \"name\" refers to the name of the container that triggered\n                    the event) or if no container name is specified \"spec.containers[2]\"\n                    (container with index 2 in this pod). This syntax is chosen only\n                    to have some well-defined way of referencing a part of an object.\n                    TODO: this design is not final and this field is subject to change\n                    in the future.'\n                  type: string\n                kind:\n                  description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n                  type: string\n                name:\n                  description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'\n                  type: string\n                namespace:\n                  description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'\n                  type: string\n                resourceVersion:\n                  description: 'Specific resourceVersion to which this reference is\n                    made, if any. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency'\n                  type: string\n                uid:\n                  description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'\n                  type: string\n              type: object\n          required:\n          - deletionPolicy\n          - driver\n          - source\n          - volumeSnapshotRef\n          type: object\n        status:\n          description: status represents the current information of a snapshot.\n          properties:\n            creationTime:\n              description: creationTime is the timestamp when the point-in-time snapshot\n                is taken by the underlying storage system. In dynamic snapshot creation\n                case, this field will be filled in with the \"creation_time\" value\n                returned from CSI \"CreateSnapshotRequest\" gRPC call. For a pre-existing\n                snapshot, this field will be filled with the \"creation_time\" value\n                returned from the CSI \"ListSnapshots\" gRPC call if the driver supports\n                it. If not specified, it indicates the creation time is unknown. The\n                format of this field is a Unix nanoseconds time encoded as an int64.\n                On Unix, the command `date +%s%N` returns the current time in nanoseconds\n                since 1970-01-01 00:00:00 UTC.\n              format: int64\n              type: integer\n            error:\n              description: error is the latest observed error during snapshot creation,\n                if any.\n              properties:\n                message:\n                  description: 'message is a string detailing the encountered error\n                    during snapshot creation if specified. NOTE: message may be logged,\n                    and it should not contain sensitive information.'\n                  type: string\n                time:\n                  description: time is the timestamp when the error was encountered.\n                  format: date-time\n                  type: string\n              type: object\n            readyToUse:\n              description: readyToUse indicates if a snapshot is ready to be used\n                to restore a volume. In dynamic snapshot creation case, this field\n                will be filled in with the \"ready_to_use\" value returned from CSI\n                \"CreateSnapshotRequest\" gRPC call. For a pre-existing snapshot, this\n                field will be filled with the \"ready_to_use\" value returned from the\n                CSI \"ListSnapshots\" gRPC call if the driver supports it, otherwise,\n                this field will be set to \"True\". If not specified, it means the readiness\n                of a snapshot is unknown.\n              type: boolean\n            restoreSize:\n              description: restoreSize represents the complete size of the snapshot\n                in bytes. In dynamic snapshot creation case, this field will be filled\n                in with the \"size_bytes\" value returned from CSI \"CreateSnapshotRequest\"\n                gRPC call. For a pre-existing snapshot, this field will be filled\n                with the \"size_bytes\" value returned from the CSI \"ListSnapshots\"\n                gRPC call if the driver supports it. When restoring a volume from\n                this snapshot, the size of the volume MUST NOT be smaller than the\n                restoreSize if it is specified, otherwise the restoration will fail.\n                If not specified, it indicates that the size is unknown.\n              format: int64\n              minimum: 0\n              type: integer\n            snapshotHandle:\n              description: snapshotHandle is the CSI \"snapshot_id\" of a snapshot on\n                the underlying storage system. If not specified, it indicates that\n                dynamic snapshot creation has either failed or it is still in progress.\n              type: string\n          type: object\n      required:\n      - spec\n      type: object\n  version: v1beta1\n  versions:\n  - name: v1beta1\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n\n---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: (devel)\n    api-approved.kubernetes.io: \"https://github.com/kubernetes-csi/external-snapshotter/pull/139\"\n  creationTimestamp: null\n  name: volumesnapshots.snapshot.storage.k8s.io\nspec:\n  group: snapshot.storage.k8s.io\n  names:\n    kind: VolumeSnapshot\n    listKind: VolumeSnapshotList\n    plural: volumesnapshots\n    singular: volumesnapshot\n  scope: Namespaced\n  subresources:\n    status: {}\n  preserveUnknownFields: false\n  validation:\n    openAPIV3Schema:\n      description: VolumeSnapshot is a user's request for either creating a point-in-time\n        snapshot of a persistent volume, or binding to a pre-existing snapshot.\n      properties:\n        apiVersion:\n          description: 'APIVersion defines the versioned schema of this representation\n            of an object. Servers should convert recognized schemas to the latest\n            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'\n          type: string\n        kind:\n          description: 'Kind is a string value representing the REST resource this\n            object represents. Servers may infer this from the endpoint the client\n            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n          type: string\n        spec:\n          description: 'spec defines the desired characteristics of a snapshot requested\n            by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots\n            Required.'\n          properties:\n            source:\n              description: source specifies where a snapshot will be created from.\n                This field is immutable after creation. Required.\n              properties:\n                persistentVolumeClaimName:\n                  description: persistentVolumeClaimName specifies the name of the\n                    PersistentVolumeClaim object in the same namespace as the VolumeSnapshot\n                    object where the snapshot should be dynamically taken from. This\n                    field is immutable.\n                  type: string\n                volumeSnapshotContentName:\n                  description: volumeSnapshotContentName specifies the name of a pre-existing\n                    VolumeSnapshotContent object. This field is immutable.\n                  type: string\n              type: object\n            volumeSnapshotClassName:\n              description: 'volumeSnapshotClassName is the name of the VolumeSnapshotClass\n                requested by the VolumeSnapshot. If not specified, the default snapshot\n                class will be used if one exists. If not specified, and there is no\n                default snapshot class, dynamic snapshot creation will fail. Empty\n                string is not allowed for this field. TODO(xiangqian): a webhook validation\n                on empty string. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshot-classes'\n              type: string\n          required:\n          - source\n          type: object\n        status:\n          description: 'status represents the current information of a snapshot. NOTE:\n            status can be modified by sources other than system controllers, and must\n            not be depended upon for accuracy. Controllers should only use information\n            from the VolumeSnapshotContent object after verifying that the binding\n            is accurate and complete.'\n          properties:\n            boundVolumeSnapshotContentName:\n              description: 'boundVolumeSnapshotContentName represents the name of\n                the VolumeSnapshotContent object to which the VolumeSnapshot object\n                is bound. If not specified, it indicates that the VolumeSnapshot object\n                has not been successfully bound to a VolumeSnapshotContent object\n                yet. NOTE: Specified boundVolumeSnapshotContentName alone does not\n                mean binding       is valid. Controllers MUST always verify bidirectional\n                binding between       VolumeSnapshot and VolumeSnapshotContent to\n                avoid possible security issues.'\n              type: string\n            creationTime:\n              description: creationTime is the timestamp when the point-in-time snapshot\n                is taken by the underlying storage system. In dynamic snapshot creation\n                case, this field will be filled in with the \"creation_time\" value\n                returned from CSI \"CreateSnapshotRequest\" gRPC call. For a pre-existing\n                snapshot, this field will be filled with the \"creation_time\" value\n                returned from the CSI \"ListSnapshots\" gRPC call if the driver supports\n                it. If not specified, it indicates that the creation time of the snapshot\n                is unknown.\n              format: date-time\n              type: string\n            error:\n              description: error is the last observed error during snapshot creation,\n                if any. This field could be helpful to upper level controllers(i.e.,\n                application controller) to decide whether they should continue on\n                waiting for the snapshot to be created based on the type of error\n                reported.\n              properties:\n                message:\n                  description: 'message is a string detailing the encountered error\n                    during snapshot creation if specified. NOTE: message may be logged,\n                    and it should not contain sensitive information.'\n                  type: string\n                time:\n                  description: time is the timestamp when the error was encountered.\n                  format: date-time\n                  type: string\n              type: object\n            readyToUse:\n              description: readyToUse indicates if a snapshot is ready to be used\n                to restore a volume. In dynamic snapshot creation case, this field\n                will be filled in with the \"ready_to_use\" value returned from CSI\n                \"CreateSnapshotRequest\" gRPC call. For a pre-existing snapshot, this\n                field will be filled with the \"ready_to_use\" value returned from the\n                CSI \"ListSnapshots\" gRPC call if the driver supports it, otherwise,\n                this field will be set to \"True\". If not specified, it means the readiness\n                of a snapshot is unknown.\n              type: boolean\n            restoreSize:\n              description: restoreSize represents the complete size of the snapshot\n                in bytes. In dynamic snapshot creation case, this field will be filled\n                in with the \"size_bytes\" value returned from CSI \"CreateSnapshotRequest\"\n                gRPC call. For a pre-existing snapshot, this field will be filled\n                with the \"size_bytes\" value returned from the CSI \"ListSnapshots\"\n                gRPC call if the driver supports it. When restoring a volume from\n                this snapshot, the size of the volume MUST NOT be smaller than the\n                restoreSize if it is specified, otherwise the restoration will fail.\n                If not specified, it indicates that the size is unknown.\n              type: string\n          type: object\n      required:\n      - spec\n      type: object\n  version: v1beta1\n  versions:\n  - name: v1beta1\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/controller_add_resizer.yaml",
    "content": "kind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  template:\n    spec:\n      containers:\n        - name: csi-resizer\n          image: quay.io/k8scsi/csi-resizer:v0.3.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/controller_add_snapshotter.yaml",
    "content": "kind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  template:\n    spec:\n      containers:\n        - name: csi-snapshotter\n          image: quay.io/k8scsi/csi-snapshotter:v2.0.1\n          args:\n            - --csi-address=$(ADDRESS)\n            - --leader-election=true\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\nimages:\n- name: amazon/aws-ebs-csi-driver\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/aws-ebs-csi-driver\n  newTag: v0.4.0\n- name: quay.io/k8scsi/csi-provisioner\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-provisioner\n  newTag: v1.3.0\n- name: quay.io/k8scsi/csi-attacher\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-attacher\n  newTag: v1.2.0\n- name: quay.io/k8scsi/livenessprobe\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-liveness-probe\n  newTag: v1.1.0\n- name: quay.io/k8scsi/csi-node-driver-registrar\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-node-driver-registrar\n  newTag: v1.1.0\npatches:\n- controller_add_snapshotter.yaml\n- controller_add_resizer.yaml\nresources:\n- rbac_add_snapshotter.yaml\n- rbac_add_resizer.yaml\n- rbac_add_snapshot_controller.yaml\n- snapshot_controller.yaml\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/rbac_add_resizer.yaml",
    "content": "---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-resizer-role\nrules:\n  # The following rule should be uncommented for plugins that require secrets\n  # for provisioning.\n  # - apiGroups: [\"\"]\n  #   resources: [\"secrets\"]\n  #   verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims/status\"]\n    verbs: [\"update\", \"patch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-resizer-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-resizer-role\n  apiGroup: rbac.authorization.k8s.io\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/rbac_add_snapshot_controller.yaml",
    "content": "# RBAC file for the snapshot controller.\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-snapshot-controller\n  namespace: kube-system\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots/status\"]\n    verbs: [\"update\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshot-controller-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-snapshot-controller-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-leaderelection\n  namespace: kube-system \nrules:\n- apiGroups: [\"coordination.k8s.io\"]\n  resources: [\"leases\"]\n  verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: snapshot-controller-leaderelection\n  namespace: kube-system \nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system \nroleRef:\n  kind: Role\n  name: snapshot-controller-leaderelection\n  apiGroup: rbac.authorization.k8s.io\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/rbac_add_snapshotter.yaml",
    "content": "---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-snapshotter-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"secrets\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents/status\"]\n    verbs: [\"update\"]\n  - apiGroups: [\"apiextensions.k8s.io\"]\n    resources: [\"customresourcedefinitions\"]\n    verbs: [\"create\", \"list\", \"watch\", \"delete\"]\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshotter-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-snapshotter-role\n  apiGroup: rbac.authorization.k8s.io\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/snapshot_controller.yaml",
    "content": "---\nkind: StatefulSet\napiVersion: apps/v1\nmetadata:\n  name: ebs-snapshot-controller\n  namespace: kube-system\nspec:\n  serviceName: ebs-snapshot-controller\n  replicas: 1\n  selector:\n    matchLabels:\n      app: ebs-snapshot-controller\n  template:\n    metadata:\n      labels:\n        app: ebs-snapshot-controller\n    spec:\n      serviceAccount: ebs-snapshot-controller\n      containers:\n        - name: snapshot-controller\n          image: quay.io/k8scsi/snapshot-controller:v2.0.1\n          args:\n            - --v=5\n            - --leader-election=false\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/dev/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\nimages:\n- name: amazon/aws-ebs-csi-driver\n  newTag: latest\n  newName: chengpan/aws-ebs-csi-driver\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\nimages:\n- name: amazon/aws-ebs-csi-driver\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/aws-ebs-csi-driver\n  newTag: v0.4.0\n- name: quay.io/k8scsi/csi-provisioner\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-provisioner\n  newTag: v1.3.0\n- name: quay.io/k8scsi/csi-attacher\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-attacher\n  newTag: v1.2.0\n- name: quay.io/k8scsi/livenessprobe\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-liveness-probe\n  newTag: v1.1.0\n- name: quay.io/k8scsi/csi-node-driver-registrar\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-node-driver-registrar\n  newTag: v1.1.0\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/deploy/kubernetes/secret.yaml",
    "content": "apiVersion: v1\nkind: Secret\nmetadata:\n  name: aws-secret\n  namespace: kube-system\nstringData:\n  key_id: \"\"\n  access_key: \"\"\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/ebs-csi-iam-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:AttachVolume\",\n        \"ec2:CreateSnapshot\",\n        \"ec2:CreateTags\",\n        \"ec2:CreateVolume\",\n        \"ec2:DeleteSnapshot\",\n        \"ec2:DeleteTags\",\n        \"ec2:DeleteVolume\",\n        \"ec2:DescribeInstances\",\n        \"ec2:DescribeSnapshots\",\n        \"ec2:DescribeTags\",\n        \"ec2:DescribeVolumes\",\n        \"ec2:DetachVolume\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/block-volume/README.md",
    "content": "## Raw Block Volume\nThis example shows how to consume a dynamically-provisioned EBS volume as a raw block device.\n\n### Edit [Persistence Volume Claim Spec](./specs/raw-claim.yaml)\nMake sure the `volumeMode` is `Block`.\n\n### Edit [Application Pod](./specs/pod.yaml)\nMake sure the pod is consuming the PVC with the defined name and `volumeDevices` is used instead of `volumeMounts`.\n\n### Deploy the Application\n```sh\nkubectl apply -f examples/kubernetes/block-volume/specs/storageclass.yaml\nkubectl apply -f examples/kubernetes/block-volume/specs/raw-claim.yaml\nkubectl apply -f examples/kubernetes/block-volume/specs/pod.yaml\n```\n\n### Access Block Device\nAfter the objects are created, verify that pod is running:\n\n```sh\n$ kubectl get pods\nNAME   READY   STATUS    RESTARTS   AGE\napp    1/1     Running   0          16m\n```\nVerify the device node is mounted inside the container:\n\n```sh\n$ kubectl exec -ti app -- ls -al /dev/xvda\nbrw-rw----    1 root     disk      202, 23296 Mar 12 04:23 /dev/xvda\n```\n\nWrite to the device using:\n\n```sh\ndd if=/dev/zero of=/dev/xvda bs=1024k count=100\n100+0 records in\n100+0 records out\n104857600 bytes (105 MB, 100 MiB) copied, 0.0492386 s, 2.1 GB/s\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/block-volume/specs/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app \nspec:\n  containers:\n  - name: app \n    image: busybox \n    command: [\"/bin/sh\", \"-c\"]\n    args: [\"tail -f /dev/null\"]\n    volumeDevices:\n    - name: data\n      devicePath: /dev/xvda\n  volumes:\n  - name: data\n    persistentVolumeClaim:\n      claimName: block-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/block-volume/specs/raw-claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: block-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  volumeMode: Block\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 10Gi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/block-volume/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/README.md",
    "content": "# Dynamic Volume Provisioning\nThis example shows how to create a EBS volume and consume it from container dynamically.\n\n## Prerequisites\n\n1. Kubernetes 1.13+ (CSI 1.0).\n\n1. The [aws-ebs-csi-driver driver](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) is installed.\n\n## Usage\n\n1. Create a sample app along with the StorageClass and the PersistentVolumeClaim:\n```\nkubectl apply -f specs/\n```\n\n2. Validate the volume was created and `volumeHandle` contains an EBS volumeID:\n```\nkubectl describe pv\n```\n\n3. Validate the pod successfully wrote data to the volume:\n```\nkubectl exec -it app cat /data/out.txt\n```\n\n4. Cleanup resources:\n```\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/resizing/README.md",
    "content": "## Volume Resizing\nThis example shows how to resize EBS persistence volume using volume resizing features.\n\n**Note**\n1. CSI volume resizing is still alpha as of Kubernetes 1.15\n2. EBS has a limit of one volume modification every 6 hours. Refer to [EBS documentation](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyVolume.html) for more details.\n\n## Usage\n1. Add `allowVolumeExpansion: true` in the StorageClass spec in [example manifest](./specs/example.yaml) to enable volume expansion. You can only expand a PVC if its storage class’s allowVolumeExpansion field is set to true\n\n2. Deploy the example:\n```sh\nkubectl apply -f specs/\n``` \n\n3. Verify the volume is created and Pod is running:\n```sh\nkubectl get pv\nkubectl get po app\n```\n\n4. Expand the volume size by increasing the capacity in PVC's `spec.resources.requests.storage`:\n```sh\nkubectl edit pvc ebs-claim\n```\nSave the result at the end of the edit.\n\n5. Verify that both the persistence volume and persistence volume claim are resized:\n```sh\nkubectl get pv\nkubectl get pvc\n```\nYou should see that both should have the new value relfected in the capacity fields.\n\n6. Verify that the application is continuously running without any interruption:\n```sh\nkubectl exec -it app cat /data/out.txt\n```\n\n7. Cleanup resources:\n```\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/resizing/spec/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: resize-sc\nprovisioner: ebs.csi.aws.com\nallowVolumeExpansion: true\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: resize-sc\n  resources:\n    requests:\n      storage: 4Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/README.md",
    "content": "# Volume Snapshots\n\n## Overview\n\nThis driver implements basic volume snapshotting functionality using the [external snapshotter](https://github.com/kubernetes-csi/external-snapshotter) sidecar and creates snapshots of EBS volumes using the `VolumeSnapshot` custom resources.\n\n## Prerequisites\n\n1. Kubernetes 1.13+ (CSI 1.0).\n\n1. The `VolumeSnapshotDataSource` must be set in `--feature-gates=` in the `kube-apiserver`.\n\n1. The [aws-ebs-csi-driver driver](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) is installed.\n\n### Usage\n\n1. Create the `StorageClass` and `VolumeSnapshotClass`:\n```\nkubectl apply -f specs/classes/\n```\n\n2. Create a sample app and the `PersistentVolumeClaim`: \n```\nkubectl apply -f specs/app/\n```\n\n3. Validate the volume was created and `volumeHandle` contains an EBS volumeID: \n```\nkubectl describe pv\n```\n\n4. Validate the pod successfully wrote data to the volume, taking note of the timestamp of the first entry:\n```\nkubectl exec -it app cat /data/out.txt\n```\n\n5. Create a `VolumeSnapshot` referencing the `PersistentVolumeClaim` name:\n```\nkubectl apply -f specs/snapshot/\n```\n\n6. Wait for the `Ready To Use:  true` attribute of the `VolumeSnapshot`: \n```\nkubectl describe volumesnapshot.snapshot.storage.k8s.io ebs-volume-snapshot\n```\n\n7. Delete the existing app:\n```\nkubectl delete -f specs/app/\n```\n\n8. Restore a volume from the snapshot with a `PersistentVolumeClaim` referencing the `VolumeSnapshot` in its `dataSource`:\n```\nkubectl apply -f specs/snapshot-restore/\n```\n\n9. Validate the new pod has the restored data by comparing the timestamp of the first entry to that of in step 4:\n```\nkubectl exec -it app cat /data/out.txt\n```\n\n10. Cleanup resources:\n```\nkubectl delete -f specs/snapshot-restore\nkubectl delete -f specs/snapshot\nkubectl delete -f specs/classes\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/app/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/app/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/classes/snapshotclass.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshotClass\nmetadata:\n  name: csi-aws-vsc\ndriver: ebs.csi.aws.com\ndeletionPolicy: Delete\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/classes/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot/snapshot.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshot\nmetadata:\n  name: ebs-volume-snapshot\nspec:\n  volumeSnapshotClassName: csi-aws-vsc\n  source:\n    persistentVolumeClaimName: ebs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-import/volume-snapshot-content.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshotContent\nmetadata:\n  name: static-snapshot-content\nspec:\n  volumeSnapshotRef:\n    kind: VolumeSnapshot\n    name: static-snapshot-demo\n    namespace: default \n  source:\n    snapshotHandle: snap-0fba4d7649d765c50\n  driver: ebs.csi.aws.com\n  volumeSnapshotClassName: csi-aws-vsc\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-import/volume-snapshot.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshot\nmetadata:\n  name: static-snapshot-demo\n  namespace: default \nspec:\n  volumeSnapshotClassName: csi-aws-vsc\n  source:\n    volumeSnapshotContentName: static-snapshot-content\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-restore/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-snapshot-restored-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n  dataSource:\n    name: ebs-volume-snapshot\n    kind: VolumeSnapshot\n    apiGroup: snapshot.storage.k8s.io\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-restore/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-snapshot-restored-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/static-provisioning/README.md",
    "content": "# Static Provisioning \nThis example shows how to create and consume persistence volume from exising EBS using static provisioning. \n\n## Usage\n1. Edit the PersistentVolume spec in [example manifest](./specs/example.yaml). Update `volumeHandle` with EBS volume ID that you are going to use, and update the `fsType` with the filesystem type of the volume. In this example, I have a pre-created EBS  volume in us-east-1c availability zone and it is formatted with xfs filesystem.\n\n```\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: test-pv\nspec:\n  capacity:\n    storage: 50Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  csi:\n    driver: ebs.csi.aws.com\n    volumeHandle: {volumeId} \n    fsType: xfs\n  nodeAffinity:\n    required:\n      nodeSelectorTerms:\n      - matchExpressions:\n        - key: topology.ebs.csi.aws.com/zone\n          operator: In\n          values:\n          - us-east-1c \n```\nNote that node affinity is used here since EBS volume is created in us-east-1c, hence only node in the same AZ can consume this persisence volume. \n\n2. Deploy the example:\n```sh\nkubectl apply -f specs/\n```\n\n3. Verify application pod is running:\n```sh\nkubectl describe po app\n```\n\n4. Validate the pod successfully wrote data to the volume:\n```sh\nkubectl exec -it app cat /data/out.txt\n```\n\n5. Cleanup resources:\n```sh\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/static-provisioning/specs/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\nreclaimPolicy: Retain\n---\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: test-pv\nspec:\n  capacity:\n    storage: 50Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  csi:\n    driver: ebs.csi.aws.com\n    volumeHandle: vol-05786ec9ec9526b67\n    fsType: xfs\n  nodeAffinity:\n    required:\n      nodeSelectorTerms:\n      - matchExpressions:\n        - key: topology.ebs.csi.aws.com/zone\n          operator: In\n          values:\n          - us-east-1c \n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 50Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/storageclass/README.md",
    "content": "# Configuring StorageClass\nThis example shows how to configure Kubernetes storageclass to provision EBS volumes with various configuration parameters. EBS CSI driver is compatiable with in-tree EBS plugin on StorageClass parameters. For the full list of in-tree EBS plugin parameters, please refer to Kubernetes documentation of [StorageClass Parameter](https://kubernetes.io/docs/concepts/storage/storage-classes/#aws-ebs).\n\n## Usage\n1. Edit the StorageClass spec in [example manifest](./specs/example.yaml) and update storageclass parameters to desired value. In this example, a `io1` EBS volume will be created and formatted to `xfs` filesystem with encryption enabled using the default KMS key.\n\n2. Deploy the example:\n```sh\nkubectl apply -f specs/\n```\n\n3. Verify the volume is created:\n```sh\nkubectl describe pv\n```\n\n4. Validate the pod successfully wrote data to the volume:\n```sh\nkubectl exec -it app cat /data/out.txt\n```\n\n5. Cleanup resources:\n```sh\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/examples/kubernetes/storageclass/specs/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\nparameters:\n  csi.storage.k8s.io/fstype: xfs\n  type: io1\n  iopsPerGB: \"50\"\n  encrypted: \"true\"\nallowedTopologies:\n- matchLabelExpressions:\n  - key: topology.ebs.csi.aws.com/zone\n    values:\n    - us-east-1a\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-ebs-csi-driver/updaterole.sh",
    "content": "\necho  \"CSI Policy ARN| $1\"\n\nCSI_ARN=$1\nROLES=$(aws iam list-roles --query 'Roles[?contains(RoleName,`nodegr`)].RoleName' --output text)\n\nfor i in $ROLES\ndo\n    echo attach [$CSI_ARN] to [$i]\n    aws iam attach-role-policy \\\n            --policy-arn $CSI_ARN \\\n             --role-name $i \\\n             --region cn-northwest-1\n\ndone\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.dockerignore",
    "content": "vendor/\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve EBS CSI Driver\nlabels: \n\n---\n\n/kind bug\n\n**What happened?**\n\n**What you expected to happen?**\n\n**How to reproduce it (as minimally and precisely as possible)?**\n\n**Anything else we need to know?**:\n\n**Environment**\n- Kubernetes version (use `kubectl version`):\n- Driver version:\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.github/ISSUE_TEMPLATE/enhancement-request.md",
    "content": "---\nname: Enhancement request\nabout: Suggest an idea for this project\nlabels: \n\n---\n\n**Is your feature request related to a problem?/Why is this needed**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n/feature\n\n**Describe the solution you'd like in detail**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\nlabels: \n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like in detail**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.github/ISSUE_TEMPLATE/support-request.md",
    "content": "---\nname: Support request\nabout: Ask questions about the driver\nlabels: \n\n---\n\n<!-- \nSTOP -- PLEASE READ!\n\nGitHub is not the right place for support requests.\n\nIf you're looking for help, post your question on the [Kubernetes Slack ](http://slack.k8s.io/) Sig-AWS Channel.\n\nIf the matter is security related, please disclose it privately via https://kubernetes.io/security/.\n-->\n\n<!-- DO NOT EDIT BELOW THIS LINE -->\n\n/triage support\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.github/PULL_REQUEST_TEMPLATE.md",
    "content": "**Is this a bug fix or adding new feature?**\n\n**What is this PR about? / Why do we need it?**\n\n**What testing is done?** \n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.github/workflows/container-image.yaml",
    "content": "name: Container Images\n\non: push\njobs:\n  build:\n    # this is to prevent the job to run at forked projects\n    if: github.repository == 'kubernetes-sigs/aws-efs-csi-driver'\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n    - name: Build container image\n      run: |\n        docker build -t aws-efs-csi-driver .\n    - name: Push to Github registry\n      run: |\n        USER=$(echo $GITHUB_REPOSITORY | cut -d'/' -f1)\n        BRANCH=$(echo $GITHUB_REF | cut -d'/' -f3)\n        IMAGE=aws-efs-csi-driver\n        if [ \"$BRANCH\" = \"master\" ]; then\n          TAG=\"latest\"\n        else\n          TAG=$BRANCH\n        fi\n        docker login docker.pkg.github.com -u $USER -p ${{ secrets.REGISTRY_TOKEN }}\n        docker tag aws-efs-csi-driver docker.pkg.github.com/$GITHUB_REPOSITORY/$IMAGE:$TAG\n        docker push docker.pkg.github.com/$GITHUB_REPOSITORY/$IMAGE:$TAG\n    - name: Push to Dockerhub registry\n      run: |\n        BRANCH=$(echo $GITHUB_REF | cut -d'/' -f3)\n        REPO=amazon/aws-efs-csi-driver\n        if [ \"$BRANCH\" = \"master\" ]; then\n          TAG=\"latest\"\n        else\n          TAG=$BRANCH\n        fi\n        docker login -u ${{ secrets.DOCKERHUB_USER }} -p ${{ secrets.DOCKERHUB_TOKEN }}\n        docker tag aws-efs-csi-driver $REPO:$TAG\n        docker push $REPO:$TAG\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.gitignore",
    "content": "*.swp\nbin/\nvendor/\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/.travis.yml",
    "content": "language: go\ngo_import_path: github.com/kubernetes-sigs/aws-efs-csi-driver\n\nenv:\n  global:\n    - GO111MODULE=on\n\ngo:\n  - \"1.13.4\"\n\nbefore_install:\n  - go get github.com/mattn/goveralls\n\nscript:\n  - make\n  - go test -covermode=count -coverprofile=profile.cov $(go list ./pkg/... | grep -v /driver)\n    # TODO stop skipping controller tests when controller is implemented\n  - go test -covermode=count -coverprofile=profile.cov ./pkg/driver/... -ginkgo.skip='\\[Controller.Server\\]'\n  - $GOPATH/bin/goveralls -coverprofile=profile.cov -service=travis-ci\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/deploy/kubernetes/base/csidriver.yaml",
    "content": "---\n\napiVersion: storage.k8s.io/v1beta1\nkind: CSIDriver\nmetadata:\n  name: efs.csi.aws.com\nspec:\n  attachRequired: false\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/deploy/kubernetes/base/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nnamespace: kube-system\nresources:\n- node.yaml\n- csidriver.yaml\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/deploy/kubernetes/base/node.yaml",
    "content": "---\n# Node Service\nkind: DaemonSet\napiVersion: apps/v1\nmetadata:\n  name: efs-csi-node\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app: efs-csi-node\n  template:\n    metadata:\n      labels:\n        app: efs-csi-node\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      hostNetwork: true\n      priorityClassName: system-node-critical\n      tolerations:\n        - operator: Exists\n      containers:\n        - name: efs-plugin\n          securityContext:\n            privileged: true\n          image: amazon/aws-efs-csi-driver:latest\n          args:\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:/csi/csi.sock\n          volumeMounts:\n            - name: kubelet-dir\n              mountPath: /var/lib/kubelet\n              mountPropagation: \"Bidirectional\"\n            - name: plugin-dir\n              mountPath: /csi\n            - name: efs-state-dir\n              mountPath: /var/run/efs\n          ports:\n            - containerPort: 9809\n              name: healthz\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 2\n            failureThreshold: 5\n        - name: csi-driver-registrar\n          image: quay.io/k8scsi/csi-node-driver-registrar:v1.1.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)\n            - --v=5\n          env:\n            - name: ADDRESS\n              value: /csi/csi.sock\n            - name: DRIVER_REG_SOCK_PATH\n              value: /var/lib/kubelet/plugins/efs.csi.aws.com/csi.sock\n            - name: KUBE_NODE_NAME\n              valueFrom:\n                fieldRef:\n                  fieldPath: spec.nodeName\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n            - name: registration-dir\n              mountPath: /registration\n        - name: liveness-probe\n          imagePullPolicy: Always\n          image: quay.io/k8scsi/livenessprobe:v1.1.0\n          args:\n            - --csi-address=/csi/csi.sock\n            - --health-port=9809\n          volumeMounts:\n            - mountPath: /csi\n              name: plugin-dir\n      volumes:\n        - name: kubelet-dir\n          hostPath:\n            path: /var/lib/kubelet\n            type: Directory\n        - name: registration-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins_registry/\n            type: Directory\n        - name: plugin-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins/efs.csi.aws.com/\n            type: DirectoryOrCreate\n        - name: efs-state-dir\n          hostPath:\n            path: /var/run/efs\n            type: DirectoryOrCreate\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/deploy/kubernetes/overlays/stable/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\nimages:\n- name: amazon/aws-efs-csi-driver\n  newTag: v0.3.0\n  newName: amazon/aws-efs-csi-driver\n- name: quay.io/k8scsi/livenessprobe\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-liveness-probe\n  newTag: v1.1.0\n- name: quay.io/k8scsi/csi-node-driver-registrar\n  newName: 961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/csi-node-driver-registrar\n  newTag: v1.1.0\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/encryption_in_transit/README.md",
    "content": "## Encryption in Transit\nThis example shows how to make a static provisioned EFS persistence volume (PV) mounted inside container with encryption in transit enabled.\n\n**Note**: this example requires Kubernetes v1.13+\n\n### Edit [Persistence Volume Spec](./specs/pv.yaml) \n\n```\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  mountOptions:\n    - tls\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: [FileSystemId] \n```\nNote that encryption in transit is enabled using mount option `tls`. Replace `VolumeHandle` value with `FileSystemId` of the EFS filesystem that needs to be mounted.\n\nYou can find it using AWS CLI:\n```sh\n>> aws efs describe-file-systems --query \"FileSystems[*].FileSystemId\"\n```\n\n### Deploy the Example\nCreate PV, persistence volume claim (PVC) and storage class:\n```sh\n>> kubectl apply -f examples/kubernetes/encryption_in_transit/specs/storageclass.yaml\n>> kubectl apply -f examples/kubernetes/encryption_in_transit/specs/pv.yaml\n>> kubectl apply -f examples/kubernetes/encryption_in_transit/specs/claim.yaml\n>> kubectl apply -f examples/kubernetes/encryption_in_transit/specs/pod.yaml\n```\n\n### Check EFS filesystem is used\nAfter the objects are created, verify that pod is running:\n\n```sh\n>> kubectl get pods\n```\n\nAlso you can verify that data is written onto EFS filesystem:\n\n```sh\n>> kubectl exec -ti efs-app -- tail -f /data/out.txt\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/encryption_in_transit/specs/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: efs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: efs-sc\n  resources:\n    requests:\n      storage: 5Gi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/encryption_in_transit/specs/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: efs-app\nspec:\n  containers:\n  - name: app\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: efs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/encryption_in_transit/specs/pv.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  mountOptions:\n    - tls\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: fs-4af69aab\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/encryption_in_transit/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: efs-sc\nprovisioner: efs.csi.aws.com\nmountOptions:\n  - tls\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/multiple_pods/README.md",
    "content": "## Multiple Pods Read Write Many \nThis example shows how to create a static provisioned EFS persistence volume (PV) and access it from multiple pods with RWX access mode.\n\n### Edit Persistent Volume\nEdit persistent volume using sample [spec](./specs/pv.yaml):\n```\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: [FileSystemId] \n```\nReplace `volumeHandle` value with `FileSystemId` of the EFS filesystem that needs to be mounted. Note that the access mode is `RWX` which means the PV can be read and written from multiple pods.\n\nYou can get `FileSystemId` using AWS CLI:\n\n```sh\n>> aws efs describe-file-systems --query \"FileSystems[*].FileSystemId\"\n```\n\n### Deploy the Example Application\nCreate PV, persistence volume claim (PVC), storageclass and the pods that consume the PV:\n```sh\n>> kubectl apply -f examples/kubernetes/multiple_pods/specs/storageclass.yaml\n>> kubectl apply -f examples/kubernetes/multiple_pods/specs/pv.yaml\n>> kubectl apply -f examples/kubernetes/multiple_pods/specs/claim.yaml\n>> kubectl apply -f examples/kubernetes/multiple_pods/specs/pod1.yaml\n>> kubectl apply -f examples/kubernetes/multiple_pods/specs/pod2.yaml\n```\n\nIn the example, both pod1 and pod2 are writing to the same EFS filesystem at the same time.\n\n### Check the Application uses EFS filesystem\nAfter the objects are created, verify that pod is running:\n\n```sh\n>> kubectl get pods\n```\n\nAlso verify that data is written onto EFS filesystem from both pods:\n\n```sh\n>> kubectl exec -ti app1 -- tail -f /data/out1.txt\n>> kubectl exec -ti app2 -- tail -f /data/out2.txt\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/multiple_pods/specs/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: efs-claim\nspec:\n  accessModes:\n    - ReadWriteMany\n  storageClassName: efs-sc\n  resources:\n    requests:\n      storage: 5Gi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/multiple_pods/specs/pod1.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app1\nspec:\n  containers:\n  - name: app1\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out1.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: efs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/multiple_pods/specs/pod2.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app2\nspec:\n  containers:\n  - name: app2\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out2.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: efs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/multiple_pods/specs/pv.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: fs-9c48a679\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/multiple_pods/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: efs-sc\nprovisioner: efs.csi.aws.com\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/statefulset/README.md",
    "content": "## Use in Stateful Set\nThis example shows how to consume EFS filesystem from StatefulSets using the driver. Before the example, refer to [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) for what it is.\n\n## Deploy the example\n\n```sh\nkubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-efs-csi-driver/master/examples/kubernetes/statefulset/specs/example.yaml\n```\n\n## Check the StatefulSets Application\nCheck StatefulSets is deployed successfully:\n```sh\n$ kubectl get sts\nNAME          READY   AGE\nefs-app-sts   3/3     70m\n``` \n\nCheck the pods are running:\n```sh\n$ kubectl get po\nNAME            READY   STATUS    RESTARTS   AGE\nefs-app-sts-0   1/1     Running   0          71m\nefs-app-sts-1   1/1     Running   0          71m\nefs-app-sts-2   1/1     Running   0          71m\n```\n\nCheck data are written onto EFS filesystem:\n```sh\n$ kubectl exec -ti efs-app-sts-0 -- tail -f /efs-data/out.txt\nMon May 6 00:50:15 UTC 2019\nMon May 6 00:50:18 UTC 2019\nMon May 6 00:50:19 UTC 2019\nMon May 6 00:50:20 UTC 2019\nMon May 6 00:50:23 UTC 2019\nMon May 6 00:50:24 UTC 2019\nMon May 6 00:50:25 UTC 2019\nMon May 6 00:50:28 UTC 2019\nMon May 6 00:50:29 UTC 2019\nMon May 6 00:50:30 UTC 2019\n```\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/statefulset/specs/example.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: fs-4af69aab\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: efs-claim\nspec:\n  accessModes:\n    - ReadWriteMany\n  storageClassName: efs-sc\n  resources:\n    requests:\n      storage: 5Gi\n---\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: efs-app-sts\nspec:\n  selector:\n    matchLabels:\n      app: test-efs\n  serviceName: efs-app\n  replicas: 3\n  template:\n    metadata:\n      labels:\n        app: test-efs\n    spec:\n      terminationGracePeriodSeconds: 10\n      containers:\n      - name: linux\n        image: amazonlinux:2 \n        command: [\"/bin/sh\"]\n        args: [\"-c\", \"while true; do echo $(date -u) >> /efs-data/out.txt; sleep 5; done\"]\n        volumeMounts:\n        - name: efs-storage\n          mountPath: /efs-data\n      volumes:\n      - name: efs-storage\n        persistentVolumeClaim:\n          claimName: efs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/static_provisioning/README.md",
    "content": "## Static Provisioning\nThis example shows how to make a static provisioned EFS persistence volume (PV) mounted inside container.\n\n### Edit [Persistence Volume Spec](./specs/pv.yaml) \n\n```\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: [FileSystemId] \n```\nReplace `VolumeHandle` value with `FileSystemId` of the EFS filesystem that needs to be mounted.\n\nYou can find it using AWS CLI:\n```sh\n>> aws efs describe-file-systems --query \"FileSystems[*].FileSystemId\"\n```\n\n### Deploy the Example Application\nCreate PV, persistence volume claim (PVC) and storage class:\n```sh\n>> kubectl apply -f examples/kubernetes/static_provisioning/specs/storageclass.yaml\n>> kubectl apply -f examples/kubernetes/static_provisioning/specs/pv.yaml\n>> kubectl apply -f examples/kubernetes/static_provisioning/specs/claim.yaml\n>> kubectl apply -f examples/kubernetes/static_provisioning/specs/pod.yaml\n```\n\n### Check EFS filesystem is used\nAfter the objects are created, verify that pod is running:\n\n```sh\n>> kubectl get pods\n```\n\nAlso you can verify that data is written onto EFS filesystem:\n\n```sh\n>> kubectl exec -ti efs-app -- tail -f /data/out.txt\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/static_provisioning/specs/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: efs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: efs-sc\n  resources:\n    requests:\n      storage: 5Gi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/static_provisioning/specs/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: efs-app\nspec:\n  containers:\n  - name: app\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: efs-claim\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/static_provisioning/specs/pv.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: fs-9c48a679\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/static_provisioning/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: efs-sc\nprovisioner: efs.csi.aws.com\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/volume_path/README.md",
    "content": "## EFS Volume Path\nSimilar to [static provisioning example](../static_provisioning). A sub directory of EFS can be mounted inside container. This gives cluster operator the flexibility to restrict the amount of data being accessed from different containers on EFS.\n\n**Note**: this feature requires the sub directory to mount precreated on EFS before consuming the volume from pod.\n\n### Edit [Persistence Volume Spec](./specs/example.yaml)\n```\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv1\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: [FileSystemId]:[Path]\n```\nReplace `FileSystemId` of the EFS filesystem ID that needs to be mounted. And replace `Path` with a existing path on the filesystem.\n\nYou can find it using AWS CLI:\n```sh\n>> aws efs describe-file-systems --query \"FileSystems[*].FileSystemId\"\n```\n\n### Deploy the Example Application\nCreate PV, persistence volume claim (PVC) and storage class:\n```sh\n>> kubectl apply -f examples/kubernetes/volume_path/specs/example.yaml\n```\n\n### Check EFS filesystem is used\nAfter the objects are created, verify that pod is running:\n\n```sh\n>> kubectl get pods\n```\n\nAlso you can verify that data is written onto EFS filesystem:\n\n```sh\n>> kubectl exec -ti efs-app -- tail -f /data-dir1/out.txt\n>> kubectl exec -ti efs-app -- ls /data-dir2\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/aws-efs-csi-driver/examples/kubernetes/volume_path/specs/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: efs-sc\nprovisioner: efs.csi.aws.com\n---\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv1\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  mountOptions:\n    - tls\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: fs-e8a95a42:/dir1\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: efs-claim1\nspec:\n  accessModes:\n    - ReadWriteMany\n  storageClassName: efs-sc\n  resources:\n    requests:\n      storage: 5Gi\n---\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: efs-pv2\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  persistentVolumeReclaimPolicy: Retain\n  storageClassName: efs-sc\n  mountOptions:\n    - tls\n  csi:\n    driver: efs.csi.aws.com\n    volumeHandle: fs-e8a95a42:/dir2\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: efs-claim2\nspec:\n  accessModes:\n    - ReadWriteMany\n  storageClassName: efs-sc\n  resources:\n    requests:\n      storage: 5Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: efs-app\nspec:\n  containers:\n  - name: app\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data-dir1/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: efs-volume-1\n      mountPath: /data-dir1\n    - name: efs-volume-2\n      mountPath: /data-dir2\n  volumes:\n  - name: efs-volume-1\n    persistentVolumeClaim:\n      claimName: efs-claim1\n  - name: efs-volume-2\n    persistentVolumeClaim:\n      claimName: efs-claim2\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/cluster-autoscaler/cluster_autoscaler.yml",
    "content": "---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\n  name: cluster-autoscaler\n  namespace: kube-system\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: cluster-autoscaler\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"events\", \"endpoints\"]\n    verbs: [\"create\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"pods/eviction\"]\n    verbs: [\"create\"]\n  - apiGroups: [\"\"]\n    resources: [\"pods/status\"]\n    verbs: [\"update\"]\n  - apiGroups: [\"\"]\n    resources: [\"endpoints\"]\n    resourceNames: [\"cluster-autoscaler\"]\n    verbs: [\"get\", \"update\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"watch\", \"list\", \"get\", \"update\"]\n  - apiGroups: [\"\"]\n    resources:\n      - \"pods\"\n      - \"services\"\n      - \"replicationcontrollers\"\n      - \"persistentvolumeclaims\"\n      - \"persistentvolumes\"\n    verbs: [\"watch\", \"list\", \"get\"]\n  - apiGroups: [\"extensions\"]\n    resources: [\"replicasets\", \"daemonsets\"]\n    verbs: [\"watch\", \"list\", \"get\"]\n  - apiGroups: [\"policy\"]\n    resources: [\"poddisruptionbudgets\"]\n    verbs: [\"watch\", \"list\"]\n  - apiGroups: [\"apps\"]\n    resources: [\"statefulsets\", \"replicasets\", \"daemonsets\"]\n    verbs: [\"watch\", \"list\", \"get\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"watch\", \"list\", \"get\"]\n  - apiGroups: [\"batch\", \"extensions\"]\n    resources: [\"jobs\"]\n    verbs: [\"get\", \"list\", \"watch\", \"patch\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"configmaps\"]\n    verbs: [\"create\"]\n  - apiGroups: [\"\"]\n    resources: [\"configmaps\"]\n    resourceNames: [\"cluster-autoscaler-status\", \"cluster-autoscaler-priority-expander\"]\n    verbs: [\"delete\", \"get\", \"update\", \"watch\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: cluster-autoscaler\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: cluster-autoscaler\nsubjects:\n  - kind: ServiceAccount\n    name: cluster-autoscaler\n    namespace: kube-system\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: cluster-autoscaler\nsubjects:\n  - kind: ServiceAccount\n    name: cluster-autoscaler\n    namespace: kube-system\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    app: cluster-autoscaler\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: cluster-autoscaler\n  template:\n    metadata:\n      labels:\n        app: cluster-autoscaler\n    spec:\n      serviceAccountName: cluster-autoscaler\n      #nodeSelector:\n      #  intent: control-apps      \n      containers:\n        - image: k8s.gcr.io/cluster-autoscaler:v1.14.7\n          name: cluster-autoscaler\n          resources:\n            limits:\n              cpu: 100m\n              memory: 300Mi\n            requests:\n              cpu: 100m\n              memory: 300Mi\n          command:\n            - ./cluster-autoscaler\n            - --v=4\n            - --stderrthreshold=info\n            - --cloud-provider=aws\n            - --skip-nodes-with-local-storage=false\n            - --nodes=1:3:eksctl-eksworkshop-nodegroup-ng-6ee72264-NodeGroup-1HV2SGGAPW9U3\n            - --expander=random\n            - --expendable-pods-priority-cutoff=-10\n            - --scale-down-unneeded-time=2m0s\n            - --scale-down-unready-time=3m0s\n            - --scale-down-delay-after-add=2m0s\n            - --scale-down-utilization-threshold=0.7\n            - --balance-similar-node-groups\n            - --max-total-unready-percentage=75\n            - --ok-total-unready-count=20\n            - --max-empty-bulk-delete=30\n          env:\n            - name: AWS_REGION\n              value: cn-northwest-1\n          volumeMounts:\n            - name: ssl-certs\n              mountPath: /etc/ssl/certs/ca-certificates.crt\n              readOnly: true\n          imagePullPolicy: \"Always\"\n      volumes:\n        - name: ssl-certs\n          hostPath:\n            path: \"/etc/ssl/certs/ca-bundle.crt\"\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/cluster-autoscaler/k8s-asg-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"autoscaling:DescribeAutoScalingGroups\",\n        \"autoscaling:DescribeAutoScalingInstances\",\n        \"autoscaling:SetDesiredCapacity\",\n        \"autoscaling:TerminateInstanceInAutoScalingGroup\",\n        \"autoscaling:DescribeTags\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/cluster-autoscaler/nginx-to-scaleout.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-to-scaleout\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        service: nginx\n        app: nginx\n    spec:\n      containers:\n      - image: nginx\n        name: nginx-to-scaleout\n        resources:\n          limits:\n            cpu: 500m\n            memory: 512Mi\n          requests:\n            cpu: 500m\n            memory: 512Mi\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/efk/fluent-bit.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: fluent-bit\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRole\nmetadata:\n  name: pod-log-reader\nrules:\n- apiGroups: [\"\"]\n  resources:\n  - namespaces\n  - pods\n  verbs: [\"get\", \"list\", \"watch\"]\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBinding\nmetadata:\n  name: pod-log-crb\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: pod-log-reader\nsubjects:\n- kind: ServiceAccount\n  name: fluent-bit\n  namespace: default\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: fluent-bit-config\n  labels:\n    app.kubernetes.io/name: fluentbit\ndata:\n  fluent-bit.conf: |\n    [SERVICE]\n        Parsers_File  parsers.conf\n    [INPUT]\n        Name              tail\n        Tag               kube.*\n        Path              /var/log/containers/*.log\n        Parser            docker\n        DB                /var/log/flb_kube.db\n        Mem_Buf_Limit     5MB\n        Skip_Long_Lines   On\n        Refresh_Interval  10\n    [FILTER]\n        Name parser\n        Match **\n        Parser nginx\n        Key_Name log\n    [OUTPUT]\n        Name cloudwatch\n        Match   *\n        region cn-northwest-1\n        log_group_name fluent-bit-cloudwatch\n        log_stream_prefix from-fluent-bit-\n        auto_create_group true \n  parsers.conf: |\n    [PARSER]\n        Name   nginx\n        Format regex\n        Regex ^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \\[(?<time>[^\\]]*)\\] \"(?<method>\\S+)(?: +(?<path>[^\\\"]*?)(?: +\\S*)?)?\" (?<code>[^ ]*) (?<size>[^ ]*)(?: \"(?<referer>[^\\\"]*)\" \"(?<agent>[^\\\"]*)\")? \\\"-\\\"$\n        Time_Key time\n        Time_Format %d/%b/%Y:%H:%M:%S %z\n    [PARSER]\n        Name        docker\n        Format      json\n        Time_Key    time\n        Time_Format %Y-%m-%dT%H:%M:%S.%L\n        Time_Keep   On\n        # Command      |  Decoder | Field | Optional Action\n        # =============|==================|=================\n        Decode_Field_As   escaped    log\n---\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: fluentbit\n  labels:\n    app.kubernetes.io/name: fluentbit\nspec:\n  selector:\n    matchLabels:\n      name: fluentbit\n  template:\n    metadata:\n      labels:\n        name: fluentbit\n    spec:\n      serviceAccountName: fluent-bit\n      containers:\n      - name: aws-for-fluent-bit\n        image: amazon/aws-for-fluent-bit:2.3.0\n        volumeMounts:\n        - name: varlog\n          mountPath: /var/log\n        - name: varlibdockercontainers\n          mountPath: /var/lib/docker/containers\n          readOnly: true\n        - name: fluent-bit-config\n          mountPath: /fluent-bit/etc/\n        - name: mnt\n          mountPath: /mnt\n          readOnly: true\n        resources:\n          limits:\n            memory: 500Mi\n          requests:\n            cpu: 500m\n            memory: 100Mi\n      volumes:\n      - name: varlog\n        hostPath:\n          path: /var/log\n      - name: varlibdockercontainers\n        hostPath:\n          path: /var/lib/docker/containers\n      - name: fluent-bit-config\n        configMap:\n          name: fluent-bit-config\n      - name: mnt\n        hostPath:\n          path: /mnt\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/.helmignore",
    "content": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation (prefixed with !). Only one pattern per line.\n.DS_Store\n# Common VCS dirs\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n# Common backup files\n*.swp\n*.bak\n*.tmp\n*.orig\n*~\n# Various IDEs\n.project\n.idea/\n*.tmproj\n.vscode/\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/Chart.yaml",
    "content": "apiVersion: v2\nname: eks-helm-demo\ndescription: A Helm chart for EKS Workshop Microservices application\nversion: 0.1.0\nappVersion: 1.0\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/templates/deployment/crystal.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: ecsdemo-crystal\n  labels:\n    app: ecsdemo-crystal\n  namespace: default\nspec:\n  replicas: {{ .Values.replicas }}\n  selector:\n    matchLabels:\n      app: ecsdemo-crystal\n  strategy:\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 25%\n    type: RollingUpdate\n  template:\n    metadata:\n      labels:\n        app: ecsdemo-crystal\n    spec:\n      containers:\n      - image: {{ .Values.crystal.image }}:{{ .Values.version }}\n        imagePullPolicy: Always\n        name: ecsdemo-crystal\n        ports:\n        - containerPort: 3000\n          protocol: TCP\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/templates/deployment/frontend.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: ecsdemo-frontend\n  labels:\n    app: ecsdemo-frontend\n  namespace: default\nspec:\n  replicas: {{ .Values.replicas }}\n  selector:\n    matchLabels:\n      app: ecsdemo-frontend\n  strategy:\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 25%\n    type: RollingUpdate\n  template:\n    metadata:\n      labels:\n        app: ecsdemo-frontend\n    spec:\n      containers:\n      - image: {{ .Values.frontend.image }}:{{ .Values.version }}\n        imagePullPolicy: Always\n        name: ecsdemo-frontend\n        ports:\n        - containerPort: 3000\n          protocol: TCP\n        env:\n        - name: CRYSTAL_URL\n          value: \"http://ecsdemo-crystal.default.svc.cluster.local/crystal\"\n        - name: NODEJS_URL\n          value: \"http://ecsdemo-nodejs.default.svc.cluster.local/\"\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/templates/deployment/nodejs.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: ecsdemo-nodejs\n  labels:\n    app: ecsdemo-nodejs\n  namespace: default\nspec:\n  replicas: {{ .Values.replicas }}\n  selector:\n    matchLabels:\n      app: ecsdemo-nodejs\n  strategy:\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 25%\n    type: RollingUpdate\n  template:\n    metadata:\n      labels:\n        app: ecsdemo-nodejs\n    spec:\n      containers:\n      - image: {{ .Values.nodejs.image }}:{{ .Values.version }}\n        imagePullPolicy: Always\n        name: ecsdemo-nodejs\n        ports:\n        - containerPort: 3000\n          protocol: TCP\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/templates/service/crystal.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: ecsdemo-crystal\nspec:\n  selector:\n    app: ecsdemo-crystal\n  ports:\n   -  protocol: TCP\n      port: 80\n      targetPort: 3000\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/templates/service/frontend.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: ecsdemo-frontend\nspec:\n  selector:\n    app: ecsdemo-frontend\n  type: LoadBalancer\n  ports:\n   -  protocol: TCP\n      port: 80\n      targetPort: 3000\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/templates/service/nodejs.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: ecsdemo-nodejs\nspec:\n  selector:\n    app: ecsdemo-nodejs\n  ports:\n   -  protocol: TCP\n      port: 80\n      targetPort: 3000\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/eks-helm-demo/values.yaml",
    "content": "# Default values for eksdemo.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\n# Release-wide Values\nreplicas: 3\nversion: 'latest'\n\n# Service Specific Values\nnodejs:\n  #image: brentley/ecsdemo-nodejs\n  image: brentley/ecsdemo-nodejs-non-existing\ncrystal:\n  image: brentley/ecsdemo-crystal\nfrontend:\n  image: brentley/ecsdemo-frontend\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/healthchecks/liveness-app.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: liveness-app\nspec:\n  containers:\n  - name: liveness\n    image: brentley/ecsdemo-nodejs\n    livenessProbe:\n      httpGet:\n        path: /health\n        port: 3000\n      initialDelaySeconds: 5\n      periodSeconds: 5\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/healthchecks/readiness-deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: readiness-deployment\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: readiness-deployment\n  template:\n    metadata:\n      labels:\n        app: readiness-deployment\n    spec:\n      containers:\n      - name: readiness-deployment\n        image: alpine\n        command: [\"sh\", \"-c\", \"touch /tmp/healthy && sleep 86400\"]\n        readinessProbe:\n          exec:\n            command:\n            - cat\n            - /tmp/healthy\n          initialDelaySeconds: 5\n          periodSeconds: 3\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/hpa/hpa-v2.yaml",
    "content": "apiVersion: v1\nitems:\n- apiVersion: autoscaling/v2beta2\n  kind: HorizontalPodAutoscaler\n  metadata:\n    creationTimestamp: \"2020-03-06T13:47:52Z\"\n    name: php-apache\n    namespace: default\n    resourceVersion: \"582901\"\n    selfLink: /apis/autoscaling/v2beta2/namespaces/default/horizontalpodautoscalers/php-apache\n    uid: 13758845-5fb1-11ea-ab77-02aadf7bd768\n  spec:\n    maxReplicas: 5\n    minReplicas: 1\n    metrics:\n    # - resource:\n    #     name: cpu\n    #     target:\n    #       averageUtilization: 30\n    #       type: Utilization\n    #   type: Resource\n    - type: Resource\n      resource:\n        name: cpu\n        target:\n          type: Utilization\n          averageUtilization: 50\n    - type: Pods\n      pods:\n        metric:\n          name: packets-per-second\n        target:\n          type: AverageValue\n          averageValue: 1k\n    - type: Object\n      object:\n        metric:\n          name: requests-per-second\n        describedObject:\n          apiVersion: networking.k8s.io/v1beta1\n          kind: Ingress\n          name: main-route\n        target:\n          type: Value\n          value: 10k\n    scaleTargetRef:\n      apiVersion: extensions/v1beta1\n      kind: Deployment\n      name: php-apache\n  status:\n    conditions:\n    - lastTransitionTime: \"2020-03-06T13:48:08Z\"\n      message: recommended size matches current size\n      reason: ReadyForNewScale\n      status: \"True\"\n      type: AbleToScale\n    - lastTransitionTime: \"2020-03-06T13:48:08Z\"\n      message: the HPA was able to successfully calculate a replica count from cpu\n        resource utilization (percentage of request)\n      reason: ValidMetricFound\n      status: \"True\"\n      type: ScalingActive\n    - lastTransitionTime: \"2020-03-06T14:03:48Z\"\n      message: the desired replica count is increasing faster than the maximum scale\n        rate\n      reason: TooFewReplicas\n      status: \"True\"\n      type: ScalingLimited\n    currentMetrics:\n    - resource:\n        current:\n          averageUtilization: 0\n          averageValue: 1m\n        name: cpu\n      type: Resource\n    currentReplicas: 1\n    desiredReplicas: 1\n    lastScaleTime: \"2020-03-06T14:03:48Z\"\nkind: List\nmetadata:\n  resourceVersion: \"\"\n  selfLink: \"\"\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/hpa/php-apache.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: php-apache\nspec:\n  selector:\n    matchLabels:\n      run: php-apache\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        run: php-apache\n    spec:\n      containers:\n      - name: php-apache\n        image: k8s.gcr.io/hpa-example\n        ports:\n        - containerPort: 80\n        resources:\n          limits:\n            cpu: 500m\n          requests:\n            cpu: 200m\n\n---\n\napiVersion: v1\nkind: Service\nmetadata:\n  name: php-apache\n  labels:\n    run: php-apache\nspec:\n  ports:\n  - port: 80\n  selector:\n    run: php-apache\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/bookinfo-gateway.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: Gateway\nmetadata:\n  name: bookinfo-gateway\nspec:\n  selector:\n    istio: ingressgateway # use istio default controller\n  servers:\n  - port:\n      number: 80\n      name: http\n      protocol: HTTP\n    hosts:\n    - \"*\"\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: bookinfo\nspec:\n  hosts:\n  - \"*\"\n  gateways:\n  - bookinfo-gateway\n  http:\n  - match:\n    - uri:\n        exact: /productpage\n    - uri:\n        prefix: /static\n    - uri:\n        exact: /login\n    - uri:\n        exact: /logout\n    - uri:\n        prefix: /api/v1/products\n    route:\n    - destination:\n        host: productpage\n        port:\n          number: 9080\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/bookinfo.yaml",
    "content": "# Copyright 2017 Istio Authors\n#\n#   Licensed under the Apache License, Version 2.0 (the \"License\");\n#   you may not use this file except in compliance with the License.\n#   You may obtain a copy of the License at\n#\n#       http://www.apache.org/licenses/LICENSE-2.0\n#\n#   Unless required by applicable law or agreed to in writing, software\n#   distributed under the License is distributed on an \"AS IS\" BASIS,\n#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#   See the License for the specific language governing permissions and\n#   limitations under the License.\n\n##################################################################################################\n# This file defines the services, service accounts, and deployments for the Bookinfo sample.\n#\n# To apply all 4 Bookinfo services, their corresponding service accounts, and deployments:\n#\n#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml\n#\n# Alternatively, you can deploy any resource separately:\n#\n#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews # reviews Service\n#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews # reviews ServiceAccount\n#   kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3 # reviews-v3 Deployment\n##################################################################################################\n\n##################################################################################################\n# Details service\n##################################################################################################\napiVersion: v1\nkind: Service\nmetadata:\n  name: details\n  labels:\n    app: details\n    service: details\nspec:\n  ports:\n  - port: 9080\n    name: http\n  selector:\n    app: details\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: bookinfo-details\n  labels:\n    account: details\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: details-v1\n  labels:\n    app: details\n    version: v1\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: details\n      version: v1\n  template:\n    metadata:\n      labels:\n        app: details\n        version: v1\n    spec:\n      serviceAccountName: bookinfo-details\n      containers:\n      - name: details\n        image: docker.io/istio/examples-bookinfo-details-v1:1.15.0\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 9080\n---\n##################################################################################################\n# Ratings service\n##################################################################################################\napiVersion: v1\nkind: Service\nmetadata:\n  name: ratings\n  labels:\n    app: ratings\n    service: ratings\nspec:\n  ports:\n  - port: 9080\n    name: http\n  selector:\n    app: ratings\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: bookinfo-ratings\n  labels:\n    account: ratings\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: ratings-v1\n  labels:\n    app: ratings\n    version: v1\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: ratings\n      version: v1\n  template:\n    metadata:\n      labels:\n        app: ratings\n        version: v1\n    spec:\n      serviceAccountName: bookinfo-ratings\n      containers:\n      - name: ratings\n        image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 9080\n---\n##################################################################################################\n# Reviews service\n##################################################################################################\napiVersion: v1\nkind: Service\nmetadata:\n  name: reviews\n  labels:\n    app: reviews\n    service: reviews\nspec:\n  ports:\n  - port: 9080\n    name: http\n  selector:\n    app: reviews\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: bookinfo-reviews\n  labels:\n    account: reviews\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: reviews-v1\n  labels:\n    app: reviews\n    version: v1\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: reviews\n      version: v1\n  template:\n    metadata:\n      labels:\n        app: reviews\n        version: v1\n    spec:\n      serviceAccountName: bookinfo-reviews\n      containers:\n      - name: reviews\n        image: docker.io/istio/examples-bookinfo-reviews-v1:1.15.0\n        imagePullPolicy: IfNotPresent\n        env:\n        - name: LOG_DIR\n          value: \"/tmp/logs\"\n        ports:\n        - containerPort: 9080\n        volumeMounts:\n        - name: tmp\n          mountPath: /tmp\n        - name: wlp-output\n          mountPath: /opt/ibm/wlp/output\n      volumes:\n      - name: wlp-output\n        emptyDir: {}\n      - name: tmp\n        emptyDir: {}\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: reviews-v2\n  labels:\n    app: reviews\n    version: v2\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: reviews\n      version: v2\n  template:\n    metadata:\n      labels:\n        app: reviews\n        version: v2\n    spec:\n      serviceAccountName: bookinfo-reviews\n      containers:\n      - name: reviews\n        image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0\n        imagePullPolicy: IfNotPresent\n        env:\n        - name: LOG_DIR\n          value: \"/tmp/logs\"\n        ports:\n        - containerPort: 9080\n        volumeMounts:\n        - name: tmp\n          mountPath: /tmp\n        - name: wlp-output\n          mountPath: /opt/ibm/wlp/output\n      volumes:\n      - name: wlp-output\n        emptyDir: {}\n      - name: tmp\n        emptyDir: {}\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: reviews-v3\n  labels:\n    app: reviews\n    version: v3\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: reviews\n      version: v3\n  template:\n    metadata:\n      labels:\n        app: reviews\n        version: v3\n    spec:\n      serviceAccountName: bookinfo-reviews\n      containers:\n      - name: reviews\n        image: docker.io/istio/examples-bookinfo-reviews-v3:1.15.0\n        imagePullPolicy: IfNotPresent\n        env:\n        - name: LOG_DIR\n          value: \"/tmp/logs\"\n        ports:\n        - containerPort: 9080\n        volumeMounts:\n        - name: tmp\n          mountPath: /tmp\n        - name: wlp-output\n          mountPath: /opt/ibm/wlp/output\n      volumes:\n      - name: wlp-output\n        emptyDir: {}\n      - name: tmp\n        emptyDir: {}\n---\n##################################################################################################\n# Productpage services\n##################################################################################################\napiVersion: v1\nkind: Service\nmetadata:\n  name: productpage\n  labels:\n    app: productpage\n    service: productpage\nspec:\n  ports:\n  - port: 9080\n    name: http\n  selector:\n    app: productpage\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: bookinfo-productpage\n  labels:\n    account: productpage\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: productpage-v1\n  labels:\n    app: productpage\n    version: v1\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: productpage\n      version: v1\n  template:\n    metadata:\n      labels:\n        app: productpage\n        version: v1\n    spec:\n      serviceAccountName: bookinfo-productpage\n      containers:\n      - name: productpage\n        image: docker.io/istio/examples-bookinfo-productpage-v1:1.15.0\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 9080\n        volumeMounts:\n        - name: tmp\n          mountPath: /tmp\n      volumes:\n      - name: tmp\n        emptyDir: {}\n---\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/destination-rule-all.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: DestinationRule\nmetadata:\n  name: productpage\nspec:\n  host: productpage\n  subsets:\n  - name: v1\n    labels:\n      version: v1\n---\napiVersion: networking.istio.io/v1alpha3\nkind: DestinationRule\nmetadata:\n  name: reviews\nspec:\n  host: reviews\n  subsets:\n  - name: v1\n    labels:\n      version: v1\n  - name: v2\n    labels:\n      version: v2\n  - name: v3\n    labels:\n      version: v3\n---\napiVersion: networking.istio.io/v1alpha3\nkind: DestinationRule\nmetadata:\n  name: ratings\nspec:\n  host: ratings\n  subsets:\n  - name: v1\n    labels:\n      version: v1\n  - name: v2\n    labels:\n      version: v2\n  - name: v2-mysql\n    labels:\n      version: v2-mysql\n  - name: v2-mysql-vm\n    labels:\n      version: v2-mysql-vm\n---\napiVersion: networking.istio.io/v1alpha3\nkind: DestinationRule\nmetadata:\n  name: details\nspec:\n  host: details\n  subsets:\n  - name: v1\n    labels:\n      version: v1\n  - name: v2\n    labels:\n      version: v2\n---\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/virtual-service-all-v1.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productpage\nspec:\n  hosts:\n  - productpage\n  http:\n  - route:\n    - destination:\n        host: productpage\n        subset: v1\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: reviews\nspec:\n  hosts:\n  - reviews\n  http:\n  - route:\n    - destination:\n        host: reviews\n        subset: v1\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: ratings\nspec:\n  hosts:\n  - ratings\n  http:\n  - route:\n    - destination:\n        host: ratings\n        subset: v1\n---\napiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: details\nspec:\n  hosts:\n  - details\n  http:\n  - route:\n    - destination:\n        host: details\n        subset: v1\n---\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/virtual-service-ratings-test-abort.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: ratings\nspec:\n  hosts:\n  - ratings\n  http:\n  - match:\n    - headers:\n        end-user:\n          exact: jason\n    fault:\n      abort:\n        percentage:\n          value: 100.0\n        httpStatus: 500\n    route:\n    - destination:\n        host: ratings\n        subset: v1\n  - route:\n    - destination:\n        host: ratings\n        subset: v1\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/virtual-service-ratings-test-delay.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: ratings\nspec:\n  hosts:\n  - ratings\n  http:\n  - match:\n    - headers:\n        end-user:\n          exact: jason\n    fault:\n      delay:\n        percentage:\n          value: 100.0\n        fixedDelay: 7s\n    route:\n    - destination:\n        host: ratings\n        subset: v1\n  - route:\n    - destination:\n        host: ratings\n        subset: v1\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/virtual-service-reviews-50-v3.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: reviews\nspec:\n  hosts:\n    - reviews\n  http:\n  - route:\n    - destination:\n        host: reviews\n        subset: v1\n      weight: 50\n    - destination:\n        host: reviews\n        subset: v3\n      weight: 50\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/virtual-service-reviews-test-v2.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: reviews\nspec:\n  hosts:\n    - reviews\n  http:\n  - match:\n    - headers:\n        end-user:\n          exact: jason\n    route:\n    - destination:\n        host: reviews\n        subset: v2\n  - route:\n    - destination:\n        host: reviews\n        subset: v1\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/istio/bookinfo/virtual-service-reviews-v3.yaml",
    "content": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: reviews\nspec:\n  hosts:\n    - reviews\n  http:\n  - route:\n    - destination:\n        host: reviews\n        subset: v3\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico.yaml",
    "content": "---\nkind: DaemonSet\napiVersion: apps/v1\nmetadata:\n  name: calico-node\n  namespace: kube-system\n  labels:\n    k8s-app: calico-node\nspec:\n  selector:\n    matchLabels:\n      k8s-app: calico-node\n  updateStrategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxUnavailable: 1\n  template:\n    metadata:\n      labels:\n        k8s-app: calico-node\n    spec:\n      priorityClassName: system-node-critical\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      hostNetwork: true\n      serviceAccountName: calico-node\n      # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a \"force\n      # deletion\": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods.\n      terminationGracePeriodSeconds: 0\n      containers:\n        # Runs calico/node container on each Kubernetes node.  This\n        # container programs network policy and routes on each\n        # host.\n        - name: calico-node\n          image: quay.io/calico/node:v3.8.1\n          env:\n            # Use Kubernetes API as the backing datastore.\n            - name: DATASTORE_TYPE\n              value: \"kubernetes\"\n            # Use eni not cali for interface prefix\n            - name: FELIX_INTERFACEPREFIX\n              value: \"eni\"\n            # Enable felix info logging.\n            - name: FELIX_LOGSEVERITYSCREEN\n              value: \"info\"\n            # Don't enable BGP.\n            - name: CALICO_NETWORKING_BACKEND\n              value: \"none\"\n            # Cluster type to identify the deployment type\n            - name: CLUSTER_TYPE\n              value: \"k8s,ecs\"\n            # Disable file logging so `kubectl logs` works.\n            - name: CALICO_DISABLE_FILE_LOGGING\n              value: \"true\"\n            - name: FELIX_TYPHAK8SSERVICENAME\n              value: \"calico-typha\"\n            # Set Felix endpoint to host default action to ACCEPT.\n            - name: FELIX_DEFAULTENDPOINTTOHOSTACTION\n              value: \"ACCEPT\"\n            # This will make Felix honor AWS VPC CNI's mangle table\n            # rules.\n            - name: FELIX_IPTABLESMANGLEALLOWACTION\n              value: Return\n            # Disable IPV6 on Kubernetes.\n            - name: FELIX_IPV6SUPPORT\n              value: \"false\"\n            # Wait for the datastore.\n            - name: WAIT_FOR_DATASTORE\n              value: \"true\"\n            - name: FELIX_LOGSEVERITYSYS\n              value: \"none\"\n            - name: FELIX_PROMETHEUSMETRICSENABLED\n              value: \"true\"\n            - name: NO_DEFAULT_POOLS\n              value: \"true\"\n            # Set based on the k8s node name.\n            - name: NODENAME\n              valueFrom:\n                fieldRef:\n                  fieldPath: spec.nodeName\n            # No IP address needed.\n            - name: IP\n              value: \"\"\n            - name: FELIX_HEALTHENABLED\n              value: \"true\"\n          securityContext:\n            privileged: true\n          livenessProbe:\n            httpGet:\n              path: /liveness\n              port: 9099\n              host: localhost\n            periodSeconds: 10\n            initialDelaySeconds: 10\n            failureThreshold: 6\n          readinessProbe:\n            exec:\n              command:\n                - /bin/calico-node\n                - -felix-ready\n            periodSeconds: 10\n          volumeMounts:\n            - mountPath: /lib/modules\n              name: lib-modules\n              readOnly: true\n            - mountPath: /run/xtables.lock\n              name: xtables-lock\n              readOnly: false\n            - mountPath: /var/run/calico\n              name: var-run-calico\n              readOnly: false\n            - mountPath: /var/lib/calico\n              name: var-lib-calico\n              readOnly: false\n      volumes:\n        # Used to ensure proper kmods are installed.\n        - name: lib-modules\n          hostPath:\n            path: /lib/modules\n        - name: var-run-calico\n          hostPath:\n            path: /var/run/calico\n        - name: var-lib-calico\n          hostPath:\n            path: /var/lib/calico\n        - name: xtables-lock\n          hostPath:\n            path: /run/xtables.lock\n            type: FileOrCreate\n      tolerations:\n        # Make sure calico/node gets scheduled on all nodes.\n        - effect: NoSchedule\n          operator: Exists\n        # Mark the pod as a critical add-on for rescheduling.\n        - key: CriticalAddonsOnly\n          operator: Exists\n        - effect: NoExecute\n          operator: Exists\n\n---\n\n# Create all the CustomResourceDefinitions needed for\n# Calico policy-only mode.\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: felixconfigurations.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: FelixConfiguration\n    plural: felixconfigurations\n    singular: felixconfiguration\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: ipamblocks.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: IPAMBlock\n    plural: ipamblocks\n    singular: ipamblock\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: blockaffinities.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: BlockAffinity\n    plural: blockaffinities\n    singular: blockaffinity\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: bgpconfigurations.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: BGPConfiguration\n    plural: bgpconfigurations\n    singular: bgpconfiguration\n\n---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: bgppeers.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: BGPPeer\n    plural: bgppeers\n    singular: bgppeer\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: ippools.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: IPPool\n    plural: ippools\n    singular: ippool\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: hostendpoints.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: HostEndpoint\n    plural: hostendpoints\n    singular: hostendpoint\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: clusterinformations.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: ClusterInformation\n    plural: clusterinformations\n    singular: clusterinformation\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: globalnetworkpolicies.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: GlobalNetworkPolicy\n    plural: globalnetworkpolicies\n    singular: globalnetworkpolicy\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: globalnetworksets.crd.projectcalico.org\nspec:\n  scope: Cluster\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: GlobalNetworkSet\n    plural: globalnetworksets\n    singular: globalnetworkset\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: networkpolicies.crd.projectcalico.org\nspec:\n  scope: Namespaced\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: NetworkPolicy\n    plural: networkpolicies\n    singular: networkpolicy\n\n---\n\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  name: networksets.crd.projectcalico.org\nspec:\n  scope: Namespaced\n  group: crd.projectcalico.org\n  versions:\n    - name: v1\n      served: true\n      storage: true\n  names:\n    kind: NetworkSet\n    plural: networksets\n    singular: networkset\n\n---\n\n# Create the ServiceAccount and roles necessary for Calico.\n\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: calico-node\n  namespace: kube-system\n\n---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: calico-node\nrules:\n  - apiGroups: [\"\"]\n    resources:\n      - namespaces\n      - serviceaccounts\n    verbs:\n      - get\n      - list\n      - watch\n  - apiGroups: [\"\"]\n    resources:\n      - pods/status\n    verbs:\n      - patch\n  - apiGroups: [\"\"]\n    resources:\n      - nodes/status\n    verbs:\n      - patch\n      - update\n  - apiGroups: [\"\"]\n    resources:\n      - pods\n    verbs:\n      - get\n      - list\n      - watch\n  - apiGroups: [\"\"]\n    resources:\n      - services\n    verbs:\n      - get\n  - apiGroups: [\"\"]\n    resources:\n      - endpoints\n    verbs:\n      - get\n  - apiGroups: [\"\"]\n    resources:\n      - nodes\n    verbs:\n      - get\n      - list\n      - update\n      - watch\n  - apiGroups: [\"extensions\"]\n    resources:\n      - networkpolicies\n    verbs:\n      - get\n      - list\n      - watch\n  - apiGroups: [\"networking.k8s.io\"]\n    resources:\n      - networkpolicies\n    verbs:\n      - watch\n      - list\n  - apiGroups: [\"crd.projectcalico.org\"]\n    resources:\n      - globalfelixconfigs\n      - felixconfigurations\n      - bgppeers\n      - globalbgpconfigs\n      - bgpconfigurations\n      - ippools\n      - ipamblocks\n      - globalnetworkpolicies\n      - globalnetworksets\n      - networkpolicies\n      - networksets\n      - clusterinformations\n      - hostendpoints\n    verbs:\n      - create\n      - get\n      - list\n      - update\n      - watch\n  - apiGroups: [\"crd.projectcalico.org\"]\n    resources:\n      - blockaffinities\n      - ipamblocks\n      - ipamhandles\n    verbs:\n      - get\n      - list\n      - create\n      - update\n      - delete\n  - apiGroups: [\"crd.projectcalico.org\"]\n    resources:\n      - blockaffinities\n    verbs:\n      - watch\n\n---\n\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: calico-node\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: calico-node\nsubjects:\n  - kind: ServiceAccount\n    name: calico-node\n    namespace: kube-system\n\n---\n\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: calico-typha\n  namespace: kube-system\n  labels:\n    k8s-app: calico-typha\nspec:\n  revisionHistoryLimit: 2\n  selector:\n    matchLabels:\n      k8s-app: calico-typha\n  template:\n    metadata:\n      labels:\n        k8s-app: calico-typha\n      annotations:\n        cluster-autoscaler.kubernetes.io/safe-to-evict: 'true'\n    spec:\n      priorityClassName: system-cluster-critical\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      tolerations:\n        # Mark the pod as a critical add-on for rescheduling.\n        - key: CriticalAddonsOnly\n          operator: Exists\n      hostNetwork: true\n      serviceAccountName: calico-node\n      containers:\n        - image: quay.io/calico/typha:v3.8.1\n          name: calico-typha\n          ports:\n            - containerPort: 5473\n              name: calico-typha\n              protocol: TCP\n          env:\n            # Use eni not cali for interface prefix\n            - name: FELIX_INTERFACEPREFIX\n              value: \"eni\"\n            - name: TYPHA_LOGFILEPATH\n              value: \"none\"\n            - name: TYPHA_LOGSEVERITYSYS\n              value: \"none\"\n            - name: TYPHA_LOGSEVERITYSCREEN\n              value: \"info\"\n            - name: TYPHA_PROMETHEUSMETRICSENABLED\n              value: \"true\"\n            - name: TYPHA_CONNECTIONREBALANCINGMODE\n              value: \"kubernetes\"\n            - name: TYPHA_PROMETHEUSMETRICSPORT\n              value: \"9093\"\n            - name: TYPHA_DATASTORETYPE\n              value: \"kubernetes\"\n            - name: TYPHA_MAXCONNECTIONSLOWERLIMIT\n              value: \"1\"\n            - name: TYPHA_HEALTHENABLED\n              value: \"true\"\n            # This will make Felix honor AWS VPC CNI's mangle table\n            # rules.\n            - name: FELIX_IPTABLESMANGLEALLOWACTION\n              value: Return\n          livenessProbe:\n            httpGet:\n              path: /liveness\n              port: 9098\n              host: localhost\n            periodSeconds: 30\n            initialDelaySeconds: 30\n          readinessProbe:\n            httpGet:\n              path: /readiness\n              port: 9098\n              host: localhost\n            periodSeconds: 10\n\n---\n\n# This manifest creates a Pod Disruption Budget for Typha to allow K8s Cluster Autoscaler to evict\napiVersion: policy/v1beta1\nkind: PodDisruptionBudget\nmetadata:\n  name: calico-typha\n  namespace: kube-system\n  labels:\n    k8s-app: calico-typha\nspec:\n  maxUnavailable: 1\n  selector:\n    matchLabels:\n      k8s-app: calico-typha\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: typha-cpha\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: typha-cpha\nsubjects:\n  - kind: ServiceAccount\n    name: typha-cpha\n    namespace: kube-system\n\n---\n\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: typha-cpha\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"list\"]\n\n---\n\nkind: ConfigMap\napiVersion: v1\nmetadata:\n  name: calico-typha-horizontal-autoscaler\n  namespace: kube-system\ndata:\n  ladder: |-\n    {\n      \"coresToReplicas\": [],\n      \"nodesToReplicas\":\n      [\n        [1, 1],\n        [10, 2],\n        [100, 3],\n        [250, 4],\n        [500, 5],\n        [1000, 6],\n        [1500, 7],\n        [2000, 8]\n      ]\n    }\n\n---\n\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: calico-typha-horizontal-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-app: calico-typha-autoscaler\nspec:\n  selector:\n    matchLabels:\n      k8s-app: calico-typha-autoscaler\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        k8s-app: calico-typha-autoscaler\n    spec:\n      priorityClassName: system-cluster-critical\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      containers:\n        - image: k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.1.2\n          name: autoscaler\n          command:\n            - /cluster-proportional-autoscaler\n            - --namespace=kube-system\n            - --configmap=calico-typha-horizontal-autoscaler\n            - --target=deployment/calico-typha\n            - --logtostderr=true\n            - --v=2\n          resources:\n            requests:\n              cpu: 10m\n            limits:\n              cpu: 10m\n      serviceAccountName: typha-cpha\n\n---\n\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: typha-cpha\n  namespace: kube-system\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"configmaps\"]\n    verbs: [\"get\"]\n  - apiGroups: [\"extensions\"]\n    resources: [\"deployments/scale\"]\n    verbs: [\"get\", \"update\"]\n\n---\n\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: typha-cpha\n  namespace: kube-system\n\n---\n\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: typha-cpha\n  namespace: kube-system\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: typha-cpha\nsubjects:\n  - kind: ServiceAccount\n    name: typha-cpha\n    namespace: kube-system\n\n---\n\napiVersion: v1\nkind: Service\nmetadata:\n  name: calico-typha\n  namespace: kube-system\n  labels:\n    k8s-app: calico-typha\nspec:\n  ports:\n    - port: 5473\n      protocol: TCP\n      targetPort: calico-typha\n      name: calico-typha\n  selector:\n    k8s-app: calico-typha\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/allow-ui-client.yaml",
    "content": "kind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  namespace: client \n  name: allow-ui \nspec:\n  podSelector:\n    matchLabels: {}\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              role: management-ui "
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/allow-ui.yaml",
    "content": "kind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  namespace: stars\n  name: allow-ui \nspec:\n  podSelector:\n    matchLabels: {}\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              role: management-ui "
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/backend-policy.yaml",
    "content": "kind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  namespace: stars\n  name: backend-policy\nspec:\n  podSelector:\n    matchLabels:\n      role: backend\n  ingress:\n    - from:\n        - podSelector:\n            matchLabels:\n              role: frontend\n      ports:\n        - protocol: TCP\n          port: 6379\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/backend.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: backend \n  namespace: stars\nspec:\n  ports:\n  - port: 6379\n    targetPort: 6379 \n  selector:\n    role: backend \n---\napiVersion: v1\nkind: ReplicationController\nmetadata:\n  name: backend \n  namespace: stars\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        role: backend \n    spec:\n      containers:\n      - name: backend \n        image: calico/star-probe:v0.1.0\n        imagePullPolicy: Always\n        command:\n        - probe\n        - --http-port=6379\n        - --urls=http://frontend.stars:80/status,http://backend.stars:6379/status,http://client.client:9000/status\n        ports:\n        - containerPort: 6379 "
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/client.yaml",
    "content": "kind: Namespace\napiVersion: v1\nmetadata:\n  name: client\n  labels:\n    role: client\n---\napiVersion: v1\nkind: ReplicationController\nmetadata:\n  name: client \n  namespace: client\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        role: client \n    spec:\n      containers:\n      - name: client \n        image: calico/star-probe:v0.1.0\n        imagePullPolicy: Always\n        command:\n        - probe\n        - --urls=http://frontend.stars:80/status,http://backend.stars:6379/status\n        ports:\n        - containerPort: 9000 \n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: client\n  namespace: client\nspec:\n  ports:\n  - port: 9000 \n    targetPort: 9000\n  selector:\n    role: client "
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/default-deny.yaml",
    "content": "kind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  name: default-deny\nspec:\n  podSelector:\n    matchLabels: {}"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/frontend-policy.yaml",
    "content": "kind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  namespace: stars\n  name: frontend-policy\nspec:\n  podSelector:\n    matchLabels:\n      role: frontend\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              role: client\n      ports:\n        - protocol: TCP\n          port: 80\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/frontend.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: frontend \n  namespace: stars\nspec:\n  ports:\n  - port: 80 \n    targetPort: 80 \n  selector:\n    role: frontend \n---\napiVersion: v1\nkind: ReplicationController\nmetadata:\n  name: frontend \n  namespace: stars\nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        role: frontend \n    spec:\n      containers:\n      - name: frontend \n        image: calico/star-probe:v0.1.0\n        imagePullPolicy: Always\n        command:\n        - probe\n        - --http-port=80\n        - --urls=http://frontend.stars:80/status,http://backend.stars:6379/status,http://client.client:9000/status\n        ports:\n        - containerPort: 80 "
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/management-ui.yaml",
    "content": "apiVersion: v1\nkind: Namespace\nmetadata:\n  name: management-ui \n  labels:\n    role: management-ui \n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: management-ui \n  namespace: management-ui \nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80 \n    targetPort: 9001\n  selector:\n    role: management-ui \n---\napiVersion: v1\nkind: ReplicationController\nmetadata:\n  name: management-ui \n  namespace: management-ui \nspec:\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        role: management-ui \n    spec:\n      containers:\n      - name: management-ui \n        image: calico/star-collect:v0.1.0\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 9001"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/network-policy/calico_resources/namespace.yaml",
    "content": "kind: Namespace\napiVersion: v1\nmetadata:\n  name: stars"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/resource/nginx-app/nginx-nlb.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    app: nginx\n  name: nginx-deployment\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - image: nginx\n        name: nginx\n        ports:\n        - containerPort: 80\n\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: \"service-nginx\"\n  annotations:\n        service.beta.kubernetes.io/aws-load-balancer-type: nlb\nspec:\n  selector:\n    app: nginx\n  type: LoadBalancer\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤1-准备实验环境.md",
    "content": "# 步骤1 准备实验环境\n本次workshop 需要的软件环境有 aws cli , eksctl ,kubectl,以及eks对应操作的IAM权限。\n\n1.1 安装配置 aws cli , version > 1.18.200\n\n >1.1.1 安装\n 利用pip安装\n ```bash\n pip3 install awscli --upgrade --user\n ```\n\n利用awscli-bundle安装\n [linux / macOS ](https://s3.amazonaws.com/aws-cli/awscli-bundle.zip)\n\n ```bash\n curl \"https://s3.amazonaws.com/aws-cli/awscli-bundle.zip\" -o \"awscli-bundle.zip\"\n unzip awscli-bundle.zip\n sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws\n ```\n\n >[windows 64 bit MSI installer](https://s3.amazonaws.com/aws-cli/AWSCLI64PY3.msi)\n windows 默认的安装路径在C:\\Program Files\\Amazon\\AWSCLI (64-bit version)\\\n\n ```bash\n $aws --version\n aws-cli/1.18.203 Python/3.8.2 Darwin/19.6.0 botocore/1.19.43\n ```\n\n>1.1.2 配置aws cli 角色\n\n\n```bash\n#配置aws cli的用户权限\n$aws configure\nAWS Access Key ID :\nAWS Secret Access Key :\nDefault region name:\nDefault output format [None]:\n\n#测试AK/SK是否生效\naws sts get-caller-identity\n\n#如果可以正常返回以下内容(包含account id),则表示已经正确设置角色权限\n{\n    \"Account\": \"<your account id, etc.11111111>\", \n    \"UserId\": \"AIDAIG42GHSYU2TYCMCZW\", \n    \"Arn\": \"arn:aws-cn:iam::<your account id, etc.11111111>:user/<iam user>\"\n}\n```\n\n1.2 安装eksctl (0.36.0-rc.0), kubectl (v1.18.9)\n\n* [masOS](https://github.com/weaveworks/eksctl/releases/download/0.15.0/eksctl_Darwin_amd64.tar.gz)\n* [linux](https://github.com/weaveworks/eksctl/releases/download/0.15.0/eksctl_Linux_amd64.tar.gz)\n* [windows](https://github.com/weaveworks/eksctl/releases/download/0.15.0/eksctl_Windows_amd64.zip)\n\n```bash\n#设置默认region\nexport AWS_REGION=cn-northwest-1\n\n#eksctl\n#linux/macOS\ncurl -OL \"https://github.com/weaveworks/eksctl/releases/download/0.36.0-rc.0/eksctl_$(uname -s)_amd64.tar.gz\"\ntar -zxf eksctl_$(uname -s)_amd64.tar.gz\nsudo mv ./eksctl /usr/local/bin\n\n#kubectl v1.18.9\nhttps://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html\n#macOS\ncurl -o kubectl  https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.9/2020-11- 02/bin/darwin/amd64/kubectl\n#Linux \ncurl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.9/2020-11- 02/bin/linux/amd64/kubectl\n\nchmod +x ./kubectl\nsudo mv ./kubectl /usr/local/bin\n\n```\n>检查工具的版本 eksctl (版本>=0.15.0), kubectl(版本>=1.15)\n\n```bash\n\n$eksctl version\n0.36.0-rc.0\n$kubectl version\nClient Version: version.Info{Major:\"1\", Minor:\"18+\", GitVersion:\"v1.18.9-eks-d1db3c\", GitCommit:\"d1db3c46e55f95d6a7d3e5578689371318f95ff9\", GitTreeState:\"clean\", BuildDate:\"2020-10-20T22:21:03Z\", GoVersion:\"go1.13.15\", Compiler:\"gc\", Platform:\"darwin/amd64\"}\n```\n\n\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤10-可用性-健康检查.md",
    "content": "# 步骤10 可用性-健康检查\n默认情况下，如果容器出于任何原因崩溃，Kubernetes将重新它。它使用Liveness和Readiness探针，可以将其配置识别运行状况良好的容器以向其发送流量并在需要时重启它们，保证应用程序运行健壮。\n1. Kubernetes中使用Liveness探针来了解Pod是alive or dead。Pod可能由于各种原因而处于dead状态。当Liveness探针未通过时，Kubernetes将杀死并重新创建Pod。\n2. Kubernetes中使用了Readiness探针，以了解Pod何时准备接收流量。仅当Readiness探针通过时，Pod才会从服务中接收流量。如果就绪探针失败，则不会将流量发送到Pod。\n\n\n> 本节目的\n1. 我们将了解如何定义Liveness和Readiness探针，并针对Pod的不同状态对其进行测试\n\n\n10.1 配置 Liveness Probe\n\n1. Liveness Probe determines how kubelet should check the container in order to consider whether it is healthy or not. \n2. The kubelet uses the periodSeconds field to do frequent check on the Container. \n3. The initialDelaySeconds field is used to tell kubelet that it should wait for several seconds before doing the first probe. \n4. To perform a probe, in this case, kubelet sends a HTTP GET request to the server hosting this pod and if the handler for the servers /health returns a success code, then the container is considered healthy. If the handler returns a failure code, the kubelet kills the container and restarts it.\n\n```bash\n# 部署 Liveness Probe\n\nkubectl apply -f healthchecks/liveness-app.yaml\n\n# Check status\nkubectl get pod liveness-app\nNAME           READY   STATUS    RESTARTS   AGE\nliveness-app   1/1     Running   0          6s\n\nkubectl describe pod liveness-app\nEvents:\n  Type    Reason     Age   From                                                       Message\n  ----    ------     ----  ----                                                       -------\n  Normal  Scheduled  41s   default-scheduler                                          Successfully assigned default/liveness-app to ip-192-168-14-19.cn-northwest-1.compute.internal\n  Normal  Pulling    40s   kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Pulling image \"brentley/ecsdemo-nodejs\"\n  Normal  Pulled     37s   kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Successfully pulled image \"brentley/ecsdemo-nodejs\"\n  Normal  Created    37s   kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Created container liveness\n  Normal  Started    36s   kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Started container liveness\n```\n\n### 模拟 Liveness 失败\n```bash\n# Simulate failure\nkubectl exec -it liveness-app -- /bin/kill -s SIGUSR1 1\n\n# check how liveness probe work\nkubectl describe pod liveness-app\n Type     Reason     Age                 From                                                       Message\n  ----     ------     ----                ----                                                       -------\n  Normal   Scheduled  6m6s                default-scheduler                                          Successfully assigned default/liveness-app to ip-192-168-14-19.cn-northwest-1.compute.internal\n  Warning  Unhealthy  57s (x3 over 67s)   kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Liveness probe failed: Get http://192.168.29.229:3000/health: net/http: request canceled (Client.Timeout exceeded while awaiting headers)\n  Normal   Killing    57s                 kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Container liveness failed liveness probe, will be restarted\n  Normal   Pulling    27s (x2 over 6m5s)  kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Pulling image \"brentley/ecsdemo-nodejs\"\n  Normal   Pulled     24s (x2 over 6m2s)  kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Successfully pulled image \"brentley/ecsdemo-nodejs\"\n  Normal   Created    24s (x2 over 6m2s)  kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Created container liveness\n  Normal   Started    24s (x2 over 6m1s)  kubelet, ip-192-168-14-19.cn-northwest-1.compute.internal  Started container liveness\n\nkubectl get pod liveness-app\nNAME           READY   STATUS    RESTARTS   AGE\nliveness-app   1/1     Running   1          6m26s\n\n# check logs\nkubectl logs liveness-app\nkubectl logs liveness-app --previous\n\n```\n\n10.2 配置 Readiness Probe\n```bash\n# 部署 Readiness Probe\nkubectl apply -f healthchecks/readiness-deployment.yaml\n\n# check status of pod and replicas\nkubectl get pods -l app=readiness-deployment\nNAME                                    READY   STATUS    RESTARTS   AGE\nreadiness-deployment-7d8df88986-sgtvz   1/1     Running   0          5m31s\nreadiness-deployment-7d8df88986-xxvt4   1/1     Running   0          5m31s\nreadiness-deployment-7d8df88986-zqczd   1/1     Running   0          5m31s\n\nkubectl describe deployment readiness-deployment | grep Replicas:\nReplicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable\n```\n\n### 模拟 Readiness 失败\n```bash\nkubectl exec -it <YOUR-FIRST-READINESS-POD-NAME> -- rm /tmp/healthy\n\nkubectl get pods -l app=readiness-deployment\nNAME                                    READY   STATUS    RESTARTS   AGE\nreadiness-deployment-7d8df88986-sgtvz   0/1     Running   0          6m37s\nreadiness-deployment-7d8df88986-xxvt4   1/1     Running   0          6m37s\nreadiness-deployment-7d8df88986-zqczd   1/1     Running   0          6m37s\n\n# Traffic will not be routed to the first pod in the above deployment. The ready column confirms that the readiness probe for this pod did not pass and hence was marked as not ready.\n\n# check for the replicas that are available to serve traffic when a service is pointed to this deployment.\nkubectl describe deployment readiness-deployment | grep Replicas:\nReplicas:               3 desired | 3 updated | 3 total | 2 available | 1 unavailable\n\n# Make pod recreate the /tmp/healthy file. Then the pod can pass the probe, it getting marked as ready and will begin to receive traffic again.\nkubectl exec -it <YOUR-FIRST-READINESS-POD-NAME> -- touch /tmp/healthy\nkubectl get pods -l app=readiness-deployment\nNAME                                    READY   STATUS    RESTARTS   AGE\nreadiness-deployment-7d8df88986-sgtvz   1/1     Running   0          7m30s\nreadiness-deployment-7d8df88986-xxvt4   1/1     Running   0          7m30s\nreadiness-deployment-7d8df88986-zqczd   1/1     Running   0          7m30s\n\nkubectl describe deployment readiness-deployment | grep Replicas:\nReplicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable\n```\n\n## Cleanup\n```bash\nkubectl delete -f healthchecks/liveness-app.yaml\nkubectl delete -f healthchecks/readiness-deployment.yaml\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤11-使用Calio加固EKS集群安全.md",
    "content": "# 步骤11 使用Calio加固EKS集群安全\n\nKubernetes Network Policy 网络策略是有关如何允许Pod组与彼此以及其他网络端点进行通信的规范。\nNetwork Policy资源使用标签选择Pods并定义规则，这些规则指定允许流量到选定Pods。Network policies 由Kubernetes 网络插件实现。\n默认情况下，Pods是non-isolated的, 他们接受来自任何来源的流量。通过选择了一定Pods的Network Policy，可以使得Pods可以被Isolated。\n在本节中，我们将学习使用开源工具通过网络策略来加固群集安全，保护集群资源。\n[官方文档](https://kubernetes.io/docs/concepts/services-networking/network-policies/)\n\n> 本节目的\n1. 使用Calico 在Kubernetes集群中实施网络策略，保护服务资源\n2. 使用Tigera的Secure Cloud Edition将Kubernetes网络策略与EKS的VPC安全组集成\n\n\n11.1 配置Calico\n\nApply the Calico manifest from the aws/amazon-vpc-cni-k8s GitHub project. This creates the daemon sets in the kube-system namespace.\nTaints and tolerations work together to ensure pods are not scheduled onto inappropriate nodes. Taints are applied to nodes, and the only pods that can tolerate the taint are allowed to run on those nodes.\n\n> 部署 Calico\n```bash\n # 部署 calico\n # https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/v1.6/calico.yaml\nmkdir network-policy && cd network-policy\nkubectl apply -f resource/network-policy/calico.yaml\n # wait for the calico-node daemon set to have the DESIRED number of pods in the READY state\nkubectl get daemonset calico-node --namespace=kube-system\nNAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE\ncalico-node   3         3         3       3            3           beta.kubernetes.io/os=linux   3m9s\n#\nkubectl get pods --namespace=kube-system\n```\n\n11.2 创建Policy示例\n>11.2.1创建示例应用\n\n```bash\n # create stars namespace\n # https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/namespace.yaml\ncd calico_resources\nkubectl apply -f namespace.yaml\n # create frontend and backend replication controllers and services under stars namespace\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/management-ui.yaml\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/#stars_policy_demo/create_resources.files/backend.yaml\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/frontend.yaml\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/client.yaml\n kubectl apply -f management-ui.yaml\n kubectl apply -f backend.yaml\n kubectl apply -f frontend.yaml\n kubectl apply -f client.yaml\n #检查pod 状态\n kubectl get pods --namespace=stars\n NAME             READY   STATUS    RESTARTS   AGE\n backend-lfmj5    1/1     Running   0          8m29s\n frontend-bnmvt   1/1     Running   0          8m25s\n kubectl get pods --namespace=management-ui\n NAME                  READY   STATUS    RESTARTS   AGE\n management-ui-xnp4r   1/1     Running   0          8m55s\n kubectl get pods --namespace=client\n NAME           READY   STATUS    RESTARTS   AGE\n client-9nfbq   1/1     Running   0          7s\n```\n\n> 11.2.2配置 Policy\n\n 1. By default, pods can communicate with other pods\n ```bash\n kubectl get svc -o wide -n management-ui\n ALB_INGRESS=$(kubectl get svc -n management-ui -o json | jq -r '.items[0].status.loadBalancer.ingress[].hostname')\necho ${ALB_INGRESS}\n # Visit management-ui to show the default behavior: all services being  able to reach each other.\n ```\n \n 2. Let's isolate the services from each other\n \n ```bash\n # Sample deny all policy: podSelector does not have any matchLabels, essentially blocking all the pods from accessing it\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/default-deny.yaml\n kubectl apply -n stars -f default-deny.yaml\n kubectl apply -n client -f default-deny.yaml\n # management UI cannot reach any of the nodes, so nothing shows up in the UI.\n ```\n\n3. Traffic is allowed in specific direction on a specific port\n```bash\n # allow stars namespaces pods accessed by management-ui and allow client namespaces pods accessed by management-ui\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/allow-ui.yaml\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/allow-ui-client.yaml\nkubectl apply -f allow-ui.yaml\nkubectl apply -f allow-ui-client.yaml\n # management UI can reach stars and client, shown traffic in UI, but front, backend and client pods still isolated.\n\n # allow backend pods accessed by front pods but deny directly access from client\n # allow front pods accessed by client pods\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/directional_traffic.files/backend-policy.yaml\n # wget https://eksworkshop.com/beginner/120_network-policies/calico/stars_policy_demo/directional_traffic.files/frontend-policy.yaml\nkubectl apply -f backend-policy.yaml -n stars\nkubectl apply -f frontend-policy.yaml -n stars\n # management UI can reach stars and client, shown traffic in UI, front->backend and client->front, but client->backend still blocked.\n # backend-policy. Its spec has a podSelector that selects all pods with the label role:backend, and allows ingress from all pods that have the label role:frontend and on TCP port 6379, but not the other way round. \n # frontend-policy. Its spec allows ingress from namespaces that have the label role: client on TCP port 80.\n```\n\n4. cleanup\n```bash\nkubectl delete namespace client stars management-ui\nkubectl get pods --all-namespaces\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤12-EFK日志收集.md",
    "content": "12.1 配置工作线程节点的权限\n\n获取工作线程节点Role ARN\n\n```\nSTACK_NAME=$(eksctl get nodegroup --cluster eksworkshop -o json | jq -r '.[].StackName')\nROLE_NAME=$(aws cloudformation describe-stack-resources --stack-name $STACK_NAME | jq -r '.StackResources[] | select(.ResourceType==\"AWS::IAM::Role\") | .PhysicalResourceId')\necho \"export ROLE_NAME=${ROLE_NAME}\" | tee -a ~/.bash_profile\n```\n\n创建权限Policy文件，主要是CloudWatch Logs权限\n\n```\ncat <<EoF > ./eks-fluent-bit-daemonset-policy.json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": \"logs:PutLogEvents\",\n            \"Resource\": \"arn:aws-cn:logs:*:*:log-group:*:*:*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"logs:CreateLogStream\",\n                \"logs:DescribeLogStreams\",\n                \"logs:PutLogEvents\"\n            ],\n            \"Resource\": \"arn:aws-cn:logs:*:*:log-group:*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n             \"Action\": [\n                \"logs:CreateLogGroup\",\n                \"logs:DescribeLogGroups\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}\nEoF\n```\n为工作线程节点Role增加CloudWatch Logs权限\n\n```\naws iam put-role-policy --role-name $ROLE_NAME \\\n--policy-name Logs-Policy-For-Worker \\\n--policy-document file://./eks-fluent-bit-daemonset-policy.json\n```\n\n查看Policy是否已附加到工作线程节点Role\n\n```\naws iam get-role-policy --role-name $ROLE_NAME \\\n--policy-name Logs-Policy-For-Worker\n```\n12.2 创建Amazon Elasticsearch Service\n\n使用CLI命令行创建一个包含2节点的Elasticsearch Domain\n\n```\naws es create-elasticsearch-domain \\\n  --domain-name kubernetes-logs \\\n  --elasticsearch-version 7.4 \\\n  --elasticsearch-cluster-config \\\n  InstanceType=m5.large.elasticsearch,InstanceCount=2 \\\n  --ebs-options EBSEnabled=true,VolumeType=standard,VolumeSize=100 \\\n  --access-policies '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"es:*\"],\"Resource\":\"*\"}]}'\n```\n查看Elasticsearch Domian创建状态\n\n```\naws es describe-elasticsearch-domain --domain-name kubernetes-logs \\\n--query 'DomainStatus.Processing'\n```\n\n12.3 部署Fluent-bit\n\n下载Fluent-bit.yml文件\n\n```\nwget https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/resource/efk/fluent-bit.yaml\n```\n部署Fluent-bit\n\n```\nkubectl apply -f ./fluent-bit.yaml\n```\n观察Fluentd Pod状态，直到其处于Running状态\n\n```\nkubectl get pods -w\n```\n通过查看日志，验证 Fluent Bit 守护程序集：\n\n```\nkubectl logs ds/fluentbit\n```\n参考输出\n```\nFound 2 pods, using pod/fluentbit-lq6qb\ntput: No value for $TERM and no -T specified\ntput: No value for $TERM and no -T specified\nAWS for Fluent Bit Container Image Version 2.3.0\ntput: No value for $TERM and no -T specified\nFluent Bit v1.4.2\n* Copyright (C) 2019-2020 The Fluent Bit Authors\n* Copyright (C) 2015-2018 Treasure Data\n* Fluent Bit is a CNCF sub-project under the umbrella of Fluentd\n* https://fluentbit.io\n\n[2020/04/12 14:57:09] [ info] [storage] version=1.0.3, initializing...\n[2020/04/12 14:57:09] [ info] [storage] in-memory\n[2020/04/12 14:57:09] [ info] [storage] normal synchronization mode, checksum disabled, max_chunks_up=128\n[2020/04/12 14:57:09] [ info] [engine] started (pid=1)\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter log_group = 'fluent-bit-cloudwatch'\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter log_stream_prefix = 'from-fluent-bit-'\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter log_stream = ''\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter region = 'cn-northwest-1'\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter log_key = ''\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter role_arn = ''\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter auto_create_group = 'true'\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter endpoint = ''\\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter credentials_endpoint = \\n\"\ntime=\"2020-04-12T14:57:09Z\" level=info msg=\"[cloudwatch 0] plugin parameter log_format = ''\\n\"\n[2020/04/12 14:57:09] [ info] [sp] stream processor started\n```\n12.4 将CloudWatch Logs流式传输到Elasticsearch\n\n创建传输过程中使用的Lambda附加的Role:*lambda_basic\\_execution*\n\n```\ncat <<EoF > ~/efk/lambda-policy.json\n{\n   \"Version\": \"2012-10-17\",\n   \"Statement\": [\n   {\n     \"Effect\": \"Allow\",\n     \"Principal\": {\n        \"Service\": \"lambda.amazonaws.com\"\n     },\n   \"Action\": \"sts:AssumeRole\"\n   }\n ]\n}\nEoF\naws iam create-role --role-name lambda_basic_execution --assume-role-policy-document file://~/lambda-policy.json\naws iam attach-role-policy --role-name lambda_basic_execution --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\n```\n为lambda_basic_execution增加Elasticsarch相关权限\n\n注意：需要将'Resource'修改为新建的Elasticsearch Domain的ARN\n\n```\ncat <<EoF > ./lambda-es-policy.json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Action\": [\n                \"es:*\"\n            ],\n            \"Effect\": \"Allow\",\n            \"Resource\": \"arn:aws-cn:es:region:account-id:domain/target-domain-name/*\"\n        }\n    ]\n}\nEoF\naws iam put-role-policy --role-name lambda_basic_execution --policy-name lambda-es-policy --policy-document file://./lambda-es-policy.json\naws iam get-role-policy --role-name lambda_basic_execution --policy-name lambda-es-policy\n```\n\n登陆AWS Console进行操作，选择log group: fluent-bit-cloudwatch\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk1.png)\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk2.png)\n选择Elasticsearch Cluster *kubernetes-logs* 和IAM Role *lambda_basic\\_execution*\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk3.png)\n选择*Comm log Format*\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk4.png)\n查看所有配置，点击*Start Streaming*\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk5.png)\n打开Lambda函数界面，选择函数*LogsToElasticsearch_kubernetes-logs*，修改正文中\n*function buildRequest*中的*var endpointParts*\n\n```\nvar endpointParts = endpoint.match(/^([^\\.]+)\\.?([^\\.]*)\\.?([^\\.]*)\\.amazonaws\\.com$/);\n修改为：\nvar endpointParts = endpoint.match(/^([^\\.]+)\\.?([^\\.]*)\\.?([^\\.]*)\\.amazonaws\\.com\\.cn$/);\n\n```\n打开Elasticsearch界面，选择*kubernetes-logs*\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk6.png)\n打开Kibana URL，几分钟后，ES中将会采集到数据。\n<br>将索引规则设置为 *cwl-**\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk7.png)\n下拉菜单中选择*@timestamp*，并创建索引规则\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk8.png)\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk9.png)\n点击发现，以探索日志\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/efk10.png)\n\n12.5 清理环境\n```\nkubectl delete -f ./fluentd.yml\naws es delete-elasticsearch-domain --domain-name kubernetes-logs\naws logs delete-log-group --log-group-name /eks/eksworkshop/containers\n```\n\n\n\n\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤13-Prometheus&Grafana监控.md",
    "content": "13.1 前提条件\n\n检查Helm是否已安装\n\n```\nhelm list\n```\n如未安装Helm，请参照\" 步骤9-使用Helm部署应用/9.1 Install Helm \"安装Helm，并添加stable repository\n\n```\nhelm repo add stable https://burdenbear.github.io/kube-charts-mirror/\n```\n13.2 部署Prometheus\n\n安装Prometheus\n\n```\nkubectl create namespace prometheus\nhelm install prometheus stable/prometheus \\\n    --namespace prometheus \\\n    --set alertmanager.persistentVolume.storageClass=\"gp2\" \\\n    --set server.persistentVolume.storageClass=\"gp2\"\n```\n留意Prometheus endpoint，后续步骤会使用到\n\n```\nThe Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:\nprometheus-server.prometheus.svc.cluster.local\n```\n查看Prometheus组件是否部署成功\n\n```\nkubectl get all -n prometheus\n\n```\n参考输出，所有组件应该是Running或Available状态\n\n```\nNAME                                                 READY     STATUS    RESTARTS   AGE\npod/prometheus-alertmanager-77cfdf85db-s9p48         2/2       Running   0          1m\npod/prometheus-kube-state-metrics-74d5c694c7-vqtjd   1/1       Running   0          1m\npod/prometheus-node-exporter-6dhpw                   1/1       Running   0          1m\npod/prometheus-node-exporter-nrfkn                   1/1       Running   0          1m\npod/prometheus-node-exporter-rtrm8                   1/1       Running   0          1m\npod/prometheus-pushgateway-d5fdc4f5b-dbmrg           1/1       Running   0          1m\npod/prometheus-server-6d665b876-dsmh9                2/2       Running   0          1m\n\nNAME                                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE\nservice/prometheus-alertmanager         ClusterIP   10.100.89.154    <none>        80/TCP     1m\nservice/prometheus-kube-state-metrics   ClusterIP   None             <none>        80/TCP     1m\nservice/prometheus-node-exporter        ClusterIP   None             <none>        9100/TCP   1m\nservice/prometheus-pushgateway          ClusterIP   10.100.136.143   <none>        9091/TCP   1m\nservice/prometheus-server               ClusterIP   10.100.151.245   <none>        80/TCP     1m\n\nNAME                                      DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE\ndaemonset.apps/prometheus-node-exporter   3         3         3         3            3           <none>          1m\n\nNAME                                            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps/prometheus-alertmanager         1         1         1            1           1m\ndeployment.apps/prometheus-kube-state-metrics   1         1         1            1           1m\ndeployment.apps/prometheus-pushgateway          1         1         1            1           1m\ndeployment.apps/prometheus-server               1         1         1            1           1m\n\nNAME                                                       DESIRED   CURRENT   READY     AGE\nreplicaset.apps/prometheus-alertmanager-77cfdf85db         1         1         1         1m\nreplicaset.apps/prometheus-kube-state-metrics-74d5c694c7   1         1         1         1m\nreplicaset.apps/prometheus-pushgateway-d5fdc4f5b           1         1         1         1m\nreplicaset.apps/prometheus-server-6d665b876                1         1         1         1m\n\n```\n\n创建NodePort类型的Service，用于访问Prometheus\n\n```\ncat << EOF > ./prometheus-service.yml\napiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app: prometheus\n    chart: prometheus-11.0.4\n    component: server\n    heritage: Helm\n    release: prometheus\n  name: prometheus-nginx\n  namespace: prometheus\nspec:\n  ports:\n  - port: 9090\n    protocol: TCP\n    targetPort: 9090\n  selector:\n    app: prometheus\n    component: server\n    release: prometheus\n  type: ClusterIP\nEOF\n\nkubectl apply -f prometheus-service.yml\n```\n通过Kube-proxy访问Prometheus\n\n```\nkubectl proxy --port=8080 --address='0.0.0.0' --disable-filter=true\n```\n打开浏览器，将\\<localhost>替换为本机ip，访问Prometheus\n\n```\nhttp://<localhost>:8080/api/v1/namespaces/prometheus/services/prometheus-nginx/proxy/graph\n\n```\n依次选择Status/Targets，在UI中查看Prometheus监控的所有对象和指标\n\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/prometheus1.png)\n\n13.3 部署Grafana\n\n在部署参数中，将datasource指向Prometheus，并为Grafana创建LoadBalancer\n\n```\nkubectl create namespace grafana\nhelm install grafana stable/grafana \\\n    --namespace grafana \\\n    --set persistence.storageClassName=\"gp2\" \\\n    --set adminPassword='EKS!sAWSome' \\\n    --set datasources.\"datasources\\.yaml\".apiVersion=1 \\\n    --set datasources.\"datasources\\.yaml\".datasources[0].name=Prometheus \\\n    --set datasources.\"datasources\\.yaml\".datasources[0].type=prometheus \\\n    --set datasources.\"datasources\\.yaml\".datasources[0].url=http://prometheus-server.prometheus.svc.cluster.local \\\n    --set datasources.\"datasources\\.yaml\".datasources[0].access=proxy \\\n    --set datasources.\"datasources\\.yaml\".datasources[0].isDefault=true \\\n    --set service.type=LoadBalancer\n```\n查看Grafana是否部署成功\n\n```\nkubectl get all -n grafana\n\n```\n参考输出，所有组件应该是Running或Available状态\n\n```\nNAME                          READY     STATUS    RESTARTS   AGE\npod/grafana-b9697f8b5-t9w4j   1/1       Running   0          2m\n\nNAME              TYPE           CLUSTER-IP       EXTERNAL-IP                                                               PORT(S)        AGE\nservice/grafana   LoadBalancer   10.100.49.172   abe57f85de73111e899cf0289f6dc4a4-1343235144.us-west-2.elb.amazonaws.com   80:31570/TCP   3m\n\n\nNAME                      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps/grafana   1         1         1            1           2m\n\nNAME                                DESIRED   CURRENT   READY     AGE\nreplicaset.apps/grafana-b9697f8b5   1         1         1         2m\n\n```\n获取Grafana ELB URL，将输出复制粘贴到浏览器中进行访问\n\n```\nexport ELB=$(kubectl get svc -n grafana grafana -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')\n\necho \"http://$ELB\"\n```\n使用用户名admin和如下命令获取的password hash登陆\n\n```\nkubectl get secret --namespace grafana grafana -o jsonpath=\"{.data.admin-password}\" | base64 --decode ; echo\n```\n13.4 查看监控面板\n\n13.4.1 创建集群监控面板\n\n* 左侧面板点击' + '，选择' Import  '\n* Grafana.com Dashboard下输入3119\n* prometheus data source下拉框中选择prometheus\n* 点击' Import  '\n\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/prometheus2.png)\n\n查看所有集群节点的监控面板\n\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/prometheus3.png)\n\n13.4.2 创建Pods监控面板\n\n* 左侧面板点击' + '，选择' Import  '\n* Grafana.com Dashboard下输6417\n*  输入Kubernetes Pods Monitoring作为Dashboard名称\n*  点击change，设置uid\n* prometheus data source下拉框中选择prometheus\n* 点击' Import  '\n\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/prometheus4.png)\n\n查看Pods的监控面板\n\n![avatar](https://github.com/toreydai/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/media/Pictures/prometheus5.png)\n\n13.5 清理环境\n\n```\nhelm uninstall prometheus --namespace prometheus\nhelm uninstall grafana --namespace grafana\nkubectl delete namespace prometheus\nkubectl delete namespace grafana\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤14-在EKS集群上部署Istio服务网格.md",
    "content": "# 步骤14 在 EKS 集群上部署 Istio 服务网格\n\n服务网格用来描述组成应用程序的微服务网络以及它们之间的交互。随着服务网格的规模和复杂性不断的增长，它将会变得越来越难以理解和管理。它的需求包括服务发现、负载均衡、故障恢复、度量和监控等。服务网格通常还有更复杂的运维需求，比如 A/B 测试、金丝雀发布、速率限制、访问控制和端到端认证。\nIstio 是一个完全开源的服务网格，作为透明的一层接入到现有的分布式应用程序里。它也是一个平台，拥有可以集成任何日志、遥测和策略系统的 API 接口。 Istio 允许您连接、保护、控制和观察服务。\n在本节中，我们将学习使用 Istio 来构建服务网格，控制服务之间的流量和 API 调用过程。\n[官方文档](https://istio.io/)\n\n> 本节目的\n1. 使用 Istio 在 Kubernetes 集群中实施服务网格，实现服务之间的流量管理\n\n\n14.1 部署 Istio\n\n> 下载 istioctl\n```bash\n# 下载 istioctl，本 Workshop 使用 1.5.1\n# https://github.com/istio/istio/releases/\nmkdir istio && cd istio\necho 'export ISTIO_VERSION=\"1.5.1\"' >> ~/.bash_profile\nsource ~/.bash_profile\n\n# 下载并安装 istioctl -option 1\ncurl -L https://istio.io/downloadIstio | sh -\nsudo cp -v bin/istioctl /usr/local/bin/\n\n# 下载并安装 istioctl -option 2\n# 也可以下载对应的安装包解压安装，此处以 osx 为例 https://github.com/istio/istio/releases/\nwget https://github.com/istio/istio/releases/download/1.5.1/istioctl-1.5.1-osx.tar.gz | tar xzvf\nchmod +x ./istioctl && mv istioctl ~/bin/\n\n# 验证\nistioctl version --remote=false\n```\n\n\n> 部署 istio\n```bash\n# 部署 istio\n# 使用 --set profile=demo 部署所有模块\nistioctl manifest apply --set profile=demo\n- Applying manifest for component Base...\n✔ Finished applying manifest for component Base.\n- Applying manifest for component Pilot...\n✔ Finished applying manifest for component Pilot.\n  Waiting for resources to become ready...\n  Waiting for resources to become ready...\n  Waiting for resources to become ready...\n- Applying manifest for component IngressGateways...\n- Applying manifest for component EgressGateways...\n- Applying manifest for component AddonComponents...\n✔ Finished applying manifest for component EgressGateways.\n✔ Finished applying manifest for component IngressGateways.\n✔ Finished applying manifest for component AddonComponents.\n\n✔ Installation complete\n\n# 验证，等待 istio pod 全部处于 READY 状态\nkubectl -n istio-system get svc\nkubectl -n istio-system get pods\ngrafana-556b649566-2gb5d                1/1     Running   0          59m\nistio-egressgateway-65949b978b-vbmg4    1/1     Running   0          59m\nistio-ingressgateway-7c76987989-2g9vn   1/1     Running   0          59m\nistio-tracing-7cf5f46848-s5pcb          1/1     Running   0          59m\nistiod-5bb7dddbd8-n84hc                 1/1     Running   0          59m\nkiali-6d54b8ccbc-v8zgb                  1/1     Running   0          59m\nprometheus-b47d8c58c-bvmr5              2/2     Running   0          59m\n```\n\n14.2 部署 Bookinfo 示例应用\n>14.2.1 创建示例应用\n\n```bash\n# 创建 bookinfo 命名空间\nkubectl create namespace bookinfo\n\n# 启用 Istio sidecar 自动注入\nkubectl label namespace bookinfo istio-injection=enabled\nkubectl get ns bookinfo --show-labels\nNAME       STATUS   AGE    LABELS\nbookinfo   Active   4h8m   istio-injection=enabled\n\n# 删除 image mirror webhook 并重新部署，以便自动映射 sidecar image 为中国区镜像\nkubectl delete -f https://raw.githubusercontent.com/nwcdlabs/container-mirror/master/webhook/mutating-webhook.yaml\nkubectl apply -f https://raw.githubusercontent.com/nwcdlabs/container-mirror/master/webhook/mutating-webhook.yaml\n\n# 部署 bookinfo 示例应用\ncd istio/bookinfo\nkubectl apply -f bookinfo.yaml -n bookinfo\n# 等待所有 pod 正常运行\nNAME                              READY   STATUS    RESTARTS   AGE\ndetails-v1-74f858558f-mc9gn       2/2     Running   0          3h43m\nproductpage-v1-76589d9fdc-vm6fl   2/2     Running   0          3h43m\nratings-v1-7855f5bcb9-nvfr9       2/2     Running   0          3h43m\nreviews-v1-64bc5454b9-9dsdt       2/2     Running   0          3h43m\nreviews-v2-76c64d4bdf-5bqfg       2/2     Running   0          3h43m\nreviews-v3-5545c7c78f-5c456       2/2     Running   0          3h42m\n\n# 为 bookinfo 部署 gateway\nkubectl apply -f bookinfo-gateway.yaml -n bookinfo\n# 验证访问 bookinfo 页面\nGATEWAY_URL=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') && echo \"http://${GATEWAY_URL}/productpage\"\nhttp://ac998a6336e9643bbaac93de0e0fcde2-1154939131.cn-north-1.elb.amazonaws.com.cn/productpage\n```\n\n> 14.2.2 配置流量管理策略\n\n1. 为 bookinfo 中的所有服务创建默认 destination rules\n ```bash\n# 创建 default destination rules\nkubectl apply -f destination-rule-all.yaml -n bookinfo\n\n# 查看 destination rules\nkubectl get destinationrules -n bookinfo\nNAME          HOST          AGE\ndetails       details       3h3m\nproductpage   productpage   3h3m\nratings       ratings       3h3m\nreviews       reviews       3h3m\n\n# 刷新 bookinfo 页面，可以看到随机显示三个版本的 Book Reviews：无星、黑色星形评价、红色星形评价\n\n ```\n \n2. 创建 Virtual Service，将所有流量指向 reviews:v1\n \n ```bash\n # 创建 Virtual Service\n kubectl apply -f virtual-service-all-v1.yaml -n bookinfo\n \n # 刷新 bookinfo 页面，可以看到当前只显示一个版本的 Book Reviews：无星\n\n ```\n\n3. 修改 Virtual Service，将用户 jason 的流量指向 reviews:v2，其他用户仍然指向 reviews:v1\n```bash\n # 修改 Virtual Service\nkubectl apply -f virtual-service-reviews-test-v2.yaml -n bookinfo\n\n# 刷新 bookinfo 页面，点击 Sign in 并以 jason 登录可以显示 reviews:v2（黑色星形评价），登出之后或者以其他用户登录仍然显示 reviews:v1（无星）\n\n```\n\n4. 修改 Virtual Service，为用户 jason 的流量注入 7s 的延迟\n```bash\n # 修改 Virtual Service\nkubectl apply -f virtual-service-ratings-test-delay.yaml -n bookinfo\n\n# 刷新 bookinfo 页面，点击 Sign in 并以 jason 登录可以看到获取 review 超时，登出之后或者以其他用户登录仍然显示 reviews:v1（无星）\n# productpage 和 reviews 服务间的超时总时间为 6s（3s + 1次重试）\n\n```\n\n5. 修改 Virtual Service，对用户 jason 的流量做 HTTP abort\n```bash\n # 修改 Virtual Service\nkubectl apply -f virtual-service-ratings-test-abort.yaml -n bookinfo\n\n# 刷新 bookinfo 页面，点击 Sign in 并以 jason 登录可以看到页面立即显示 Ratings service is currently unavailable，登出之后或者以其他用户登录仍然显示 reviews:v1（无星）\n\n```\n\n6. 修改 Virtual Service，实现流量灰度迁移\n```bash\n# 修改 Virtual Service，将所有流量指向 reviews:v1\nkubectl apply -f virtual-service-all-v1.yaml -n bookinfo\n# 刷新 bookinfo 页面，可以看到当前只显示一个版本的 Book Reviews：无星\n\n# 修改 Virtual Service，将 50% 流量指向 reviews:v3\nkubectl apply -f virtual-service-reviews-50-v3.yaml -n bookinfo\n# 刷新 bookinfo 页面，可以看到有一半的概率显示 reviews:v1（无星） 和 reviews:v3（红色星形评价）\n\n# 修改 Virtual Service，将所有流量指向 reviews:v3\nkubectl apply -f virtual-service-reviews-v3.yaml -n bookinfo\n# 刷新 bookinfo 页面，可以看到当前只显示一个版本的 Book Reviews：reviews:v3（红色星形评价）\n\n```\n\n> 14.2.3 cleanup\n```bash\n# Namespace 及所有相关资源\nkubectl delete namespace bookinfo\n\n# istioctl 删除所有 rbac 权限、istio-system namespace 及相关资源\nistioctl manifest generate --set profile=demo | kubectl delete -f -\ncd istio\n\n# 删除安装时下载的 istio 目录，清除 ~/.bash_profile\nrm -rf istio-${ISTIO_VERSION}\nsed -i '/ISTIO_VERSION/d' ~/.bash_profile\nunset ISTIO_VERSION\n\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤2-创建EKS集群.md",
    "content": "# 步骤2 创建EKS集群\n\n2.1 使用eksctl 创建EKS集群(操作需要10-15分钟),该命令同时会创建一个使用t3.small的受管节点组。\n\n详细参考手册\n* [creating-and-managing-clusters](https://eksctl.io/usage/creating-and-managing-clusters/)\n* [managing-nodegroups](https://eksctl.io/usage/managing-nodegroups/)\n\n\n ```bash\n #环境变量\n #CLUSTER_NAME 集群名称\n #AWS_REGION cn-northwest-1：宁夏区； cn-north-1：北京区\n\n export AWS_REGION=cn-northwest-1\n export CLUSTER_NAME=eksworkshop\n\n #参数说明\n #--node-type 工作节点类型 默认为m5.large\n #--nodes 工作节点数量 默认为2\n \neksctl create cluster --name=${CLUSTER_NAME} --node-type t3.medium --managed --alb-ingress-access --region=${AWS_REGION}\n\n ```\n\n参考输出\n ```bash\n [ℹ]  eksctl version 0.15.0\n [ℹ]  using region cn-northwest-1\n [ℹ]  setting availability zones to [cn-northwest-1b cn-northwest-1a cn-northwest-1c]\n [ℹ]  subnets for cn-northwest-1b - public:192.168.0.0/19 private:192.168.96.0/19\n [ℹ]  subnets for cn-northwest-1a - public:192.168.32.0/19 private:192.168.128.0/19\n [ℹ]  subnets for cn-northwest-1c - public:192.168.64.0/19 private:192.168.160.0/19\n [ℹ]  using Kubernetes version 1.14\n [ℹ]  creating EKS cluster \"eksworkshop\" in \"cn-northwest-1\" region with managed nodes\n [ℹ]  will create 2 separate CloudFormation stacks for cluster itself and the initial managed nodegroup\n [ℹ]  if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=cn-northwest-1 --cluster=eksworkshop'\n [ℹ]  CloudWatch logging will not be enabled for cluster \"eksworkshop\" in \"cn-northwest-1\"\n [ℹ]  you can enable it with 'eksctl utils update-cluster-logging --region=cn-northwest-1 --cluster=eksworkshop'\n [ℹ]  Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster \"eksworkshop\" in \"cn-northwest-1\"\n [ℹ]  2 sequential tasks: { create cluster control plane \"eksworkshop\", create managed nodegroup \"ng-f6ef3930\" }\n [ℹ]  building cluster stack \"eksctl-eksworkshop-cluster\"\n [ℹ]  deploying stack \"eksctl-eksworkshop-cluster\"\n [ℹ]  building managed nodegroup stack \"eksctl-eksworkshop-nodegroup-ng-f6ef3930\"\n [ℹ]  deploying stack \"eksctl-eksworkshop-nodegroup-ng-f6ef3930\"\n [✔]  all EKS cluster resources for \"eksworkshop\" have been created\n [✔]  saved kubeconfig as \"/Users/ec2-user/.kube/config\"\n [ℹ]  nodegroup \"ng-f6ef3930\" has 2 node(s)\n [ℹ]  node \"ip-192-168-14-19.cn-northwest-1.compute.internal\" is ready\n [ℹ]  node \"ip-192-168-40-132.cn-northwest-1.compute.internal\" is ready\n [ℹ]  waiting for at least 2 node(s) to become ready in \"ng-f6ef3930\"\n [ℹ]  nodegroup \"ng-f6ef3930\" has 2 node(s)\n [ℹ]  node \"ip-192-168-14-19.cn-northwest-1.compute.internal\" is ready\n [ℹ]  node \"ip-192-168-40-132.cn-northwest-1.compute.internal\" is ready\n [ℹ]  kubectl command should work with \"/Users/ruiliang/.kube/config\", try 'kubectl get nodes'\n [✔]  EKS cluster \"eksworkshop\" in \"cn-northwest-1\" region is ready\n\n ```\n\n  集群创建完毕后,查看EKS集群工作节点\n  ```bash\n   kubectl get node\n  ```\n\n  参考输出\n ```bash\n NAME                                                STATUS   ROLES    AGE    VERSION\nip-192-168-14-19.cn-northwest-1.compute.internal    Ready    <none>   4d1h   v1.14.9-eks-1f0ca9\nip-192-168-40-132.cn-northwest-1.compute.internal   Ready    <none>   4d1h   v1.14.9-eks-1f0ca9\n\n ```\n\n（可选）使用配置文件创建eksworkshop 集群\n\n```bash\n\n```\n\n\n\n\n\n（可选）配置环境变量用于后续使用\n\n```bash\nSTACK_NAME=$(eksctl get nodegroup --cluster ${CLUSTER_NAME} --region=${AWS_REGION} -o json | jq -r '.[].StackName')\necho $STACK_NAME\nROLE_NAME=$(aws cloudformation describe-stack-resources --stack-name $STACK_NAME --region=${AWS_REGION} | jq -r '.StackResources[] | select(.ResourceType==\"AWS::IAM::Role\") | .PhysicalResourceId')\necho $ROLE_NAME\nexport ROLE_NAME=${ROLE_NAME}\nexport STACK_NAME=${STACK_NAME}\n```\n\n2.2 部署一个nginx测试eks集群基本功能\n\n> 下载本git repository, 参考 resource/nginx-app目录的nginx-nlb.yaml, 创建一个nginx pod，并通过LoadBalancer类型对外暴露\n *特别提醒80/443 在AWS China Region需要完成备案流程，请联系你的商业经理确保已开通，或者自行更改nginx-nlb.yaml的端口\n\n```bash\nkubectl apply -f resource/nginx-app/nginx-nlb.yaml \n\n## Check deployment status\nkubectl get pods\nkubectl get deployment nginx-deployment \n\n## Get the external access 确保 EXTERNAL-IP是一个有效的AWS Network Load Balancer的地址\nkubectl get service service-nginx -o wide \n\n## 下面可以试着访问这个地址\nELB=$(kubectl get service service-nginx -o json | jq -r '.status.loadBalancer.ingress[].hostname')\ncurl -m3 -v $ELB\n```\n\n> 清理\n```bash\nkubectl delete -f nginx-nlb.yaml \n```\n\n2.3 扩展集群节点\n> 我们之前通过eksctl创建了一个2节点的集群，下面我们来扩展集群节点到3\n```bash\nNODE_GROUP=$(eksctl get nodegroup --cluster ${CLUSTER_NAME} --region=${AWS_REGION} -o json | jq -r '.[].Name')\neksctl scale nodegroup --cluster=${CLUSTER_NAME} --nodes=3 --name=${NODE_GROUP} --region=${AWS_REGION}\n```\n> 检查结果\n```bash\neksctl get nodegroup --cluster ${CLUSTER_NAME} --region=${AWS_REGION}\nkubectl get node\n```\n\n参考输出\n```bash\nCLUSTER\t\t\tNODEGROUP\tCREATED\t\t\tMIN SIZE\tMAX SIZE\tDESIRED CAPACITY\tINSTANCE TYPE\tIMAGE ID\neksworkshop\tng-f6ef3930\t2020-03-03T08:09:39Z\t2\t\t3\t\t3\t\t\tt3.medium\n\nNAME                                                STATUS   ROLES    AGE    VERSION\nip-192-168-14-19.cn-northwest-1.compute.internal    Ready    <none>   4d1h   v1.14.9-eks-1f0ca9\nip-192-168-40-132.cn-northwest-1.compute.internal   Ready    <none>   4d1h   v1.14.9-eks-1f0ca9\nip-192-168-86-36.cn-northwest-1.compute.internal    Ready    <none>   3d4h   v1.14.9-eks-1f0ca9\n```\n\n2.4  中国区镜像处理\n\n  由于防火墙或安全限制，海外gcr.io, quay.io的镜像可能无法下载，为了不手动修改原始yaml文件的镜像路径，可以使用 [amazon-api-gateway-mutating-webhook-for-k8](https://github.com/aws-samples/amazon-api-gateway-mutating-webhook-for-k8) 项目实现镜像自动映射,  本workshop所需要的镜像已经由nwcdlabs/container-mirror准备好了，直接部署MutatingWebhookConfiguration即可。\n\n1. 部署webhook配置文件\n```bash\nkubectl apply -f https://raw.githubusercontent.com/nwcdlabs/container-mirror/master/webhook/mutating-webhook.yaml\n```\n\n2. 部署样例应用，验证webhook工作正常\n\n```bash\nkubectl apply -f ./nginx-gcr.yaml\nkubectl get pods\nkubectl get pod nginx-gcr-deployment-xxxx -o=jsonpath='{.spec.containers[0].image}'\n# 结果应显示为配置的gcr.io的路径\n# 清理\nkubectl delete -f ./nginx-gcr.yaml\n```\n\n注意：China region EKS service 有2个官方的账号id, cn-northwest-1 961992271922, cn-north-1 91830976355，因此如果你需要下载EKS 官方的镜像，需要正确使用上面的两个id\n```bash\n#例如宁夏区\n#aws-efs-csi-driver\n961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/aws-efs-csi-driver\n\n#aws-ebs-csi-driver\n961992271922.dkr.ecr.cn-northwest-1.amazonaws.com.cn/eks/aws-ebs-csi-driver\n```\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤3-部署官方的KubernetesDashboard.md",
    "content": "# 步骤3 部署官方的Kubernetes dashboard\n\n3.1 下载配置文件\n\n```bash\n# 如果采用了2.4 中的镜像webhook，直接进行部署，否则需要修改kubernetes-dashboard.yaml中镜像位置为国内Mirror，否则部署会因为Image无法下载而失败\nkubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml\nkubectl get pods -n kube-system\nkubectl get services -n kube-system\n\n#由于我们部署的EKS cluster是private cluster，所以我们需要通过 proxy. Kube-proxy进行访问Dashboard\nkubectl proxy --port=8080 --address='0.0.0.0' --disable-filter=true &\n\n#访问\nhttp://localhost:8080//api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login\n\n#获取登录的token\naws eks get-token --cluster-name ${CLUSTER_NAME} --region ${AWS_REGION} | jq -r '.status.token'\n\n#登录\n选择 Dashbaord 登录页面的 “Token” 单选按钮，复制上述命令的输出，粘贴，之后点击 Sign In。\n```\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤4-部署微服务以及配置ALBIngressController.md",
    "content": "# 步骤4 部署微服务以及配置ALB Ingress Controller\n\n4.1 参考 eksworkshop的样例，部署微服务 (可选)\n* [eksworkshop的样例微服务] (https://eksworkshop.com/beginner/050_deploy/)\n\n> 4.1.1 下载样例\n```bash\n## Ruby Frontend\ngit clone https://github.com/brentley/ecsdemo-frontend.git\n## NodeJS Backend and crystal backend\ngit clone https://github.com/brentley/ecsdemo-nodejs.git\ngit clone https://github.com/brentley/ecsdemo-crystal.git\n```\n\n> 4.1.2 部署后台\n```bash\n cd ecsdemo-nodejs \n kubectl apply -f kubernetes/deployment.yaml\n kubectl apply -f kubernetes/service.yaml\n # 检查部署是否正确\n kubectl get deployment ecsdemo-nodejs\n #\n cd ../ecsdemo-crystal\n kubectl apply -f kubernetes/deployment.yaml\n kubectl apply -f kubernetes/service.yaml\n # 检查部署是否正确\n kubectl get deployment ecsdemo-crystal\n```\n\n> 4.1.3 部署前台\n```bash\n # 检查ELB Service Role以及在您的账号下创建，如果没有创建，请参考AWS文档进行创建\n aws iam get-role --role-name \"AWSServiceRoleForElasticLoadBalancing\" --region ${AWS_REGION}\n # 部署\n cd ../ecsdemo-frontend\n kubectl apply -f kubernetes/deployment.yaml\n kubectl apply -f kubernetes/service.yaml\n kubectl get deployment ecsdemo-frontend\n # 检查状态\n kubectl get service ecsdemo-frontend -o wide\n # 访问前端服务\n ELB=$(kubectl get service ecsdemo-frontend -o json | jq -r '.status.loadBalancer.ingress[].hostname')\necho ${ELB}\n # 浏览器访问或者通过curl命令进行验证\n curl -m3 -v $ELB\n```\n\n> 微服务部署扩展\n我们发现集群并不是跨多节点的高可用的架构，因此我们需要对部署进行扩展\n\n```bash\n # 每一个微服务目前都只有一个部署单元\n kubectl get deployments\n # NAME               READY   UP-TO-DATE   AVAILABLE   AGE\n # ecsdemo-crystal    1/1     1            1           19m\n # ecsdemo-frontend   1/1     1            1           7m51s\n # ecsdemo-nodejs     1/1     1            1           24m\n\n # scale 到3个replicas\n kubectl scale deployment ecsdemo-nodejs --replicas=3\n kubectl scale deployment ecsdemo-crystal --replicas=3\n kubectl scale deployment ecsdemo-frontend --replicas=3\n\n kubectl get deployments\n # NAME               READY   UP-TO-DATE   AVAILABLE   AGE\n # ecsdemo-crystal    3/3     3            3           21m\n # ecsdemo-frontend   3/3     3            3           9m51s\n # ecsdemo-nodejs     3/3     3            3           26m\n```\n\n> 清除资源\n```bash\n cd ../ecsdemo-frontend\n kubectl delete -f kubernetes/service.yaml\n kubectl delete -f kubernetes/deployment.yaml\n cd ../ecsdemo-crystal\n kubectl delete -f kubernetes/service.yaml\n kubectl delete -f kubernetes/deployment.yaml\n cd ../ecsdemo-nodejs\n kubectl delete -f kubernetes/service.yaml\n kubectl delete -f kubernetes/deployment.yaml\n```\n\n4.2 使用ALB Ingress Controller\n\n参考文档 \n\nhttps://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html\n\nhttps://aws.amazon.com/cn/blogs/opensource/kubernetes-ingress-aws-alb-ingress-controller/\n\n> 4.2.1 创建ALB Ingress Controller所需要的IAM policy , EKS OIDC provider, service account\n\n> 4.2.1.1 创建EKS OIDC Provider (这个操作每个集群只需要做一次）\n\n```bash\neksctl utils associate-iam-oidc-provider --cluster=${CLUSTER_NAME} --approve --region ${AWS_REGION}\n[ℹ]  eksctl version 0.15.0-rc.1\n[ℹ]  using region cn-northwest-1\n[ℹ]  will create IAM Open ID Connect provider for cluster \"eksworkshop\" in \"cn-northwest-1\"\n[✔]  created IAM Open ID Connect provider for cluster \"eksworkshop\" in \"cn-northwest-1\"\n```\n\n> 4.2.1.2 创建所需要的IAM policy\n[https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.5/docs/examples/iam-policy.json](https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.5/docs/examples/iam-policy.json)\n * 请注意官方的policy里面包含了WAF等服务，中国区没有所以需要手动删除,修改好的已经放在resource/alb-ingress-controller目录下\n\n```bash\ncd china/2020_EKS_Launch_Workshop\naws iam create-policy --policy-name ALBIngressControllerIAMPolicy \\\n  --policy-document file://./alb-ingress-controller/ingress-iam-policy.json --region ${AWS_REGION}\n\n# 记录返回的Plociy ARN\nPOLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==`ALBIngressControllerIAMPolicy`].Arn' --output text --region ${AWS_REGION})\n\n```\n\n>4.2.1.3 请使用上述返回的policy ARN创建service account\n\n```bash\neksctl create iamserviceaccount \\\n       --cluster=${CLUSTER_NAME} \\\n       --namespace=kube-system \\\n       --name=alb-ingress-controller \\\n       --attach-policy-arn=${POLICY_NAME} \\\n       --override-existing-serviceaccounts \\\n       --approve\n\n参考输出\n[ℹ]  eksctl version 0.15.0-rc.2\n[ℹ]  using region cn-northwest-1\n[ℹ]  1 iamserviceaccount (kube-system/alb-ingress-controller) was included (based on the include/exclude rules)\n[!]  metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set\n[ℹ]  1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount \"kube-system/alb-ingress-controller\", create serviceaccount \"kube-system/alb-ingress-controller\" } }\n[ℹ]  building iamserviceaccount stack \"eksctl-eksworkshop-addon-iamserviceaccount-kube-system-alb-ingress-controller\"\n[ℹ]  deploying stack \"eksctl-eksworkshop-addon-iamserviceaccount-kube-system-alb-ingress-controller\"\n[ℹ]  created serviceaccount \"kube-system/alb-ingress-controller\"\n```\n\n\n\n4.3 部署 ALB Ingress Controller\n\n 相关文件已经resource/alb-ingress-controller目录下，并且修改好，下面步骤为你全新Step-by-Step操作\n\n >4.3.1 创建 ALB Ingress Controller 所需要的RBAC\n\n ```bash\n kubectl apply -f alb-ingress-controller/rbac-role.yaml\n \n ```\n\n>4.2.2 创建 ALB Ingress Controller 配置文件\n\n 修改alb-ingress-controller.yaml 以下配置，参考示例 resource/alb-ingress-controller/alb-ingress-controller.yaml\n(eksctl 自动创建的 vpc 默认为 eksctl-<集群名字>-cluster/VPC)\n\n**特别注意,如果你在中国区使用最新版本1.1.7会有WAF,WAFV2 issue**\n\n[https://github.com/aws-samples/eks-workshop-greater-china/issues/31](https://github.com/aws-samples/eks-workshop-greater-china/issues/31)\n\n需要添加--feature-gates=waf=false,wafv2=false 参数\n\n  ```bash\n  #修改以下内容\n  - --cluster-name=<步骤2 创建的集群名字>\n  - --aws-vpc-id=<eksctl 创建的vpc-id>   \n  - --aws-region=cn-northwest-1\n  #1.1.7 waf,wafv2修复方式\n  # 如果你使用alb-ingress-controller 1.1.7 需要禁用waf,wafv2\n  - --feature-gates=waf=false,wafv2=false\n  \n  #添加环境变量，作为 https://github.com/kubernetes-sigs/aws-alb-ingress-controller/issues/1180 的workaround\n  env:\n            - name: AWS_REGION\n              value: cn-northwest-1\n              \n \n    \n  #使用修改好的yaml文件部署ALB Ingress Controller\n kubectl apply -f alb-ingress-controller/alb-ingress-controller.yaml\n\n \n #确认ALB Ingress Controller是否工作\n kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o alb-ingress[a-zA-Z0-9-]+)\n\n #参考输出\n-------------------------------------------------------------------------------\n  AWS ALB Ingress controller\n  Release:    v1.1.5\n  Build:      git-2560c813\n  Repository: https://github.com/kubernetes-sigs/aws-alb-ingress-controller.git\n-------------------------------------------------------------------------------\n\n  ```\n\n\n 4.4 使用ALB Ingress   \n>4.4.1 为nginx service创建ingress\n\n```bash\ncd resource/alb-ingress-controller\nkubectl apply -f nginx-alb-ingress.yaml\n```\n\n>4.4.2 验证\n\n```bash\nALB=$(kubectl get ingress -o json | jq -r '.items[0].status.loadBalancer.ingress[].hostname')\ncurl -m3 -v $ALB\n\n# 如果遇到问题，请查看日志\nkubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o alb-ingress[a-zA-Z0-9-]+)\n```\n\n> 4.4.3 清理\n```bash\nkubectl delete -f nginx-alb-ingress.yaml\n```\n\n4.5 使用ALB Ingress，部署2048 game (可选）\n\n注意，默认已经使用2.4章节自动修改image mirror的webhook，否则请修改Image地址为国内可以访问的。\n\n```bash\nkubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-namespace.yaml\nkubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-deployment.yaml\nkubectl get pods -n 2048-game\nkubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-service.yaml\nkubectl get service service-2048 -o wide -n 2048-game\nkubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-ingress.yaml\n\n# 获取访问地址，在浏览器中访问2048游戏\nkubectl get ingress/2048-ingress -n 2048-game\n\nkubectl delete -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-deployment.yaml\nkubectl delete -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-service.yaml\nkubectl delete -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-ingress.yaml\nkubectl delete -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.0.0/docs/examples/2048/2048-namespace.yaml\n```\n\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤5-配置使用EBS.md",
    "content": "# 步骤5 配置使用EBS CSI\n\n* [官方ebs-csi指导](https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/ebs-csi.html)\n* [官方eks-persistent-storage支持手册](https://aws.amazon.com/premiumsupport/knowledge-center/eks-persistent-storage/)\n\n5.1 创建所需要的IAM policy , EKS OIDC provider, service account\n\n> 5.1.1 创建所需要的IAM policy\n[https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/v0.4.0/docs/example-iam-policy.json](https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/v0.4.0/docs/example-iam-policy.json)\n\n```bash\n\n#中国区请使用aws-ebs-csi-driver/ebs-csi-iam-policy.json\naws iam create-policy \\\n    --policy-name Amazon_EBS_CSI_Driver \\\n    --policy-document file://./aws-ebs-csi-driver/ebs-csi-iam-policy.json \\\n    --region ${AWS_REGION}\n        \n#返回示例,请记录返回的Plociy ARN\nPOLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==`Amazon_EBS_CSI_Driver`].Arn' --output text --region ${AWS_REGION})\n```\n\n> 5.1.2 获取EKS工作节点的IAM role\n\n```bash\n# 注意这一步如果是多个nodegroup就会有多个role\nkubectl -n kube-system describe configmap aws-auth\n\n# 单个节点组\nROLE_NAME=Role-name-in-above-output\naws iam attach-role-policy --policy-arn ${POLICY_NAME} \\\n    --role-name ${ROLE_NAME} --region ${AWS_REGION}\n\n#多个节点组, 这里准备了一个脚本updaterole.sh\nsh aws-ebs-csi-driver/updaterole.sh ${POLICY_NAME}\n```\n\n> 5.1.3 部署EBS CSI 驱动到eks 集群\n\n[官方文档 https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/ebs-csi.html](https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/ebs-csi.html)\n\n```bash\n#git clone https://github.com/kubernetes-sigs/aws-ebs-csi-driver.git\n\n#中国区请使用resource/aws-ebs-csi-driver的配置文件进行部署\nkubectl apply -k aws-ebs-csi-driver/deploy/kubernetes/overlays/stable\n\n# 验证部署正确 \nkubectl get pods -n kube-system\nNAME                                      READY   STATUS             RESTARTS   AGE\nalb-ingress-controller-649b854d75-m8c75   1/1     Running            0          2d\naws-node-ct6rz                            1/1     Running            0          4d\naws-node-sfjtn                            1/1     Running            0          3d2h\naws-node-xzfx9                            1/1     Running            0          4d\ncoredns-6565755d58-pd5nm                  1/1     Running            0          4d\ncoredns-6565755d58-v9nl7                  1/1     Running            0          4d\nebs-csi-controller-6dcc4dc6f4-6k4s5       4/4     Running            0          47h\nebs-csi-controller-6dcc4dc6f4-vtklz       4/4     Running            0          47h\nebs-csi-node-2zmct                        3/3     Running            0          47h\nebs-csi-node-plljf                        3/3     Running            0          47h\nebs-csi-node-s9lbz                        3/3     Running            0          47h\nkube-proxy-g4mcw                          1/1     Running            0          4d\nkube-proxy-mb88w                          1/1     Running            0          4d\nkube-proxy-tpx4x                          1/1     Running            0          3d2h\nkubernetes-dashboard-5f7b999d65-dcc6h     1/1     Running            0          2d4h\nmetrics-server-7fcf9cc98b-rntrh           1/1     Running            0          26h\n```\n\n5.2 部署动态卷实例应用\n\n```bash\ncd aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/\nkubectl apply -f specs/\n\n#查看storageclass\nkubectl describe storageclass ebs-sc\n\n#查看示例app状态\nkubectl get pods --watch\n#查看是否有失败\nkubectl get events\n\nkubectl get pv\nPV_NAME=$(kubectl get pv -o json | jq -r '.items[0].metadata.name')\nkubectl describe persistentvolumes ${PV_NAME}\n\nkubectl exec -it app cat /data/out.txt\n# Thu Mar 5 14:19:43 UTC 2020\n# Thu Mar 5 14:19:48 UTC 2020\n\n#删除示例程序\nkubectl delete -f specs/\n```"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤6-配置使用EFS.md",
    "content": "# 步骤6 配置使用EFS\n\n6.1 创建EFS file system\n```bash\n# 创建EFS Security group\nVPC_ID=$(aws eks describe-cluster --name ${CLUSTER_NAME} --region ${AWS_REGION} --query \"cluster.resourcesVpcConfig.vpcId\" --output text)\nVPC_CIDR=$(aws ec2 describe-vpcs --vpc-ids ${VPC_ID} --query \"Vpcs[].CidrBlock\"  --region ${AWS_REGION} --output text)\naws ec2 create-security-group --description ${CLUSTER_NAME}-efs-eks-sg --group-name efs-sg --vpc-id ${VPC_ID}\nSGGroupID=上一步的结果访问\naws ec2 authorize-security-group-ingress --group-id ${SGGroupID}  --protocol tcp --port 2049 --cidr ${VPC_CIDR}\n\n# 创建EFS file system 和 mount-target, 请根据你的环境替换 FileSystemId， SubnetID， SGGroupID\naws efs create-file-system --creation-token eks-efs --region ${AWS_REGION}\n# FileSystemId 为上一步创建的文件系统id\n# SubnetID 需要挂载目标区域子网id，可以为 EKS Node 所在区域的子网，如果有多个则需要挂载多次\n# SGGroupID 为上一步创建的EFS所属的 SG id\naws efs create-mount-target --file-system-id FileSystemId --subnet-id SubnetID --security-group SGGroupID\n\n```\n\n6.2. 部署EFS驱动和示例程序\n[官方文档]（https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/efs-csi.html）\n\n```bash\ngit clone https://github.com/kubernetes-sigs/aws-efs-csi-driver.git\ncd aws-efs-csi-driver\n```\n\n6.2.1 Deploy EFS CSI driver to EKS cluster \n\n> 已知问题：\n\nhttps://github.com/kubernetes-sigs/aws-efs-csi-driver/issues/138\nv0.2.0 image contains old version of efs-utils, efs-utils added China region support from v1.19\nThe v.0.3.0 does work, you can also build your image to use v.0.2.0 CSI\n\n```bash\n#使用EFS CSI v0.3.0 镜像\nkubectl apply -k ./aws-efs-csi-driver/deploy/kubernetes/overlays/stable\nkubectl get pods -n kube-system\n\nNAME                                      READY   STATUS    RESTARTS   AGE\nalb-ingress-controller-649b854d75-m8c75   1/1     Running   0          2d18h\naws-node-ct6rz                            1/1     Running   0          4d18h\naws-node-sfjtn                            1/1     Running   0          3d21h\naws-node-xzfx9                            1/1     Running   0          4d18h\ncoredns-6565755d58-pd5nm                  1/1     Running   0          4d18h\ncoredns-6565755d58-v9nl7                  1/1     Running   0          4d18h\nebs-csi-controller-6dcc4dc6f4-6k4s5       4/4     Running   0          2d17h\nebs-csi-controller-6dcc4dc6f4-vtklz       4/4     Running   0          2d17h\nebs-csi-node-2zmct                        3/3     Running   0          2d17h\nebs-csi-node-plljf                        3/3     Running   0          2d17h\nebs-csi-node-s9lbz                        3/3     Running   0          2d17h\nefs-csi-node-5jtlc                        3/3     Running   0          10h\nefs-csi-node-lqdz9                        3/3     Running   0          10h\nefs-csi-node-snqmh                        3/3     Running   0          10h\nkube-proxy-g4mcw                          1/1     Running   0          4d18h\nkube-proxy-mb88w                          1/1     Running   0          4d18h\nkube-proxy-tpx4x                          1/1     Running   0          3d21h\nkubernetes-dashboard-5f7b999d65-dcc6h     1/1     Running   0          2d23h\nmetrics-server-7fcf9cc98b-rntrh           1/1     Running   0          44h\n\nkubectl exec -ti efs-csi-node-5jtlc -n kube-system -- mount.efs --version\n# Make sure the version is > 1.19\n```\n\n6.2.2 部署样例测试\n```bash\n## Deploy app use the EFS\ncd examples/kubernetes/multiple_pods/\naws efs describe-file-systems --query \"FileSystems[*].[FileSystemId,Name]\" --region ${AWS_REGION} --output text\n\n# 修改 the specs/pv.yaml file and replace the volumeHandle with FILE_SYSTEM_ID\n# 例子：\n#csi:\n#    driver: efs.csi.aws.com\n#    volumeHandle: fs-9c21a999\n\n\n# 部署 the efs-sc storage class, efs-claim pv claim, efs-pv, and app1 and app2 sample applications.\nkubectl apply -f specs/\n\nkubectl describe storageclass efs-sc\nkubectl get pv\nkubectl describe pv efs-pv\nkubectl get pods --watch\nkubectl get events\n\n# 验证\nkubectl exec -ti app1 -- tail /data/out1.txt\nkubectl exec -ti app2 -- tail /data/out1.txt\n\n# 清理\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤7-在EKS中使用IAMRole进行权限管理.md",
    "content": "# 步骤7 在EKS中使用IAM Role进行权限管理\n我们将要为ServiceAccount配置一个S3的访问角色，并且部署一个job应用到EKS集群，完成S3的写入。\n\n[官方文档](https://aws.amazon.com/blogs/opensource/introducing-fine-grained-iam-roles-service-accounts/)\n\n7.1 配置IAM Role、ServiceAccount\n\n>7.1.1 使用eksctl 创建service account \n\n```bash\n# 在步骤3我们已经创建了OIDC身份提供商 \n# 请检查IAM OpenID Connect (OIDC) 身份提供商是否已经创建\naws eks describe-cluster --name ${CLUSTER_NAME} --region ${AWS_REGION} --query cluster.identity.oidc.issuer --output text\n# 如果上述命令无输出，请执行以下命令创建OpenID Connect (OIDC) 身份提供商\neksctl utils associate-iam-oidc-provider --cluster=${CLUSTER_NAME} --approve --region ${AWS_REGION}\n\n#创建serviceaccount s3-echoer with IAM role\neksctl create iamserviceaccount --name s3-echoer --namespace default \\\n    --cluster ${CLUSTER_NAME} --attach-policy-arn arn:aws-cn:iam::aws:policy/AmazonS3FullAccess \\\n    --approve --override-existing-serviceaccounts --region ${AWS_REGION}\n\n```\n\n7.2 部署测试访问S3的应用\n*使用已有s3 bucket或创建s3 bucket, 请确保bucket名字唯一才能创建成功.\n\n```bash\ngit clone https://github.com/mhausenblas/s3-echoer.git && cd s3-echoer\n\n# 设置环境变量TARGET_BUCKET,Pod访问的S3 bucket\nTARGET_BUCKET=eksworkshop-irsa-2019\nif [ $(aws s3 ls | grep $TARGET_BUCKET | wc -l) -eq 0 ]; then\n    aws s3api create-bucket  --bucket $TARGET_BUCKET  --create-bucket-configuration LocationConstraint=$AWS_REGION  --region $AWS_REGION\nelse\n    echo \"S3 bucket $TARGET_BUCKET existed, skip creation\"\nfi\n\n# 修改Region,部署Job\nsed -e \"s/TARGET_BUCKET/${TARGET_BUCKET}/g;s/us-west-2/${AWS_REGION}/g\" s3-echoer-job.yaml.template > s3-echoer-job.yaml\nkubectl apply -f s3-echoer-job.yaml\n\n# 验证\nkubectl get job/s3-echoer\nkubectl logs job/s3-echoer\n## 参考输出\nUploading user input to S3 using eksworkshop-irsa-2019/s3echoer-1583415691\n\n# 检查S3 bucket上面的文件\naws s3api list-objects --bucket $TARGET_BUCKET --query 'Contents[].{Key: Key, Size: Size}'  --region $AWS_REGION\n[\n    {\n        \"Key\": \"s3echoer-1583415691\",\n        \"Size\": 27\n    }\n]\n\n#清理\nkubectl delete job/s3-echoer\n```\n\n7.3 部署第二个IAM 权限测试Pod\n```bash\ncd china/2020_EKS_Launch_Workshop/resource/\n\n# Apply the testing\nkubectl apply -f IRSA/iam-pod.yaml\npod/s3-echoer created created\n\nkubectl get pod  s3-echoer\nNAME                            READY   STATUS    RESTARTS   AGE\ns3-echoer                       1/1     Running   0          2m38s\n\n# 验证IAM Role 是否生效\nkubectl exec -it s3-echoer bash\n# In promote input, the output Arn should looks like assumed-role/eksctl-gcr-zhy-eksworkshop-addon-iamservicea-Role\naws sts get-caller-identity\n# output shoudld list all the S3 bucket in AWS_REGION under the account \naws s3 ls\naws ec2 describe-instances\n# output should be like: An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.\n\n# cleanup\nkubectl delete -f IRSA/iam-pod.yaml\n\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤8-对应用Pod和集群进行自动扩展.md",
    "content": "# 步骤8 使用HPA对Pod进行自动扩展， 使用CA对集群进行自动扩展\n\n> 本节目的\n1. 为集群配置一个HPA，并且部署一个应用进行压力测试，验证Pod 横向扩展能力。\n2. 为集群配置一个CA，使用CA对集群进行自动扩展\n\n[官方文档](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#increase-load)\n\n8.1 使用HPA对Pod进行自动扩展\n\n8.1.1 Install Metrics Server\n\n```bash\n# 下载Metrics Server\nmkdir -p hpa && cd hpa\ncurl -Ls https://api.github.com/repos/kubernetes-sigs/metrics-server/tarball/v0.3.6  -o metrics-server-v0.3.6.tar.gz\nmkdir -p metrics-server-v0.3.6\ntar -xzf metrics-server-v0.3.6.tar.gz --directory metrics-server-v0.3.6 --strip-components 1\n\n# 假设您已经使用了image webhook, 否则请修改image地址为中国国内可访问的\nkubectl apply -f metrics-server-v0.3.6/deploy/1.8+/\nkubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o metrics-server[a-zA-Z0-9-]+)\n\n# 验证 Metrics Server installation\nkubectl get deployment metrics-server -n kube-system\nkubectl get apiservice v1beta1.metrics.k8s.io -o yaml\n```\n\n8.1.2 安装 HPA sample application php-apache\n```bash\nkubectl apply -f https://k8s.io/examples/application/php-apache.yaml\n\n# Set threshold to CPU30% auto-scaling, and up to 5 pod replicas\nkubectl autoscale deployment php-apache --cpu-percent=30 --min=1 --max=5\nkubectl get hpa\n```\n\n8.1.3 开启 load-generator\n```bash\nkubectl run --generator=run-pod/v1 -it --rm load-generator --image=busybox /bin/sh\n\n# 提示框输入\nwhile true; do wget -q -O- http://php-apache.default.svc.cluster.local; done\n```\n\n8.1.4 Check HPA\n```bash\n\nwatch kubectl get hpa\nNAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE\nphp-apache   Deployment/php-apache   250%/30%   1         5         4          3m22s\n\nkubectl get deployment php-apache\nNAME         READY   UP-TO-DATE   AVAILABLE   AGE\nphp-apache   5/5     5            5           6m2s\n\n```\n\n8.2 使用CA对集群进行自动扩展\n\n适用于AWS的Cluster Autoscaler提供与Auto Scaling Group 集成。 它使用户可以从四个不同的部署选项中进行选择：\n1. 一个Auto Scaling Group - 本节使用的方式\n2. 多个Auto Scaling组\n3. 自动发现 Auto-Discovery\n4. 主节点设置\n\n8.2.1 配置Cluster Autoscaler (CA)\n```bash\nmkdir cluster-autoscaler && cd cluster-autoscaler\nwget https://eksworkshop.com/beginner/080_scaling/deploy_ca.files/cluster_autoscaler.yml\n\nK8S_VERSION=$(kubectl version --short | grep 'Server Version:' | sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/' | cut -d. -f1,2)\n\nAUTOSCALER_VERSION=$(curl -s \"https://api.github.com/repos/kubernetes/autoscaler/releases\" | grep '\"tag_name\":' | sed 's/.*-\\([0-9][0-9\\.]*\\).*/\\1/' | grep -m1 ${K8S_VERSION})\n```\n\n8.2.2 Configure the Auto Scaling Group ASG\n![ASG](media/cluster-asg.png)\n修改Capacity为\nMin: 2\nMax: 6\n\n8.2.3 Apply CA\n```bash\n# Replace the placeholder value\n${AUTOSCALER_VERSION}\n<AUTOSCALING GROUP NAME>\n<AWS_REGION_NAME> \nThis specifies the minimum nodes (2), max nodes (8) and ASG Name.\n\n# Apply IAM Policy\nSTACK_NAME=$(eksctl get nodegroup --cluster ${CLUSTER_NAME} --region=${AWS_REGION} -o json | jq -r '.[].StackName')\necho $STACK_NAME\nROLE_NAME=$(aws cloudformation describe-stack-resources --stack-name $STACK_NAME --region=${AWS_REGION} | jq -r '.StackResources[] | select(.ResourceType==\"AWS::IAM::Role\") | .PhysicalResourceId')\necho $ROLE_NAME\n\ncat cluster-autoscaler/k8s-asg-policy.json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"autoscaling:DescribeAutoScalingGroups\",\n        \"autoscaling:DescribeAutoScalingInstances\",\n        \"autoscaling:SetDesiredCapacity\",\n        \"autoscaling:TerminateInstanceInAutoScalingGroup\",\n        \"autoscaling:DescribeTags\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n\naws iam put-role-policy --role-name $ROLE_NAME --policy-name ASG-Policy-For-Worker --policy-document file://./cluster-autoscaler/k8s-asg-policy.json --region ${AWS_REGION}\n\naws iam get-role-policy --role-name $ROLE_NAME --policy-name ASG-Policy-For-Worker --region ${AWS_REGION}\n\n# Deploy CA\nkubectl apply -f cluster-autoscaler/cluster_autoscaler.yml\nkubectl get pod -n kube-system -o wide \\\n    $(kubectl get po -n kube-system | egrep -o cluster-autoscaler[a-zA-Z0-9-]+)\nkubectl logs -f deployment/cluster-autoscaler -n kube-system\n\n\n```\n\n8.2.4 Scale cluster\n```bash\n\nkubectl apply -f cluster-autoscaler/nginx-to-scaleout.yaml\nkubectl get deployment/nginx-to-scaleout\nNAME                READY   UP-TO-DATE   AVAILABLE   AGE\nnginx-to-scaleout   1/1     1            1           43s\n\n# Scale out the ReplicaSet\nkubectl scale --replicas=10 deployment/nginx-to-scaleout\n\nkubectl get pods --watch\nNAME                                 READY   STATUS    RESTARTS   AGE\nbusybox                              1/1     Running   0          22h\nnginx-to-scaleout-84f9cdbd84-2tklw   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-4rs5d   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-72sb7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-7rdjb   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-9kpt6   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-h4fd7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-hxxq7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-pxhc5   1/1     Running   0          19m\nnginx-to-scaleout-84f9cdbd84-snbc7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-snd56   1/1     Running   0          17m\n\nkubectl logs -f deployment/cluster-autoscaler -n kube-system\n\n#Check the AWS Management Console to confirm that the Auto Scaling groups are scaling up to meet demand. \naws ec2 describe-instances --filters \"Name=tag:eks:cluster-name,Values=${CLUSTER_NAME}\" --query \"Reservations[].Instances[].[InstanceId,State.Name]\" --region ${AWS_REGION}\n\n[\n    [\n        \"i-00a58166f01483577\",\n        \"running\"\n    ],\n    [\n        \"i-028933f3a55edae59\",\n        \"running\"\n    ],\n    [\n        \"i-01adcd8b6e3c7ce8c\",\n        \"running\"\n    ],\n    [\n        \"i-02e545c32952d9879\",\n        \"running\"\n    ]\n]\n\n```\n\n8.2.5 clean up\n```bash\nkubectl delete -f cluster-autoscaler/nginx-to-scaleout.yaml\nkubectl delete -f cluster-autoscaler/cluster_autoscaler.yml\n```\n"
  },
  {
    "path": "china/2020_EKS_Launch_Workshop/步骤9-使用Helm部署应用.md",
    "content": "# 步骤9 使用Helm部署应用\nHelm帮助您管理Kubernetes应用程序。在原来Kubernetes项目中都是基于yaml文件来进行部署发布微服务化应用的，会分成很多个组件来部署，每个组件可能对应一个deployment.yaml,一个service.yaml,一个Ingress.yaml等文件，还可能存在各种依赖关系。Helm旨在解决\n\n（1）基于yaml配置的集中存放 \n（2）基于项目的打包 \n（3）组件间的依赖\n（4）部署过程中的前置和后置任务\n（5）更新、回滚和测试部署\n\nHelm由以下几个组件组成：\n1. Helm Charts: 一个 Helm 包，包含了运行一个应用所需要的镜像、依赖和资源定义等，还可能包含Kubernetes集群中的服务定义\n2. Helm Release: 运行中的一个Chart实例。在同一个Kubernetes集群上，一个 Chart 可以安装很多次。每次安装都会创建一个新的 release\n3. Helm Repository：用于发布和存储 Chart 的仓库。\n4. Helm Config：创建发布对象的chart的配置信息\n\n常见的文件结构：\n```bash\nwordpress/\n  Chart.yaml          # A YAML file containing information about the chart\n  LICENSE             # OPTIONAL: A plain text file containing the license for the chart\n  README.md           # OPTIONAL: A human-readable README file\n  requirements.yaml   # OPTIONAL: A YAML file listing dependencies for the chart\n  values.yaml         # The default configuration values for this chart\n  charts/             # A directory containing any charts upon which this chart depends.\n  templates/          # A directory of templates that, when combined with values,\n                      # will generate valid Kubernetes manifest files.\n  templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes\n```\n\n[官方文档](https://helm.sh/docs/)\n\n> 本节目的\n1. 安装配置Helm\n2. 使用Helm部署样例微服务\n\n9.1 Install Helm \n\n```bash\n# 通用\ncurl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash\n# MacOS\nbrew install helm\n# 验证安装\nhelm version --short\n\n# 设置 stable repository\n## 删除默认的源\nhelm repo remove stable\n## 增加新的国内镜像源, 你可以选择其他偏好的国内镜像\nhelm repo add stable https://burdenbear.github.io/kube-charts-mirror/\nhelm search repo wordpress\n\n# 配置 Bash completion\n# linux\nhelm completion bash >> ~/.bash_completion\n. /etc/profile.d/bash_completion.sh\n. ~/.bash_completion\nsource <(helm completion bash)\n# Mac\nbrew install bash-completion\nbrew tap homebrew/completions\n# Edit ~/.bash_profile or ~/.bashrc\nsource <(kubectl completion bash)\nsource <(helm completion bash)\nif [ -f $(brew --prefix)/etc/bash_completion ]; then \n. $(brew --prefix)/etc/bash_completion\nfi\n```\n\n9.2 使用Helm部署 nginx\n```bash\nhelm repo update\nhelm search repo nginx\n# add nginx standalone web server\nhelm repo add bitnami https://charts.bitnami.com/bitnami\nhelm search repo bitnami/nginx\n# install\nhelm install gcr-eks-webserver bitnami/nginx\n\n# verify the helm chart deployed, nginx deployment available and pod on running\nhelm list\nkubectl describe deployment gcr-eks-webserver\nkubectl get pods -l app.kubernetes.io/name=nginx\n\n# Get the NGINX URL:\n#Watch the status with\nkubectl get svc -n default -w gcr-eks-webserver-nginx\nSERVICE_IP=$(kubectl get svc --namespace default gcr-eks-webserver-nginx --template \"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}\")\necho \"NGINX URL: http://${SERVICE_IP}/\"\ncurl ${SERVICE_IP}\n\n# cleanup\nhelm list\nhelm uninstall gcr-eks-webserver\nkubectl get pods -l app.kubernetes.io/name=nginx\nkubectl get svc -n default -o wide gcr-eks-webserver-nginx\n```\n\n9.3 使用Helm部署样例微服务\n\n学习如何用Helm部署[步骤4](步骤4-部署微服务以及配置ALBIngressController)的微服务 \n```bash\ncd ~/temp\n# create a chart\nhelm create eks-helm-demo\nls eks-helm-demo/\nChart.yaml\tcharts\t\ttemplates\tvalues.yaml\n\n# create our own file\nrm -rf eks-helm-demo/templates/\nrm eks-helm-demo/Chart.yaml\nrm eks-helm-demo/values.yaml\ncat <<EoF > eks-helm-demo/Chart.yaml\napiVersion: v2\nname: eks-helm-demo\ndescription: A Helm chart for EKS Workshop Microservices application\nversion: 0.1.0\nappVersion: 1.0\nEoF\n\n#create subfolders for each template type\nmkdir -p eks-helm-demo/templates/deployment\nmkdir -p eks-helm-demo/templates/service\n\n# Copy and rename frontend manifests\ncp ecsdemo-frontend/kubernetes/deployment.yaml eks-helm-demo/templates/deployment/frontend.yaml\ncp ecsdemo-frontend/kubernetes/service.yaml eks-helm-demo/templates/service/frontend.yaml\n\n# Copy and rename crystal manifests\ncp ecsdemo-crystal/kubernetes/deployment.yaml eks-helm-demo/templates/deployment/crystal.yaml\ncp ecsdemo-crystal/kubernetes/service.yaml eks-helm-demo/templates/service/crystal.yaml\n\n# Copy and rename nodejs manifests\ncp ecsdemo-nodejs/kubernetes/deployment.yaml eks-helm-demo/templates/deployment/nodejs.yaml\ncp ecsdemo-nodejs/kubernetes/service.yaml eks-helm-demo/templates/service/nodejs.yaml\n\n# Replace hard-coded values with template directives\nspec:\n  replicas: 1\n#replace with the following:\nreplicas: {{ .Values.replicas }}\n\nspec.template.spec.containers.image\n#replace with \nfrontend.yaml\t- image: {{ .Values.frontend.image }}:{{ .Values.version }}\ncrystal.yaml\t- image: {{ .Values.crystal.image }}:{{ .Values.version }}\nnodejs.yaml\t- image: {{ .Values.nodejs.image }}:{{ .Values.version }}\n\neks-helm-demo/templates/deployment/frontend.yaml\neks-helm-demo/templates/deployment/crystal.yaml\neks-helm-demo/templates/deployment/nodejs.yaml\n\ncat <<EoF > eks-helm-demo/values.yaml\n# Default values for eksdemo.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\n# Release-wide Values\nreplicas: 3\nversion: 'latest'\n\n# Service Specific Values\nnodejs:\n  image: brentley/ecsdemo-nodejs\ncrystal:\n  image: brentley/ecsdemo-crystal\nfrontend:\n  image: brentley/ecsdemo-frontend\nEoF\n\n# Deployment chart\n## dry-run\nhelm install --debug --dry-run workshop eks-helm-demo\n## install chart\nhelm install workshop eks-helm-demo\nNAME: workshop\nLAST DEPLOYED: Tue Mar 10 15:04:18 2020\nNAMESPACE: default\nSTATUS: deployed\nREVISION: 1\nTEST SUITE: None\n\n# Verify\nhelm list\nNAME               READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS         IMAGES                             SELECTOR\necsdemo-crystal    3/3     3            3           11m     ecsdemo-crystal    brentley/ecsdemo-crystal:latest    app=ecsdemo-crystal\necsdemo-frontend   3/3     3            3           11m     ecsdemo-frontend   brentley/ecsdemo-frontend:latest   app=ecsdemo-frontend\necsdemo-nodejs     3/3     3            3           11m     ecsdemo-nodejs     brentley/ecsdemo-nodejs:latest     app=ecsdemo-nodejs\n\nkubectl get pods -l app=ecsdemo-crystal\nkubectl get pods -l app=ecsdemo-nodejs\nkubectl get pods -l app=ecsdemo-frontend\nkubectl get svc ecsdemo-frontend -o jsonpath=\"{.status.loadBalancer.ingress[*].hostname}\"; echo\n\n```\n\n9.4 ROLLING Upgrade / Back\n```bash\n# Update the demo application chart with a breaking change\n# Edit values.yaml and modify the image name under nodejs.image to brentley/ecsdemo-nodejs-non-existing. \n# This image does not exist, so this will break our deployment.\n\n# rolling upgrade\nhelm upgrade workshop eks-helm-demo\nRelease \"workshop\" has been upgraded. Happy Helming!\nNAME: workshop\nLAST DEPLOYED: Tue Mar 10 15:22:20 2020\nNAMESPACE: default\nSTATUS: deployed\nREVISION: 2\nTEST SUITE: None\n\n# Check the rolling upgrade\n# ecsdemo-nodejs should shown ImagePullBackOff error\nkubectl get pods -l app=ecsdemo-nodejs\nNAME                              READY   STATUS         RESTARTS   AGE\necsdemo-nodejs-6fdf964f5f-27569   1/1     Running        0          18m\necsdemo-nodejs-6fdf964f5f-ngw54   1/1     Running        0          18m\necsdemo-nodejs-6fdf964f5f-rr9m6   1/1     Running        0          18m\necsdemo-nodejs-7c6575b56c-brfpv   0/1     ErrImagePull   0          5s\n\n# rolling back\n# Run helm status workshop to verify the LAST DEPLOYED timestamp.\nhelm status workshop\nhelm history workshop\nREVISION\tUPDATED                 \tSTATUS    \tCHART              \tAPP VERSION\tDESCRIPTION\n1       \tTue Mar 10 15:04:18 2020\tsuperseded\teks-helm-demo-0.1.0\t1          \tInstall complete\n2       \tTue Mar 10 15:22:20 2020\tdeployed  \teks-helm-demo-0.1.0\t1          \tUpgrade complete\n\n# rollback to the 1st revision\nhelm rollback workshop 1\nRollback was a success! Happy Helming!\n# Check status\nkubectl get pods -l app=ecsdemo-nodejs\nNAME                              READY   STATUS    RESTARTS   AGE\necsdemo-nodejs-6fdf964f5f-27569   1/1     Running   0          20m\necsdemo-nodejs-6fdf964f5f-ngw54   1/1     Running   0          20m\necsdemo-nodejs-6fdf964f5f-rr9m6   1/1     Running   0          20m\n\n# Clean up\nhelm uninstall workshop\nkubectl get pods -l app=ecsdemo-nodejs\nkubectl get pods -l app=ecsdemo-crystal\nkubectl get pods -l app=ecsdemo-frontend\nkubectl get svc ecsdemo-frontend -o wide\n```\n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/Kubeflow_Pipelines.md",
    "content": "### Kubeflow Pipelines与sagemaker集成\n\nKubeflow pipeline是工具包的核心组件之一，在安装Kubeflow时自动部署。Kubeflow管道包括:\n\n- 用于管理和跟踪实验、作业和运行的用户界面(UI)\n- 用于调度多步ML工作流的引擎\n- 用于定义和操作管道和组件的SDK\n- 使用SDK与笔记本交互\n\nKubeflow pipeline SDK提供了一组Python包，您可以使用它们来指定和运行您的机器学习(ML)工作流。pipeline是ML工作流的描述，包括组成工作流步骤的所有组件以及组件之间如何交互。\n\n#### 在 EKS cluster配置 AWS credentials \n\n为了运行本实验，我们需要不同级别的IAM权限。\n\n1. 使用Sagemaker策略创建Kubernetes secrets aws-secret。我们将在管道执行期间使用它来调用AWS API。\n2. 为Sagemaker创建一个IAM执行角色，以便作业可以承担此角色以执行Sagemaker操作。\n\n通常在生产环境中，您将根据操作分配细粒度的权限，并利用诸如IAM Role for Service Account这样的工具来确保对AWS资源的访问，但为简单起见，我们将为分配AmazonSageMakerFullAccess IAM策略。\n\n在终端运行下列命令创建 IAM 权限：\n\n```bash\naws iam create-user --user-name sagemakeruser\naws iam attach-user-policy --user-name sagemakeruser --policy-arn arn:aws:iam::aws:policy/AmazonSageMakerFullAccess\naws iam create-access-key --user-name sagemakeruser > /tmp/create_output.json\n```\n\n设置环境变量：\n\n```bash\nexport AWS_ACCESS_KEY_ID_VALUE=$(jq -j .AccessKey.AccessKeyId /tmp/create_output.json | base64)\nexport AWS_SECRET_ACCESS_KEY_VALUE=$(jq -j .AccessKey.SecretAccessKey /tmp/create_output.json | base64)\n```\n\n 在EKS cluster中创建secret资源:\n\n```yaml\ncat <<EOF | kubectl apply -f -\napiVersion: v1\nkind: Secret\nmetadata:\n  name: aws-secret\n  namespace: kubeflow\ntype: Opaque\ndata:\n  AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID_VALUE\n  AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY_VALUE\nEOF\n```\n\n运行下列命令创建 Sagemaker执行角色\n\n```bash\nTRUST=\"{ \\\"Version\\\": \\\"2012-10-17\\\", \\\"Statement\\\": [ { \\\"Effect\\\": \\\"Allow\\\", \\\"Principal\\\": { \\\"Service\\\": \\\"sagemaker.amazonaws.com\\\" }, \\\"Action\\\": \\\"sts:AssumeRole\\\" } ] }\"\naws iam create-role --role-name eksworkshop-sagemaker-kfp-role --assume-role-policy-document \"$TRUST\"\naws iam attach-role-policy --role-name eksworkshop-sagemaker-kfp-role --policy-arn arn:aws:iam::aws:policy/AmazonSageMakerFullAccess\naws iam attach-role-policy --role-name eksworkshop-sagemaker-kfp-role --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess\naws iam get-role --role-name eksworkshop-sagemaker-kfp-role --output text --query 'Role.Arn'\n```\n\n在脚本的最后，您将得到生成的IAM角色的arn。请记录这个角色arn，因为在kubeflow管道创建步骤中需要，下面是输出的例子：\n\n```bash\n$ aws iam get-role --role-name eksworkshop-sagemaker-kfp-role --output text --query 'Role.Arn'\narn:aws:iam::371348455981:role/eksworkshop-sagemaker-kfp-role\n```\n\n最后,分配 sagemaker:InvokeEndpoint 权限给 EKS 工作节点IAM role\n\n```bash\ncat <<EoF > ~/environment/sagemaker-invoke.json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"sagemaker:InvokeEndpoint\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}\nEoF\naws iam put-role-policy --role-name $ROLE_NAME --policy-name sagemaker-invoke-for-worker --policy-document file://~/environment/sagemaker-invoke.json\n```\n\n#### 运行 Sagemaker pipeline 笔记本\n\n 浏览到Sagemaker pipeline notebook (eks-workshop-notebook/notebooks/05_Kubeflow_Pipeline/05_04_Pipeline_SageMaker.ipynb). 打开 Sagemaker pipeline 笔记本\n![dashboard](images/pipelines-view-sagemaker-notebook.png)\n\n完成以下先决条件:\n\n创建S3存储桶；复制管道数据。您可以跳过步骤3，因为我们已经在前面创建了Kubernetes secrets和Sagemaker执行角色，跳过3。继续执行第4步，安装Kubeflow管道SDK。\n\n完成所有先决条件步骤之后，继续构建pipeline。首先运行步骤1来加载Kubeflow管道SDK，完成之后，运行步骤2来加载sagemaker组件\n\n修改：AWS_REGION = 'cn-northwest-1'，如图所示：\n\n![](images/AFFAD617-732B-4799-9B6F-A0015F219BE2.png)\n\n下载训练数据和valid数据。将它们转换为KMeans所需的格式并上传到S3存储桶中。由于网络原因，如果遇上数据集不能从http://deeplearning.net/data/mnist/mnist.pkl.gz的情况，请手工下载，并上传到notebook笔记本：\n\n![AF8CAAE2-7011-40B5-BDC7-D2A97329DA42](images/AF8CAAE2-7011-40B5-BDC7-D2A97329DA42.jpg)\n\n注释：#urllib.request.urlretrieve(\"http://deeplearning.net/data/mnist/mnist.pkl.gz\", \"mnist.pkl.gz\")\n\n增加代码 ：boto3.setup_default_session(region_name='cn-northwest-1')\n\n如图所示：\n\n![991D210F-E610-48DE-B621-5A3C42A4899C](images/991D210F-E610-48DE-B621-5A3C42A4899C.jpg)\n\n#### 构建pipeline\n\n在运行步骤3 - create pipeline之前，需要修改以下代码：\n\n将SAGEMAKER_ROLE_ARN的值替换为我们在分配IAM权限期间创建的Sagemaker执行角色\n\n将kmeans镜像替换为：image='387376663083.dkr.ecr.cn-northwest-1.amazonaws.com.cn/kmeans:1'\n\n将region替换为：region='cn-northwest-1'\n\n将训练实例类型替换：instance_type='ml.m5.large'\n\n![83687F81-5325-4993-AB30-E4B9C1D38AA9](images/83687F81-5325-4993-AB30-E4B9C1D38AA9.jpg)\n\n在此之后，运行下面两个步骤来编译和部署管道\n\n您将收到两个链接，一个是Experiment，另一个是运行的pipeline。\n\n![dashboard](images/pipelines-deploy.png)\n\n点击 **here** 链接到 **Experiment link**.\n\n![dashboard](images/pipelines-sagemaker-experiment.png)\n\n通过 View pipeline查看pipeline的详细信息\n\n![dashboard](images/pipelines-sagemaker-overview.png)\n\n点击 **Experiments**, **All runs**, **mnist-classification-pipeline** 检查pipeline中的所有步骤\n\n![dashboard](images/pipelines-sagemaker-experiment-run.png)\n\n点击 sagemaker training job ， 点击logs 查看执行日志细节\n\n![dashboard](images/pipelines-run-logs.png)\n\n十几分钟后，您将看到训练工作完成，pipeline完成后然后创建一个模型。在此步骤之后，运行批处理转换，最后使用Sagemaker推理部署模型。记下Sagemaker端点，以便我们可以运行推理来验证我们的模型\n\n![dashboard](images/pipelines-sagemaker-endpoint.png)\n\n查看sagemaker的终端节点已部署成功：\n\n\n![9237694F-B635-455E-B147-272E9D857276](images/9237694F-B635-455E-B147-272E9D857276.jpg)\n\n现在，我们对这个端点进行预测，调用boto3，\n\n将端点名称更改为在前面步骤中接收到的sagemaker端点名称\n\nregion_name替换成'cn-northwest-1'\n\n得到的推理结果如下：\n\n![6B748653-A556-48CE-9E42-8590F3D3A4DA](images/6B748653-A556-48CE-9E42-8590F3D3A4DA.jpg)\n\n#### 清理\n\n到Sagemaker console 手工删除本实验创建的 `endpoint`, `model`.\n\n删除本次实验创建的 S3 bucket\n\n```bash\n!aws s3 rb s3://$S3_BUCKET --force\n```\n\n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/Kubeflow_fairing.md",
    "content": "Kubeflow Fairing是一个Python软件包，可轻松在[Kubeflow](https://www.kubeflow.org/docs/about/kubeflow/)上训练和部署ML模型。Kubeflow Fairing还可以扩展为在其他平台上进行培训或部署。目前，Kubeflow Fairing已扩展为可在aws上进行培训。\n\nKubeflow Fairing将您的Jupyter笔记本，Python函数或Python文件打包为Docker映像，然后在Kubeflow或AI平台上部署并运行培训作业。训练工作完成后，您可以使用Kubeflow Fairing将训练后的模型部署为Kubeflow上的预测端点。\n\n以下是[Kubeflow Fairing项目](https://github.com/kubeflow/fairing)的目标：\n\n- **轻松打包ML培训作业：**使ML从业人员可以轻松地将其ML模型培训代码及其代码依赖性打包为Docker映像。\n- **在混合云环境中轻松训练ML模型：**提供用于训练ML模型的高级API，从而使您可以轻松地在云中运行训练作业，而无需了解底层基础结构。\n- **简化部署训练有素的模型的过程：**使ML练习者可以轻松地将训练有素的ML模型部署到混合云环境。\n\n#### 创建 Jupyter notebook serve\n\n使用自定义镜像 (seedjeffwan/tensorflow-1.13.1-notebook-cpu:awscli-v2) 创建笔记本，如下图所示： \n\n![dashboard](images/eks-kubeflow-workshop-notebook-server-20200522171332313.png)\n\n#### 克隆实验repo\n\n创建一个新的 Python 3 Notebook.运行一下命令clone本实验repo：\n\n```bash\n!git clone https://github.com/aws-samples/eks-kubeflow-workshop.git\n```\n\n点击运行. 关闭 notebook tab, 返回 notebook server, 选择刚才使用的notebook 并点击**Shutdown**.\n\n[![dashboard](images/fairing-shutdown-notebook-0138774.png)](https://eksworkshop.com/images/kubeflow/fairing-shutdown-notebook.png)\n\n#### 设置 S3 and ECR 访问许可\n\n在本实验中，我们将同时使用S3和ECR服务。我们将使用S3来存储和访问管道数据。我们将使用ECR作为训练镜像的容器注册表。我们需要将IAM策略添加到工作节点，以便能够访问S3和ECR，在终端中运行以下命令并分配所需的权限：\n\n```bash\naws iam attach-role-policy --role-name $NODE_INSTANCE_ROLE --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess\n\naws iam attach-role-policy --role-name $NODE_INSTANCE_ROLE --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess\n```\n\n#### 运行 fairing \n\n浏览**“eks-kubeflow-workshop”**库，转到fairing introduction notebook (eks-kubeflow-workshop/notebook /02_Fairing/02_01_fairing_introduction.ipynb)。您可以点击笔记本打开并点击**查看**\n\n![dashboard](images/fairing-view-introduction-notebook.png)\n\n检查内容并单击第一个单元格，然后单击**Run**。这将允许您从Github存储库安装faring，等待安装完成，转到下一个单元格并单击**Run**。如下图：\n\n![dashboard](images/fairing-install-from-github.png)\n\n现在已经安装了fairing，我们将训练用Python编写模型。该模型将创建一个线性回归模型，该模型允许我们从一组给定的连续数据中学习一个函数或关系。例如，我们已知x和对应y的一些数据点我们需要了解它们之间的关系。\n\n在线性回归的情况下，假设是一条直线i。例如, h(x) = x *权值+ b。\n\n运行单元3。完成后，运行单元格4。这将在我们的笔记本上本地创建并训练一个模型\n\n![dashboard](images/fairing-train-locally.png)\n\n现在，让我们使用fairing，并将图像推入ECR，可用于remote训练,在使用ECR运行authenticate之前，请更改区域为'cn-northwest-1'。运行此单元并登录ECR，以便执行ECR操作\n\n运行下一个单元并在同一区域创建一个ECR存储库(fair -job)。您应该会看到类似的输出\n\n![](images/DD2DC6CF-C1A4-4CD1-9DA5-E9840AC449CA.jpg)\n\n![](images/output.png)\n\n修改 AWS_ACCOUNT_ID为上面registryId的输出，\n\n修改DOCKER_REGISTRY='{}.dkr.ecr.{}.amazonaws.com.cn'.format(AWS_ACCOUNT_ID, AWS_REGION),\n\n如下所示：\n\n![](images/6F747188-6041-4395-BCC8-5C1AECA8150A.png)\n\n运行下一个单元格。Fairing将图像推送到ECR，然后远程部署模型\n\n![img](images/fairing-remote-job.png)\n\n\n\n我们已经成功运行了如何使用fairing在本地和远程进行模型训练\n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/README.md",
    "content": "#### 概要 \n\nKubeflow提供了一种在Kubernetes上运行机器学习工作负载的简单、可移植和可伸缩的方法，使机器学习(ML)工作流在Kubernetes上的部署变得简单、可移植和可伸缩。在本练习中，您将学习如何在EKS中部署和创建Kubeflow，并学会如何在Kubeflow创建和使用jupter notebook，使用TensorFlow运行一个单节点训练和推理，以及如果利用kubeflow fairing将训练后的模型部署为预测端点、学会如何利用pipeline用于定义复杂的机器学习工作流程，并学会如何利用kubeflow进行分布式训练。\n\n ![kubeflow](images/kubeflow.png)\n\n 在此教程中，您将完成以下实验：\n\n  * [安装Kubeflow](安装Kubeflow.md)\n\n  * [创建和使用jupter notebook](创建和使用jupter笔记本.md)\n\n  * [使用Kubeflow fairing](Kubeflow_fairing.md)\n\n  * [使用Kubeflow pipeline](Kubeflow_Pipelines.md)\n\n  * [Kubeflow 分布式训练]准备中......\n\n  * [清理资源](清理资源.md)\n\n \n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/resources/mnist-tensorflow-jupyter.py",
    "content": "from __future__ import print_function\n\nimport tensorflow as tf\nfrom tensorflow import keras\n\n# Helper libraries\nimport numpy as np\nimport os\nimport subprocess\nimport argparse\n\n# Reduce spam logs from s3 client\nos.environ['TF_CPP_MIN_LOG_LEVEL']='3'\n\ndef preprocessing():\n  fashion_mnist = keras.datasets.fashion_mnist\n  (train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()\n\n  # scale the values to 0.0 to 1.0\n  train_images = train_images / 255.0\n  test_images = test_images / 255.0\n\n  # reshape for feeding into the model\n  train_images = train_images.reshape(train_images.shape[0], 28, 28, 1)\n  test_images = test_images.reshape(test_images.shape[0], 28, 28, 1)\n\n  class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',\n                'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']\n\n  print('\\ntrain_images.shape: {}, of {}'.format(train_images.shape, train_images.dtype))\n  print('test_images.shape: {}, of {}'.format(test_images.shape, test_images.dtype))\n\n  return train_images, train_labels, test_images, test_labels\n\ndef train(train_images, train_labels, epochs, model_summary_path):\n  if model_summary_path:\n    logdir=model_summary_path # + datetime.now().strftime(\"%Y%m%d-%H%M%S\")\n    tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir)\n\n  model = keras.Sequential([\n    keras.layers.Conv2D(input_shape=(28,28,1), filters=8, kernel_size=3,\n                        strides=2, activation='relu', name='Conv1'),\n    keras.layers.Flatten(),\n    keras.layers.Dense(10, activation=tf.nn.softmax, name='Softmax')\n  ])\n  model.summary()\n\n  model.compile(optimizer=tf.train.AdamOptimizer(),\n                loss='sparse_categorical_crossentropy',\n                metrics=['accuracy']\n                )\n  if model_summary_path:\n    model.fit(train_images, train_labels, epochs=epochs, callbacks=[tensorboard_callback])\n  else:\n    model.fit(train_images, train_labels, epochs=epochs)\n\n  return model\n\ndef eval(model, test_images, test_labels):\n  test_loss, test_acc = model.evaluate(test_images, test_labels)\n  print('\\nTest accuracy: {}'.format(test_acc))\n\ndef export_model(model, model_export_path):\n  version = 1\n  export_path = os.path.join(model_export_path, str(version))\n\n  tf.saved_model.simple_save(\n    keras.backend.get_session(),\n    export_path,\n    inputs={'input_image': model.input},\n    outputs={t.name:t for t in model.outputs})\n\n  print('\\nSaved model: {}'.format(export_path))\n\n\ndef main(argv=None):\n  parser = argparse.ArgumentParser(description='Fashion MNIST Tensorflow Example')\n  parser.add_argument('--model_export_path', type=str, help='Model export path')\n  parser.add_argument('--model_summary_path', type=str,  help='Model summry files for Tensorboard visualization')\n  parser.add_argument('--epochs', type=int, default=5, help='Training epochs')\n  args = parser.parse_args(args=[])\n\n  train_images, train_labels, test_images, test_labels = preprocessing()\n  model = train(train_images, train_labels, args.epochs, args.model_summary_path)\n  eval(model, test_images, test_labels)\n\n  if args.model_export_path:\n    export_model(model, args.model_export_path)\n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/创建和使用jupter笔记本.md",
    "content": "#### 配置kubeflow dashboard\n\n检查kubeflow dashboard状态\n\n```bash\nkubectl get service istio-ingressgateway -n istio-system\nNAME                   TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                                                                                                      AGE\nistio-ingressgateway   NodePort   10.100.239.93   <none>        15020:31062/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32662/TCP,15030:31314/TCP,15031:32088/TCP,15032:30973/TCP,15443:30713/TCP   27h\n```\n\n通过kubectl port-forward端口转发映射本地端口到指定的kubeflow dashboard 80端口\n\n```bash\nkubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80\n```\n\n\n\n#### 访问Kubeflow用户界面\n\n从本地网络浏览器输入http://127.0.0.1:8080/，您就可以进入到Kubeflow UI界面，Kubeflow dashboard默认为无身份验证。点击dashboard中 **Start Setup**，设置namespace 得值为 **eksworkshop**\n\n![](images/dashboard-create-namespace.png)\n\n\n\n点击 **Finish** 浏览kubeflow dashboard\n\n![dashboard-first-look](images/dashboard-first-look.png)\n\n\n\n#### 创建和使用jupter notebook\n\nJupyter notebook 通常用于数据清洗和转换、数值模拟、统计建模、数据可视化、机器学习等。在Kubeflow dashboard中, 点击 **Create a new Notebook server**:\n\n![dashboard-new-notebook-server](images/dashboard-new-notebook-server.png)\n\n\n\n选择您在上一个部步骤中创建的 namespace ：\n\n![jupyter-select-namespace](images/jupyter-select-namespace.png)\n\n\n\n\n\n为jupter notebook指定一个名称:\n\n![jupyter-enter-notebook-server-name](images/jupyter-enter-notebook-server-name.png)\n\n选择Image如下：\n\n![select_image](images/select_image.jpg)\n\n\n\n为创建jupter notebook设置CPU值为 **1.0**:\n\n![jupyter-select-cpu](images/jupyter-select-cpu.png)\n\n滚动到底部，接受所有其他默认设置，然后单击LAUNCH。等待jupter notebook启动。点击**CONNECT**\n\n![jupyter-notebook-servers](images/jupyter-notebook-servers.png)\n\n\n\n在jupter notebook界面里点击 **New**, 选择 **Python3**，创建一个空 Python 3 Jupyter notebook\n\n![jupyter-new-python3-notebook](images/jupyter-new-python3-notebook.png)\n\n#### 训练模型\n\n打开 resouce/mnist-tensorflow-jupyter.py并把代码粘贴到notebook中. 这段Python样例代码会使用TensorFlow基于MNIST数据集训练模型，点击Run运行训练代码。\n\n![jupyter-mnist-code](images/jupyter-mnist-code.png)\n\n运行后会创建一个新的代码块，在这个新代码块中输入main()，然后单击Run\n\n![jupyter-mnist-training](images/jupyter-mnist-training.png)\n\n训练完成后，前几行显示下载了TensorFlow和Keras数据集。训练数据集是60k图像，测试数据集为10k图像，并给出了用于训练的超参数，五次Epoch的输出，训练完成后输出了模型的精度。\n\n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/安装Kubeflow.md",
    "content": "#### 前提\n\n本kubeflow workshop 需要的软件环境有 aws cli , eksctl ,kubectl,e aws-iam-authenticator以及eks对应操作的IAM权限。具体安装步骤请参考[2020_EKS_Launch_Workshop/步骤1-准备实验环境]([https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/%E6%AD%A5%E9%AA%A41-%E5%87%86%E5%A4%87%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83.md](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/china/2020_EKS_Launch_Workshop/步骤1-准备实验环境.md))。\n\n本workshop选择了缺省的kfctl配置文件，以简化kubeflow安装。但是，我们建议在生产环境中安装Cognito配置并添加身份验证和SSL(通过ACM)。有关启用Cognito所需的其他步骤，请参阅[Kubeflow documentation](https://www.kubeflow.org/docs/aws/deploy/install-kubeflow/)文档\n\n#### 设置环境变量\n\n执行以下命令来设置环境变量，然后为这个部署设置Kubeflow应用程序目录,在CLUSTER_NAME指定您的EKS集群名称\n\n```bash\nexport REGION=cn-northwest-1\nexport CLUSTER_NAME=eks\nexport BASE_DIR=$(pwd)\nexport KF_NAME=${CLUSTER_NAME}\nexport KF_DIR=${BASE_DIR}/${KF_NAME}\nexport CONFIG_FILE=${KF_DIR}/kfctl_aws.yaml\n```\n\n#### 使用eksctl创建EKS集群\n\n由于Kubeflow需要较多的资源来部署，通过执行以下操作创建一个6个工作节点EKS集群，大约需要15分钟，请耐心等待。\n\n```bash\neksctl create cluster --name=${CLUSTER_NAME} --nodes=4 --managed --alb-ingress-access --region=${REGION}\n```\n\n获取EKS 工作节点role，配置环境变量用于后续使用\n\n```bash\nexport STACK_NAME=$(eksctl get nodegroup --cluster $CLUSTER_NAME --region $REGION  -o json | jq -r '.[].StackName')\nexport NODE_INSTANCE_ROLE=$(aws cloudformation describe-stack-resources --region $REGION --stack-name $STACK_NAME | jq -r '.StackResources[] | select(.LogicalResourceId==\"NodeInstanceRole\") | .PhysicalResourceId' ) \n```\n\n#### 安装kubeflow\n\n下载并安装kfctl\n\n```\ncurl --silent --location \"https://github.com/kubeflow/kfctl/releases/download/v1.0.1/kfctl_v1.0.1-0-gf3edb9b_linux.tar.gz\" | tar xz -C /tmp\nsudo mv -v /tmp/kfctl /usr/local/bin\n```\n\n配置和下载kubeflow文件，本实验使用非cognito版本，默认不进行身份验证。（注意：如果存在文件不能下载的问题，可以尝试重新运行wget -O ${KF_DIR}/kfctl_aws.yaml $CONFIG_URI）\n\n```bash\nexport CONFIG_URI=\"https://raw.githubusercontent.com/kubeflow/manifests/v1.0-branch/kfdef/kfctl_aws.v1.0.1.yaml\"\nexport KF_NAME=${CLUSTER_NAME}\nmkdir -p ${BASE_DIR}\nexport KF_DIR=${BASE_DIR}/${KF_NAME}\nmkdir -p ${KF_DIR}\nwget -O ${KF_DIR}/kfctl_aws.yaml $CONFIG_URI\nexport CONFIG_FILE=${KF_DIR}/kfctl_aws.yaml\n\n```\n\n替换kfctl_aws.yaml中的region和role为当前的创建eks的region和node节点使用的role\n\n```bash\nsed -i'.bak' ${CONFIG_FILE}\nsed -i -e \"s/eksctl-kubeflow-aws-nodegroup-ng-a2-NodeInstanceRole-xxxxxxx/$NODE_INSTANCE_ROLE/g\" ${CONFIG_FILE}\nsed -i -e 's/us-west-2/'\"$REGION\"'/' ${CONFIG_FILE}\n```\n\n检查kfctl_aws.yaml是否正确替换\n\n```\nregion: cn-northwest-1\nroles:\n- eksctl-kubeflow-example-nodegroup-ng-185-NodeInstanceRole-1DDJJXQBG9EM6\n```\n\nkfclt 本质上是使用了 kustomize 来安装，通过kfctl build生成kubeflow  kustomize配置文件\n\n```bash\nkfctl build -f ${CONFIG_FILE}\n```\n\n由于防火墙或安全限制，海外gcr.io, quay.io的镜像可能无法下载，需要通过修改镜像的方式安装，把镜像url替换成aws国内镜像站点url：\n\n```bash\nsed -i \"s/gcr.io/048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn\\/gcr/g\" `grep \"gcr.io\" -rl ${KF_DIR}`\nsed -i \"s/quay.io/048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn\\/quay/g\" `grep \"quay.io\" -rl ${KF_DIR}`\n```\n\n开始部署kubeflow\n\n```bash\nkfctl apply -V -f ${CONFIG_FILE}\n```\n\n安装Kubeflow及其工具集可能需要数分钟。有一些的pod最初可能会出现Error或CrashLoopBackOff状态。需要一些时间，它们会自动修复，并进入运行状态\n\n\n\n#### 验证kubeflow是否成功部署\n\n运行下面的命令检查状态\n\n```\nkubectl -n kubeflow get all\n```\n\n如果一段时间后仍不正常，请通过查看日志进行故障排除\n\n<details>\n<summary>状态信息</summary>\n<pre><codes>\n$ kubectl -n kubeflow get all                         \nNAME                                                               READY   STATUS      RESTARTS   AGE\npod/admission-webhook-bootstrap-stateful-set-0                     1/1     Running     0          5m50s\npod/admission-webhook-deployment-64cb96ddbf-x2zfm                  1/1     Running     0          5m12s\npod/alb-ingress-controller-c76dd95d-z2kc7                          1/1     Running     0          5m45s\npod/application-controller-stateful-set-0                          1/1     Running     0          6m32s\npod/argo-ui-778676df64-w4lpj                                       1/1     Running     0          5m51s\npod/centraldashboard-7dd7dd685d-fjnr2                              1/1     Running     0          5m51s\npod/jupyter-web-app-deployment-89789fd5-pmwmf                      1/1     Running     0          5m50s\npod/katib-controller-6b789b6cb5-rc7xz                              1/1     Running     1          5m48s\npod/katib-db-manager-64f548b47c-6p6nv                              1/1     Running     0          5m48s\npod/katib-mysql-57884cb488-6g9zk                                   1/1     Running     0          5m48s\npod/katib-ui-5c5cc6bd77-mwmrl                                      1/1     Running     0          5m48s\npod/metacontroller-0                                               1/1     Running     0          5m51s\npod/metadata-db-76c9f78f77-pjvh8                                   1/1     Running     0          5m49s\npod/metadata-deployment-674fdd976b-946k6                           1/1     Running     0          5m49s\npod/metadata-envoy-deployment-5688989bd6-j5bdh                     1/1     Running     0          5m49s\npod/metadata-grpc-deployment-5579bdc87b-fc88k                      1/1     Running     2          5m49s\npod/metadata-ui-9b8cd699d-drm2p                                    1/1     Running     0          5m49s\npod/minio-755ff748b-hdfwk                                          1/1     Running     0          5m47s\npod/ml-pipeline-79b4f85cbc-hcttq                                   1/1     Running     5          5m47s\npod/ml-pipeline-ml-pipeline-visualizationserver-5fdffdc5bf-nqjb5   1/1     Running     0          5m46s\npod/ml-pipeline-persistenceagent-645cb66874-rgrt4                  1/1     Running     1          5m47s\npod/ml-pipeline-scheduledworkflow-6c978b6b85-dxgw4                 1/1     Running     0          5m46s\npod/ml-pipeline-ui-6995b7bccf-ktwb2                                1/1     Running     0          5m47s\npod/ml-pipeline-viewer-controller-deployment-8554dc7b9f-n4ccc      1/1     Running     0          5m46s\npod/mpi-operator-5bf8b566b7-gkbz9                                  1/1     Running     0          5m45s\npod/mysql-598bc897dc-srtpt                                         1/1     Running     0          5m47s\npod/notebook-controller-deployment-7db57b9ccf-4pqkw                1/1     Running     0          5m49s\npod/nvidia-device-plugin-daemonset-4s9tv                           1/1     Running     0          5m46s\npod/nvidia-device-plugin-daemonset-5p8kn                           1/1     Running     0          5m46s\npod/nvidia-device-plugin-daemonset-84jv6                           1/1     Running     0          5m46s\npod/nvidia-device-plugin-daemonset-d7x5f                           1/1     Running     0          5m46s\npod/nvidia-device-plugin-daemonset-m8cpr                           1/1     Running     0          5m46s\npod/profiles-deployment-b45dbc6f-7jfqw                             2/2     Running     0          5m46s\npod/pytorch-operator-5fd5f94bdd-dbddk                              1/1     Running     0          5m49s\npod/seldon-controller-manager-679fc777cd-58vzl                     1/1     Running     0          5m45s\npod/spark-operatorcrd-cleanup-tc4nw                                0/2     Completed   0          5m50s\npod/spark-operatorsparkoperator-c7b64b87f-w6glw                    1/1     Running     0          5m50s\npod/spartakus-volunteer-5b7d86d9cd-2z4dn                           1/1     Running     0          5m49s\npod/tensorboard-6544748d94-dr87g                                   1/1     Running     0          5m48s\npod/tf-job-operator-7d7c8fb8bb-bh2j9                               1/1     Running     0          5m48s\npod/workflow-controller-945c84565-ctx84                            1/1     Running     0          5m51s\n\n\nNAME                                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE\nservice/admission-webhook-service                     ClusterIP   10.100.34.137    <none>        443/TCP             5m50s\nservice/application-controller-service                ClusterIP   10.100.122.252   <none>        443/TCP             6m32s\nservice/argo-ui                                       NodePort    10.100.56.77     <none>        80:32722/TCP        5m51s\nservice/centraldashboard                              ClusterIP   10.100.122.184   <none>        80/TCP              5m51s\nservice/jupyter-web-app-service                       ClusterIP   10.100.184.50    <none>        80/TCP              5m50s\nservice/katib-controller                              ClusterIP   10.100.96.16     <none>        443/TCP,8080/TCP    5m48s\nservice/katib-db-manager                              ClusterIP   10.100.161.38    <none>        6789/TCP            5m48s\nservice/katib-mysql                                   ClusterIP   10.100.186.115   <none>        3306/TCP            5m48s\nservice/katib-ui                                      ClusterIP   10.100.110.39    <none>        80/TCP              5m48s\nservice/metadata-db                                   ClusterIP   10.100.92.177    <none>        3306/TCP            5m49s\nservice/metadata-envoy-service                        ClusterIP   10.100.17.145    <none>        9090/TCP            5m49s\nservice/metadata-grpc-service                         ClusterIP   10.100.238.212   <none>        8080/TCP            5m49s\nservice/metadata-service                              ClusterIP   10.100.183.244   <none>        8080/TCP            5m49s\nservice/metadata-ui                                   ClusterIP   10.100.28.97     <none>        80/TCP              5m49s\nservice/minio-service                                 ClusterIP   10.100.185.36    <none>        9000/TCP            5m48s\nservice/ml-pipeline                                   ClusterIP   10.100.45.162    <none>        8888/TCP,8887/TCP   5m48s\nservice/ml-pipeline-ml-pipeline-visualizationserver   ClusterIP   10.100.211.60    <none>        8888/TCP            5m47s\nservice/ml-pipeline-tensorboard-ui                    ClusterIP   10.100.150.113   <none>        80/TCP              5m47s\nservice/ml-pipeline-ui                                ClusterIP   10.100.135.60    <none>        80/TCP              5m47s\nservice/mysql                                         ClusterIP   10.100.37.144    <none>        3306/TCP            5m48s\nservice/notebook-controller-service                   ClusterIP   10.100.250.183   <none>        443/TCP             5m49s\nservice/profiles-kfam                                 ClusterIP   10.100.24.246    <none>        8081/TCP            5m47s\nservice/pytorch-operator                              ClusterIP   10.100.104.208   <none>        8443/TCP            5m49s\nservice/seldon-webhook-service                        ClusterIP   10.100.68.153    <none>        443/TCP             5m46s\nservice/tensorboard                                   ClusterIP   10.100.25.5      <none>        9000/TCP            5m49s\nservice/tf-job-operator                               ClusterIP   10.100.165.41    <none>        8443/TCP            5m48s\n\nNAME                                            DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE\ndaemonset.apps/nvidia-device-plugin-daemonset   5         5         5       5            5           <none>          5m46s\n\nNAME                                                          READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps/admission-webhook-deployment                  1/1     1            1           5m50s\ndeployment.apps/alb-ingress-controller                        1/1     1            1           5m46s\ndeployment.apps/argo-ui                                       1/1     1            1           5m51s\ndeployment.apps/centraldashboard                              1/1     1            1           5m51s\ndeployment.apps/jupyter-web-app-deployment                    1/1     1            1           5m50s\ndeployment.apps/katib-controller                              1/1     1            1           5m48s\ndeployment.apps/katib-db-manager                              1/1     1            1           5m48s\ndeployment.apps/katib-mysql                                   1/1     1            1           5m48s\ndeployment.apps/katib-ui                                      1/1     1            1           5m48s\ndeployment.apps/metadata-db                                   1/1     1            1           5m49s\ndeployment.apps/metadata-deployment                           1/1     1            1           5m49s\ndeployment.apps/metadata-envoy-deployment                     1/1     1            1           5m49s\ndeployment.apps/metadata-grpc-deployment                      1/1     1            1           5m49s\ndeployment.apps/metadata-ui                                   1/1     1            1           5m49s\ndeployment.apps/minio                                         1/1     1            1           5m48s\ndeployment.apps/ml-pipeline                                   1/1     1            1           5m48s\ndeployment.apps/ml-pipeline-ml-pipeline-visualizationserver   1/1     1            1           5m47s\ndeployment.apps/ml-pipeline-persistenceagent                  1/1     1            1           5m48s\ndeployment.apps/ml-pipeline-scheduledworkflow                 1/1     1            1           5m47s\ndeployment.apps/ml-pipeline-ui                                1/1     1            1           5m47s\ndeployment.apps/ml-pipeline-viewer-controller-deployment      1/1     1            1           5m47s\ndeployment.apps/mpi-operator                                  1/1     1            1           5m46s\ndeployment.apps/mysql                                         1/1     1            1           5m48s\ndeployment.apps/notebook-controller-deployment                1/1     1            1           5m49s\ndeployment.apps/profiles-deployment                           1/1     1            1           5m47s\ndeployment.apps/pytorch-operator                              1/1     1            1           5m49s\ndeployment.apps/seldon-controller-manager                     1/1     1            1           5m46s\ndeployment.apps/spark-operatorsparkoperator                   1/1     1            1           5m50s\ndeployment.apps/spartakus-volunteer                           1/1     1            1           5m49s\ndeployment.apps/tensorboard                                   1/1     1            1           5m49s\ndeployment.apps/tf-job-operator                               1/1     1            1           5m48s\ndeployment.apps/workflow-controller                           1/1     1            1           5m51s\n\nNAME                                                                     DESIRED   CURRENT   READY   AGE\nreplicaset.apps/admission-webhook-deployment-64cb96ddbf                  1         1         1       5m50s\nreplicaset.apps/alb-ingress-controller-c76dd95d                          1         1         1       5m45s\nreplicaset.apps/argo-ui-778676df64                                       1         1         1       5m51s\nreplicaset.apps/centraldashboard-7dd7dd685d                              1         1         1       5m51s\nreplicaset.apps/jupyter-web-app-deployment-89789fd5                      1         1         1       5m50s\nreplicaset.apps/katib-controller-6b789b6cb5                              1         1         1       5m48s\nreplicaset.apps/katib-db-manager-64f548b47c                              1         1         1       5m48s\nreplicaset.apps/katib-mysql-57884cb488                                   1         1         1       5m48s\nreplicaset.apps/katib-ui-5c5cc6bd77                                      1         1         1       5m48s\nreplicaset.apps/metadata-db-76c9f78f77                                   1         1         1       5m49s\nreplicaset.apps/metadata-deployment-674fdd976b                           1         1         1       5m49s\nreplicaset.apps/metadata-envoy-deployment-5688989bd6                     1         1         1       5m49s\nreplicaset.apps/metadata-grpc-deployment-5579bdc87b                      1         1         1       5m49s\nreplicaset.apps/metadata-ui-9b8cd699d                                    1         1         1       5m49s\nreplicaset.apps/minio-755ff748b                                          1         1         1       5m47s\nreplicaset.apps/ml-pipeline-79b4f85cbc                                   1         1         1       5m47s\nreplicaset.apps/ml-pipeline-ml-pipeline-visualizationserver-5fdffdc5bf   1         1         1       5m46s\nreplicaset.apps/ml-pipeline-persistenceagent-645cb66874                  1         1         1       5m47s\nreplicaset.apps/ml-pipeline-scheduledworkflow-6c978b6b85                 1         1         1       5m46s\nreplicaset.apps/ml-pipeline-ui-6995b7bccf                                1         1         1       5m47s\nreplicaset.apps/ml-pipeline-viewer-controller-deployment-8554dc7b9f      1         1         1       5m46s\nreplicaset.apps/mpi-operator-5bf8b566b7                                  1         1         1       5m45s\nreplicaset.apps/mysql-598bc897dc                                         1         1         1       5m47s\nreplicaset.apps/notebook-controller-deployment-7db57b9ccf                1         1         1       5m49s\nreplicaset.apps/profiles-deployment-b45dbc6f                             1         1         1       5m46s\nreplicaset.apps/pytorch-operator-5fd5f94bdd                              1         1         1       5m49s\nreplicaset.apps/seldon-controller-manager-679fc777cd                     1         1         1       5m45s\nreplicaset.apps/spark-operatorsparkoperator-c7b64b87f                    1         1         1       5m50s\nreplicaset.apps/spartakus-volunteer-5b7d86d9cd                           1         1         1       5m49s\nreplicaset.apps/tensorboard-6544748d94                                   1         1         1       5m48s\nreplicaset.apps/tf-job-operator-7d7c8fb8bb                               1         1         1       5m48s\nreplicaset.apps/workflow-controller-945c84565                            1         1         1       5m51s\n\nNAME                                                        READY   AGE\nstatefulset.apps/admission-webhook-bootstrap-stateful-set   1/1     5m50s\nstatefulset.apps/application-controller-stateful-set        1/1     6m32s\nstatefulset.apps/metacontroller                             1/1     5m51s\n\nNAME                                  COMPLETIONS   DURATION   AGE\njob.batch/spark-operatorcrd-cleanup   1/1           42s        5m50s\n</codes></pre>\n</details>\n\n\n#### 可选操作：创建profile\n\nKubeflow提供多租户支持，用户无法在Kubeflow的默认名称空间中创建笔记本。\n\n第一次访问kubeflow时，可以使用一个匿名命名空间。如果您想要创建不同的jupter用户空间，您可以创建配置文件，然后运行kubectl apply -f Profile .yaml。kubeflow配置文件控制器将创建新的名称空间和服务帐户，允许在该名称空间中创建笔记本。\n\n```yaml\napiVersion: kubeflow.org/v1beta1\nkind: Profile\nmetadata:\n  name: aws-sample-user\nspec:\n  owner:\n    kind: User\n    name: aws-sample-user\n```\n\n"
  },
  {
    "path": "china/2020_GCR_Kubeflow_Workshop/清理资源.md",
    "content": "使用以下命令将其删除\n\n```bash\ncd  ${KF_DIR} \n#这将删除通过kfctl创建的kubeflow和istio-system名称空间。\nkfctl delete -f ${CONFIG_FILE} \n#删除eks cluster\neksctl delete cluster kubeflow\n```\n\n如果eksclt delete失败，请手动删除CloudFormation堆栈。将策略手动添加到IAM角色或更改安全组甚至可能失败，因此您可能需要手动还原或删除它。如果您忘记删除它，则需要付费，因此您可能需要在AWS管理控制台中确认删除。"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/Kubeflow on AWS EKS (GCR Region) 部署.md",
    "content": "## Kubeflow on AWS EKS (GCR Region)\n\n### 前置条件\n\n* 安装命令行工具\n\n```bash\n#使用pip安装aws cli ,其他方式请阅读参考文档\npip install awscli\n#配置权限\naws configure\n\n#kubectl v1.20.0\n#macbook\ncurl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.20.4/2021-04-12/bin/darwin/amd64/kubectl\n\n#linux\ncurl -o kubectl https://amazon-eks.s3.us-west-2.amazonaws.com/1.20.4/2021-04-12/bin/linux/amd64/kubectl\n\n\n#eksctl 0.54.0\n#macbook\ncurl -OL https://github.com/weaveworks/eksctl/releases/download/0.54.0/eksctl_Darwin_amd64.tar.gz\n\n#kfctl v1.2.0-0-gbc038f9\n#macbook\ncurl -OL https://github.com/kubeflow/kfctl/releases/download/v1.2.0/kfctl_v1.2.0-0-gbc038f9_darwin.tar.gz\n\n#linux \ncurl -OL https://github.com/kubeflow/kfctl/releases/download/v1.2.0/kfctl_v1.2.0-0-gbc038f9_linux.tar.gz\n \ntar -zxvf kfctl_v1.2.0-0-gbc038f9_darwin.tar.gz\n\n#aws-iam-authenticator\n\n#macbook\ncurl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.9/2020-11-02/bin/darwin/amd64/aws-iam-authenticator\n\n#linux\ncurl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.9/2020-11-02/bin/linux/amd64/aws-iam-authenticator\n\n#jq \n#macbook\nbrew install jq\n#linux \n#CentOS, Amaon Linux\nyum install jq\n#ubuntu\napt-get install jq\n\n```\n\n\n\n### 1. Create AWS EKS Cluster\n\n使用标准模板创建eks cluster,  集群名字 kubeflow-workshop,模版会创建一个CPU工作组eks-prod-cpu-ng-1(m5.2xlarge 3台), GPU工作组 eks-prod-gpu-ng-1(g4dn.xlarge 1台)\n\n```bash\n#步骤1 修改kubeflow-workshop-eks.yaml中的publicKeyName(必须)\n#publicKeyName: <aws keypair name> \n\n#步骤2 创建集群(也可以通过其他方式创建EKS集群)\neksctl create cluster -f ./resource/kubeflow-workshop-eks.yaml\n\n#步骤3 检查EKS节点状态是否就绪\nkubectl get node \n\n```\n\n### 2. 配置NWCD 镜像 mutating-webhook\n\n具体参考https://github.com/nwcdlabs/container-mirror, 主要作用就是自动转换gcr.io到048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn/gcr, kubeflow 1.2所需要的全部镜像已经推送到NWCD的镜像仓库\n\n```bash\n#步骤1 安装 mutating-webhook\nkubectl apply -f resource/mutating-webhook.yaml\n\n#步骤2 验证是否生效\nkubectl run test --image=k8s.gcr.io/coredns:1.3.1\nkubectl get pod test -o=jsonpath='{.spec.containers[0].image}'\n#如果显示 048912060910.dkr.ecr.cn-northwest-1.amazonaws.com.cn/gcr/google_containers/coredns:1.3.1 表示mutating-webhook 工作正常\n#删除测试pod\nkubectl delete pod test\n\n\n```\n\n### 3. 安装kubeflow 1.2\n\n请使用resource目录下的manifests-1.2.0.tar.gz\n\n```bash\nexport CLUSTER_NAME=kubeflow-workshop\nmkdir ${CLUSTER_NAME}\ncd ${CLUSTER_NAME}\n\n#步骤1 生成配置文件 kfctl_aws.v1.2.0.yaml \nsed -e \"s/{FULL_PATH}/$(echo $PWD | sed 's_/_\\\\/_g')/g\" kfctl_aws.v1.2.0.yaml.tpl > kfctl_aws.v1.2.0.yaml\n\n\n#步骤2 部署kubeflow v1.2.0, 如果中间有问题请删除当前目录下面.cache目录\nkfctl apply -V -f kfctl_aws.v1.2.0.yaml\n\n\n#步骤3 验证kubeflow是否部署成功,如果pod都是runing就表示成功运行了\nkubectl get all -n kubeflow\n\n\n#步骤4 更新ALB ingress controller 需要的权限和配置\n#4.1 创建Policy\nexport AWS_REGION=cn-northwest-1\nexport CLUSTER_NAME=kubeflow-workshop\n\naws iam create-policy --policy-name ALBIngressControllerIAMPolicy \\\n  --policy-document file://./resource/ingress-iam-policy.json --region \n  ${AWS_REGION}\n\nPOLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==`ALBIngressControllerIAMPolicy`].Arn' --output text --region ${AWS_REGION})\n\n#4.2. 创建EKS OIDC provider\neksctl utils  associate-iam-oidc-provider  --cluster=${CLUSTER_NAME} --approve\n\n#4.3 关联service account \neksctl create iamserviceaccount \\\n       --cluster=${CLUSTER_NAME} \\\n       --namespace=kubeflow \\\n       --name=alb-ingress-controller \\\n       --attach-policy-arn=${POLICY_NAME} \\\n       --override-existing-serviceaccounts \\\n       --approve\n       \n\n#4.3 并重启ALB Ingress Controller\nkubectl rollout restart deployment alb-ingress-controller -n kubeflow\n\n#5. 获取kubeflow URL\nkubectl get ingress -n istio-system\n\n\n\n```\n\n\n\n### 4. 配置多用户\n\n```bash\n# 静态用户文件 dex-config.yaml\n# 密码需要使用https://passwordhashing.com/BCrypt 生成\n# 这里的默认密码是abcd1234\n\n# 修改后dex-config.yaml提交\ncd resource\nkubectl create configmap dex --from-file=config.yaml=dex-config.yaml -n auth --dry-run -oyaml | kubectl apply -f -\n\n# 重启dex应用\nkubectl rollout restart deployment dex -n auth\n\n\n#创建完后使用admin@kubeflow.com/abcd1234, app1@kubeflow.com/abcd1234, 登陆会自动创建namespace\n```\n\n### 5. 配置用户配额\n\n```bash\n#修改app1.yaml\nkubectl apply -f app1.yaml\n```\n\n\n\n### 6. 配置用户权限(可选)\n\n* IAM 创建policy 限制s3访问\n\n  ```bash\n  #s3-kubeflow-on-eks-app1.json 里面使用的s3 bucket 是kubeflow-on-eks-app1\n  #请自行修改\n  \n  export AWS_REGION=cn-northwest-1\n  export CLUSTER_NAME=kubeflow-workshop\n  \n  aws iam create-policy --policy-name s3-kubeflow-on-eks-app1 \\\n    --policy-document file://./resource/s3-kubeflow-on-eks-app1.json --region ${AWS_REGION}\n    \n  ```\n  \n* 使用eksctl管理service account\n\n  ```bash\n  \n  #请重复为app1的service account 设置IAM role\n  POLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==`s3-kubeflow-on-eks-app1`].Arn' --output text --region ${AWS_REGION})\n  \n  eksctl create iamserviceaccount \\\n         --cluster=${CLUSTER_NAME} \\\n         --namespace=app1 \\\n         --name=default-editor \\\n         --attach-policy-arn=${POLICY_NAME} \\\n         --override-existing-serviceaccounts \\\n         --approve\n  ```\n\n  \n\n\n### 问题列表\n\n* dex 配置ldap \n\n  参考文档:\n\n  * openldap 使用https://docs.bitnami.com/tutorials/create-openldap-server-kubernetes/#step-1-create-and-install-the-openldap-server-on-your-cluster)\n  * dex with ldap https://github.com/dexidp/dex/blob/master/examples/ldap/\n\n  \n\n  ```bash\n  #添加secret密码\n  kubectl create secret generic openldap --from-literal=adminpassword=adminpassword --from-literal=users=user01 --from-literal=passwords=password01\n  \n  #部署openldap\n  kubectl apply -f openldap.yaml -n auth\n  \n  #\n  kubectl exec -ti $(kubectl get pod -n auth | grep openldap | awk '{print $1}') -n auth -- bash \n  \n  ldapdelete -x -H ldap://localhost:1389  -D \"cn=admin,dc=example,dc=org\" -w adminpassword  \"cn=user01,ou=users,dc=example,dc=org\"\n  \n  ldapadd -x -H ldap://localhost:1389 -D \"cn=admin,dc=example,dc=org\" -w adminpassword -f users.ldif\n  \n  \n  ldapsearch  -x -H ldap://localhost:1389  -b dc=example,dc=org -D \"cn=admin,dc=example,dc=org\" -w adminpassword\n  \n  ldappasswd -x -H ldap://localhost:1389 -D \"cn=admin,dc=example,dc=org\" -w adminpassword  \"cn=user01,ou=users,dc=example,dc=org\"\n  \n  \n  #分别设置user01-user04密码\n  ldappasswd -x -H ldap://localhost:1389 -D \"cn=admin,dc=example,dc=org\" -w admin  \"cn=user01,ou=users,dc=example,dc=org\"\n  user01@example.org/IhlXjrOo\n  user02@example.org/5MZ4rMKr\n  user03@example.org/oiCK1oWB\n  user04@example.org/HlUqcbwC\n  \n  ```\n\n\n\n  \n\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/app1.yaml",
    "content": "apiVersion: kubeflow.org/v1beta1\nkind: Profile\nmetadata:\n  name: app1  # replace with the name of profile you want, this will be user's namespace name\nspec:\n  owner:\n    kind: User\n    name: app1@kubeflow.com  # replace with the email of the user\n\n  resourceQuotaSpec:    # resource quota can be set optionally\n   hard:\n     cpu: \"2\"\n     memory: 2Gi\n     nvidia.com/gpu: \"0\"\n     persistentvolumeclaims: \"5\"\n     requests.storage: \"50Gi\"\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/aws-alb-config-map.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  labels:\n    app: aws-alb-ingress-controller\n    kustomize.component: aws-alb-ingress-controller\n  name: aws-alb-ingress-controller-config\n  namespace: kubeflow\ndata:\n  cluster-name: kubeflow-workshop\n\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/dex-config.yaml",
    "content": "issuer: http://dex.auth.svc.cluster.local:5556/dex\nstorage:\n  type: kubernetes\n  config:\n    inCluster: true\nweb:\n  http: 0.0.0.0:5556\nlogger:\n  level: \"debug\"\n  format: text\noauth2:\n  skipApprovalScreen: true\nenablePasswordDB: true\n\nstaticPasswords:\n- email: admin@kubeflow.com\n  hash: $2b$10$7rlrsR0svw3ON0A7gLVVRuXFXz890XfrP8vRSeGywI7YlqnJni.3e\n  username: admin\n  userID: 08a8684b-db88-4b73-90a9-3cd1661f5466\n- email: app1@kubeflow.com\n  hash: $2b$10$7rlrsR0svw3ON0A7gLVVRuXFXz890XfrP8vRSeGywI7YlqnJni.3e\n  username: app1\n  userID: 08a8684b-db88-4c72-90a1-3cd1661f5477\n\n\nstaticClients:\n- id: kubeflow-oidc-authservice\n  redirectURIs: [\"/login/oidc\"]\n  name: 'Dex Login Application'\n  secret: pUBnBOY80SnXgjibTYM9ZWNzY2xreNGQok\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/ingress-iam-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"acm:DescribeCertificate\",\n        \"acm:ListCertificates\",\n        \"acm:GetCertificate\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:AuthorizeSecurityGroupIngress\",\n        \"ec2:CreateSecurityGroup\",\n        \"ec2:CreateTags\",\n        \"ec2:DeleteTags\",\n        \"ec2:DeleteSecurityGroup\",\n        \"ec2:DescribeAccountAttributes\",\n        \"ec2:DescribeAddresses\",\n        \"ec2:DescribeInstances\",\n        \"ec2:DescribeInstanceStatus\",\n        \"ec2:DescribeInternetGateways\",\n        \"ec2:DescribeNetworkInterfaces\",\n        \"ec2:DescribeSecurityGroups\",\n        \"ec2:DescribeSubnets\",\n        \"ec2:DescribeTags\",\n        \"ec2:DescribeVpcs\",\n        \"ec2:ModifyInstanceAttribute\",\n        \"ec2:ModifyNetworkInterfaceAttribute\",\n        \"ec2:RevokeSecurityGroupIngress\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"elasticloadbalancing:AddListenerCertificates\",\n        \"elasticloadbalancing:AddTags\",\n        \"elasticloadbalancing:CreateListener\",\n        \"elasticloadbalancing:CreateLoadBalancer\",\n        \"elasticloadbalancing:CreateRule\",\n        \"elasticloadbalancing:CreateTargetGroup\",\n        \"elasticloadbalancing:DeleteListener\",\n        \"elasticloadbalancing:DeleteLoadBalancer\",\n        \"elasticloadbalancing:DeleteRule\",\n        \"elasticloadbalancing:DeleteTargetGroup\",\n        \"elasticloadbalancing:DeregisterTargets\",\n        \"elasticloadbalancing:DescribeListenerCertificates\",\n        \"elasticloadbalancing:DescribeListeners\",\n        \"elasticloadbalancing:DescribeLoadBalancers\",\n        \"elasticloadbalancing:DescribeLoadBalancerAttributes\",\n        \"elasticloadbalancing:DescribeRules\",\n        \"elasticloadbalancing:DescribeSSLPolicies\",\n        \"elasticloadbalancing:DescribeTags\",\n        \"elasticloadbalancing:DescribeTargetGroups\",\n        \"elasticloadbalancing:DescribeTargetGroupAttributes\",\n        \"elasticloadbalancing:DescribeTargetHealth\",\n        \"elasticloadbalancing:ModifyListener\",\n        \"elasticloadbalancing:ModifyLoadBalancerAttributes\",\n        \"elasticloadbalancing:ModifyRule\",\n        \"elasticloadbalancing:ModifyTargetGroup\",\n        \"elasticloadbalancing:ModifyTargetGroupAttributes\",\n        \"elasticloadbalancing:RegisterTargets\",\n        \"elasticloadbalancing:RemoveListenerCertificates\",\n        \"elasticloadbalancing:RemoveTags\",\n        \"elasticloadbalancing:SetIpAddressType\",\n        \"elasticloadbalancing:SetSecurityGroups\",\n        \"elasticloadbalancing:SetSubnets\",\n        \"elasticloadbalancing:SetWebACL\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iam:CreateServiceLinkedRole\",\n        \"iam:GetServerCertificate\",\n        \"iam:ListServerCertificates\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"cognito-idp:DescribeUserPoolClient\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"tag:GetResources\",\n        \"tag:TagResources\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/kfctl_aws.v1.2.0.yaml",
    "content": "apiVersion: kfdef.apps.kubeflow.org/v1\nkind: KfDef\nmetadata:\n  clusterName: VOLVO-KUBEFLOW-EKS.cn-northwest-1.eksctl.io\n  creationTimestamp: null\n  name: kubeflow-on-eks\n  namespace: kubeflow\nspec:\n  applications:\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: namespaces/base\n    name: namespaces\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: application/v3\n    name: application\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/istio-1-3-1-stack\n    name: istio-stack\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cluster-local-gateway-1-3-1\n    name: cluster-local-gateway\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: istio/istio/base\n    name: istio\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cert-manager-crds\n    name: cert-manager-crds\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cert-manager-kube-system-resources\n    name: cert-manager-kube-system-resources\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cert-manager\n    name: cert-manager\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: metacontroller/base\n    name: metacontroller\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/oidc-authservice\n    name: oidc-authservice\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/dex-auth\n    name: dex\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: admission-webhook/bootstrap/overlays/application\n    name: bootstrap\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: spark/spark-operator/overlays/application\n    name: spark-operator\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws\n    name: kubeflow-apps\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: aws/istio-ingress/base_v3\n    name: istio-ingress\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: knative/installs/generic\n    name: knative\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: kfserving/installs/generic\n    name: kfserving\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/spartakus\n    name: spartakus\n  plugins:\n  - kind: KfAwsPlugin\n    metadata:\n      creationTimestamp: null\n      name: aws\n    spec:\n      auth:\n        basicAuth:\n          password: 12341234\n          username: admin@kubeflow.org\n      enablePodIamPolicy: false\n      region: cn-northwest-1\n  repos:\n  - name: manifests\n    uri: https://github.com/kubeflow/manifests/archive/v1.2.0.tar.gz\n  version: v1.2-branch\nstatus:\n  reposCache:\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/kfctl_aws.v1.2.0.yaml.tpl",
    "content": "apiVersion: kfdef.apps.kubeflow.org/v1\nkind: KfDef\nmetadata:\n  annotations:\n    kfctl.kubeflow.io/force-delete: \"false\"\n  clusterName: kubeflow-workshop.cn-northwest-1.eksctl.io\n  creationTimestamp: null\n  name: kubeflow-workshop\n  namespace: kubeflow\nspec:\n  applications:\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: namespaces/base\n    name: namespaces\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: application/v3\n    name: application\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/istio-1-3-1-stack\n    name: istio-stack\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cluster-local-gateway-1-3-1\n    name: cluster-local-gateway\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: istio/istio/base\n    name: istio\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cert-manager-crds\n    name: cert-manager-crds\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cert-manager-kube-system-resources\n    name: cert-manager-kube-system-resources\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/cert-manager\n    name: cert-manager\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: metacontroller/base\n    name: metacontroller\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/oidc-authservice\n    name: oidc-authservice\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/dex-auth\n    name: dex\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: admission-webhook/bootstrap/overlays/application\n    name: bootstrap\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: spark/spark-operator/overlays/application\n    name: spark-operator\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws\n    name: kubeflow-apps\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: aws/istio-ingress/base_v3\n    name: istio-ingress\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: knative/installs/generic\n    name: knative\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: kfserving/installs/generic\n    name: kfserving\n  - kustomizeConfig:\n      repoRef:\n        name: manifests\n        path: stacks/aws/application/spartakus\n    name: spartakus\n  plugins:\n  - kind: KfAwsPlugin\n    metadata:\n      creationTimestamp: null\n      name: aws\n    spec:\n      auth:\n        basicAuth:\n          password: 12341234\n          username: admin@kubeflow.org\n      enablePodIamPolicy: false\n      region: cn-northwest-1\n  repos:\n  - name: manifests\n    uri: file:{FULL_PATH}/manifests-1.2.0.tar.gz\n  version: v1.2-branch\nstatus:\n  reposCache:\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n  - localPath: '\".cache/manifests/manifests-1.2.0\"'\n    name: manifests\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/kubeflow-workshop-eks.yaml",
    "content": "apiVersion: eksctl.io/v1alpha5\nkind: ClusterConfig\n\nmetadata:\n  name: kubeflow-workshop\n  region: cn-northwest-1\n  version: \"1.18\"\n\n\nnodeGroups:\n  - name: eks-prod-cpu-ng-1\n    instanceType: m5.2xlarge\n    desiredCapacity: 2\n    minSize: 1\n    maxSize: 3\n    volumeSize: 50\n    ssh:\n      allow: true \n      publicKeyName: wsu-cn-northwest-1\n    iam:\n      withAddonPolicies:\n        autoScaler: true\n        ebs: true\n        efs: true\n        cloudWatch: true\n        albIngress: true\n\n\n  - name: eks-prod-gpu-ng-1\n    instanceType: g4dn.xlarge\n    desiredCapacity: 1\n    minSize: 1\n    maxSize: 1  \n    volumeSize: 100\n    ssh:\n      allow: true \n      publicKeyName: wsu-cn-northwest-1\n    iam:\n      withAddonPolicies:\n        autoScaler: true\n        ebs: true\n        efs: true\n        cloudWatch: true\n        albIngress: true\n\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/mutating-webhook.yaml",
    "content": "apiVersion: admissionregistration.k8s.io/v1beta1\nkind: MutatingWebhookConfiguration\nmetadata:\n  name: image-mutating\nwebhooks:\n  - name: image.mutating.webhook\n    failurePolicy: Ignore\n    clientConfig:\n        url: https://cnn2vome4a.execute-api.cn-northwest-1.amazonaws.com.cn/call\n        caBundle: \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ3ekNDQXRlZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBRENCbURFTE1Ba0dBMVVFQmhNQ1ZWTXgKRURBT0JnTlZCQWdUQjBGeWFYcHZibUV4RXpBUkJnTlZCQWNUQ2xOamIzUjBjMlJoYkdVeEpUQWpCZ05WQkFvVApIRk4wWVhKbWFXVnNaQ0JVWldOb2JtOXNiMmRwWlhNc0lFbHVZeTR4T3pBNUJnTlZCQU1UTWxOMFlYSm1hV1ZzClpDQlRaWEoyYVdObGN5QlNiMjkwSUVObGNuUnBabWxqWVhSbElFRjFkR2h2Y21sMGVTQXRJRWN5TUI0WERUQTUKTURrd01UQXdNREF3TUZvWERUTTNNVEl6TVRJek5UazFPVm93Z1pneEN6QUpCZ05WQkFZVEFsVlRNUkF3RGdZRApWUVFJRXdkQmNtbDZiMjVoTVJNd0VRWURWUVFIRXdwVFkyOTBkSE5rWVd4bE1TVXdJd1lEVlFRS0V4eFRkR0Z5ClptbGxiR1FnVkdWamFHNXZiRzluYVdWekxDQkpibU11TVRzd09RWURWUVFERXpKVGRHRnlabWxsYkdRZ1UyVnkKZG1salpYTWdVbTl2ZENCRFpYSjBhV1pwWTJGMFpTQkJkWFJvYjNKcGRIa2dMU0JITWpDQ0FTSXdEUVlKS29aSQpodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQU5VTU9zUXErVTdpOWI0WmwxK09pRk94SHovTHo1OGdFMjBwCk9zZ1BmVHozYTNZNFk5azJZS2liWGx3QWdMSXZXWC8yaC9rbFE0Ym5hUnRTbXBEaGNlUFlMUTFPYi9iSVNkbTIKOHhwV3JpdTJkQlRyei9zbTR4cTZIWll1YWp0WWxJbEhWdjhsb0pOd1U0UGFoSFFVdzJlZUJHZzYzNDVBV2gxSwpUczlEa1R2blZ0WUFjTXRTN250OXJqcm52REg1UmZiQ1lNOFRXUUlyZ013MFI5KzUzcEJsYlFMUExKR21wdWZlCmhSaEpmR1pPb3pwdHFiWHVOQzY2RFFPNE05OUg2N0ZyalNYWm04NkIwVVZHTXBad2g5NENEa2xEaGJac2M3dGsKNm1GQnJNblVWTitITDhjaXNpYk1uMWxVYUovOHZpb3Z4RlVjZFVCZ0Y0VUNWVG1MZndVQ0F3RUFBYU5DTUVBdwpEd1lEVlIwVEFRSC9CQVV3QXdFQi96QU9CZ05WSFE4QkFmOEVCQU1DQVFZd0hRWURWUjBPQkJZRUZKeGZBTitxCkFkY3dLemlJb3JodFNwenlFWkdETUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCTE5xYUVkMm5kT3htZlp5TUkKYnc1aHlmMkUzRi9ZTm9ITjJCdEJMWjlnM2NjYWFOblJib2JoaUNQUEU5NUR6K0kwc3dTZEh5blZ2L2hleU5YQgp2ZTZTYnpKMDhwR0NMNzJDUW5xdEtyY2dmVTI4ZWxVU3doWHF2ZmRxbFM1c2RKL1BITFR5eFFHamhkQnlQcTF6CnF3dWJkUXh0UmJlT2xLeVdON1dnMEk4VlJ3N2o2SVBkai8zdlFRRjN6Q2VwWW9VejhqY0k3M0hQZHdiZXlCa2QKaUVEUGZVWWQveDdINGM3L0k5dkcrbzFWVHFrQzUwY1JSajcwL2IxN0tTYTdxV0ZpTnlpMkxTcjJFSVpreVhDbgowcTIzS1hCNTZqemFZeVdmL1dpM01PeHcrM1dLdDIxZ1o3SWV5TG5wMktodkFvdG5EVTBtVjNIYUlQekJTbENOCnNTaTYKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==\"\n    rules:\n      - operations: [ \"CREATE\", \"UPDATE\" ]\n        apiGroups: [\"\"]\n        apiVersions: [\"v1\"]\n        resources: [\"pods\"]\n"
  },
  {
    "path": "china/2021_GCR_Kubeflow_on_EKS/resource/s3-kubeflow-on-eks-app1.json",
    "content": "{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"VisualEditor0\",\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"s3:PutObject\",\n                \"s3:GetObject\",\n                \"s3:DeleteObject\"\n            ],\n            \"Resource\": \"arn:aws-cn:s3:::kubeflow-on-eks-app1/*\"\n        },\n        {\n            \"Sid\": \"VisualEditor1\",\n            \"Effect\": \"Allow\",\n            \"Action\": \"s3:ListBucket\",\n            \"Resource\": \"arn:aws-cn:s3:::kubeflow-on-eks-app1\"\n        }\n    ]\n}\n"
  },
  {
    "path": "global/2019_GCR_EKS_Workshop/README.md",
    "content": "##AWS EKS Workshop Greater China\n\nAWS EKS Workshop for Learning EKS for Greater China\n\n-   [步骤1: 通过AWSCloud9搭建服务器环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/%E6%AD%A5%E9%AA%A41-%E9%80%9A%E8%BF%87AWS%20Cloud9%E6%90%AD%E5%BB%BA%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%8E%AF%E5%A2%83.md)\n-   [步骤2: 设置默认region, 安装eksctl,kubectl工具](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/%E6%AD%A5%E9%AA%A42-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n-   [步骤3: 创建EKS集群(启用按需实例和Fargate)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/%E6%AD%A5%E9%AA%A43-%E5%88%9B%E5%BB%BAEKS%E9%9B%86%E7%BE%A4(%E5%90%AF%E7%94%A8%E6%8C%89%E9%9C%80%E5%AE%9E%E4%BE%8B%E5%92%8CFargate).md)\n-   [步骤4: 部署示例应用，通过HPA测试Fargate弹性伸缩功能](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/%E6%AD%A5%E9%AA%A44-%E9%83%A8%E7%BD%B2%E7%A4%BA%E4%BE%8B%E5%BA%94%E7%94%A8%EF%BC%8C%E9%80%9A%E8%BF%87HPA%E6%B5%8B%E8%AF%95Fargate%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9%E5%8A%9F%E8%83%BD.md)\n-   [步骤5: 在EKS中使用IAM Role进行权限管理(可选)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/%E6%AD%A5%E9%AA%A45-%E5%9C%A8EKS%E4%B8%AD%E4%BD%BF%E7%94%A8IAM%20Role%E8%BF%9B%E8%A1%8C%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86(%E5%8F%AF%E9%80%89).md)\n\n## License Summary\n\nThis sample code is made available under the MIT-0 license. See the LICENSE file.\n"
  },
  {
    "path": "global/2019_GCR_EKS_Workshop/步骤1-通过AWS Cloud9搭建服务器环境.md",
    "content": "# 进入实验环境\n\n通过浏览器进入 https://dashboard.eventengine.run/ ,填入12位code\n# 步骤1: 通过AWS Cloud9搭建服务器环境\nAWS Cloud9 为您提供了EC2基础设施资源并且一个可视化的编辑器。在本次实验中，您将通过Cloud9去创建一台具有公网访问权限的EC2 实例，运行后续的实验。\n\r\n1.1 打开AWS管理控制台，在Service菜单栏中输入关键字Cloud9，进入Cloud9 管理页面\n  ![](media/15764751257913/15764752078709.jpg)\n\n1.2 点击Create environment,在Environment name and Description内输入 环境的名称 [username]_cloud9，点击 Next Step。\n![](media/15764751257913/15764752501954.jpg)\n\n1.3 保持界面上的默认配置，本次实验不需要改动任何实例环境和网路环境， 点击 Next step\n   ![](media/15764751257913/15764752786196.jpg)\n\n1.4 进入Review界面后，确认无误，点击Create Environment完成创建。此后界面会跳转到 Cloud9 的编辑器页面\n![](media/15764751257913/15764753072137.jpg)\n \n1.5\tCloud9 通常动态生成 IAM 的认证授权信息，但目前和 EKS IAM Authentication 不兼容，因此我们直接给 Cloud 9 EC2 实例附加一个管理员权限的 IAM 角色，并禁止掉 Cloud9 默认的动态 IAM认证授权信息：\n\n* 1）\t创建 IAM 角色\n\n> (1)请新开一个页面,进入[https://console.aws.amazon.com/iam/home#/roles](https://console.aws.amazon.com/iam/home#/roles),选择创建角色 第一步选择 AWS service 并选择 EC2,点击下一步\n\n![](media/15764751257913/15764753509904.png)\n\n> (2)权限中选择 AdministratorAccess,点击下一步\n\n![](media/15764751257913/15764753504307.png)\n\n> (3)输入角色名字 eksworkshop-admin,点击创建角色\n\n![](media/15764751257913/15764753507358.png)\n\n* 2）\t在EC2 Instances界面选择cloud9的EC2实例(名字为aws-cloud9-xxxxx),点击Actions/Instance Settings/Attach/Replace IAM Role,为该实例设置正确的角色\n\n  ![](media/15764751257913/1576503061.png)\n  \n>   选择eksworkshop-admin 角色,点击Apply完成\n\n![](media/15764751257913/15764754031465.png)\n\n* 3）\t关闭cloud9临时权限，并验证角色是否生效.\n![](media/15764751257913/15765030614319.png)\n\n输入:\n\n```bash\n#测试角色是否生效\r\naws sts get-caller-identity\n```\n如果可以正常返回以下内容(包含eksworkshop-admin),则表示已经正确设置角色权限\n```json\n{\r\n    \"Account\": \"<your account id, etc.11111111>\", \r\n    \"UserId\": \"AROAYVRRQ4TUEIX4VRZLN:i-0e011f5bb16f38173\", \r\n    \"Arn\": \"arn:aws:sts:: <your account id, etc.11111111>:assumed-role/eksworkshop-admin/i-0e011f5bb16f38173\"\r\n}\n```\n\n\n\n\n\n"
  },
  {
    "path": "global/2019_GCR_EKS_Workshop/步骤2-设置默认region, 安装eksctl, kubectl工具.md",
    "content": "# 步骤2: 设置默认region, 安装eksctl, kubectl工具\n\n我们将在步骤1创建的AWS Cloud9 环境里面安装eksctl,kubectl。进入Cloud9编辑器环境后，在终端中输入以下命令,进行安装。\n\n```bash\n#设置默认region\nexport AWS_DEFAULT_REGION=ap-northeast-1\r\necho \"export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}\" >> ~/.bashrc\n\n#eksctl\r\ncurl -L \"https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz\" | tar xz -C .\r\nsudo mv ./eksctl /usr/local/bin\r\n\r\n#kubectl\r\ncurl -LO --silent https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl\r\nchmod 775 ./kubectl\r\nsudo mv ./kubectl /usr/local/bin\r\n\n```\n\n>检查工具的版本 eksctl (版本>=0.11.1), kubectl(版本>=1.14)\n\n```bash\neksctl version\nkubectl version\n```\n"
  },
  {
    "path": "global/2019_GCR_EKS_Workshop/步骤3-创建EKS集群(启用按需实例和Fargate).md",
    "content": "# 步骤3: 创建EKS集群(启用按需实例和Fargate)\n\n3.1 打开Cloud9终端管理控制台， 使用eksctl 创建EKS集群(操作需要10-15分钟),该命令同时会创建一个使用t3.small的受管节点组。\n\n ```bash\n eksctl create cluster \\\r\n       --name eksworkshop \\\r\n       --version 1.14 \\\r\n       --node-type t3.small \\\r\n       --nodes 1 \\\r\n       --managed\n ```\n \n ![](media/15764759782724/15764761011094.jpg)\n\n  查看EKS集群工作节点\n  ```bash\n   kubectl get node\n  ```\n  ![](media/15764759782724/15764762619982.jpg)\n\n3.2 (可选)部署一个测试应用\n在Cloud9创建一个nginx.yaml,内容如下\n\n```yaml\n---\r\napiVersion: extensions/v1beta1\r\nkind: Deployment\r\nmetadata:\r\n  name: nginx-deployment\r\n  labels:\r\n    app: nginx\r\nspec:\r\n  replicas: 1\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nginx\r\n    spec:\r\n      containers:\r\n      - name: nginx\r\n        image: nginx\r\n        ports:\r\n        - containerPort: 80\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: \"service-nginx\"\r\n  annotations:\r\n        service.beta.kubernetes.io/aws-load-balancer-type: nlb\r\nspec:\r\n  selector:\r\n    app: nginx\r\n  type: LoadBalancer\r\n  ports:\r\n  - protocol: TCP\r\n    port: 80\r\n    targetPort: 80\r\n\r\n\n\n```\n \n > 部署nginx\n \n ```bash\n  kubectl apply -f nginx.yaml\n\n ```\n\n3.3 使用eksctl创建fargateprofile\n   我们将会创建一个fargateprofile,并且将namespace参数设置为dev, 这样之后所有在dev部署的deployment、pod就会使用Fargate实例运行了。\n\n```bash\n\n kubectl create namespace dev\n\r\n eksctl create fargateprofile --cluster eksworkshop --name fargate-dev  --namespace dev\n\n#(可选)部署nginx到fargate\nkubectl apply -f nginx.yaml --namespace dev\n```\n\n\n\n"
  },
  {
    "path": "global/2019_GCR_EKS_Workshop/步骤4-部署示例应用，通过HPA测试Fargate弹性伸缩功能.md",
    "content": "#  步骤4: 部署示例应用，通过HPA测试Fargate弹性伸缩功能\r\n我们将要部署Metrics Server,部署标准HPA实例程序hpa-example ，并通过Horizontal Pod Autoscaler (HPA)设置CPU 50%自动扩展策略,测试Fargate弹性伸缩功能。 \r\n\r\n**本节所有操作均部署在namespace dev*\r\n\r\n4.1 安装Metrics Server 0.3.6 , Metrics Server会提供性能检测配合HPA实现Fargate水平扩展。\r\n\r\n请在Cloud9环境的终端上运行以下命令安装Metrics Server\r\n```bash\r\ncurl -Ls https://api.github.com/repos/kubernetes-sigs/metrics-server/tarball/v0.3.6  -o metrics-server-v0.3.6.tar.gz\r\nmkdir metrics-server-v0.3.6\r\ntar -xzf metrics-server-v0.3.6.tar.gz --directory metrics-server-v0.3.6 --strip-components 1\r\n\r\nkubectl apply -f metrics-server-v0.3.6/deploy/1.8+/\r\n\r\nkubectl get deployment metrics-server -n kube-system\r\n\r\n```\r\n> 验证metrics-server是否成功\r\n\r\n```bash\r\nkubectl get apiservice v1beta1.metrics.k8s.io -o yaml\r\n```\r\n\r\n> 如果返回结果如下(message: all checks passe)，则metrics server安装成功\r\n\r\n![](media/15764769332543/15764771434548.jpg)\r\n\r\n4.2 部署实例应用 php-apache,并设置HPA cpu 50%开始自动扩展,最大扩展10个replicas\r\n\r\n```bash\r\n#部署HPA示例应用\r\nkubectl run php-apache --image=k8s.gcr.io/hpa-example --requests=cpu=200m --expose --port=80 --namespace dev\r\n\r\n#设置CPU50%进行扩展,最大扩展为10个副本\r\nkubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10 --namespace dev\r\n```\r\n\r\n> 在Cloud9环境中新开一个终端,启动压力客户端。通过脚本访问php-apache服务，持续增加压力。\r\n\r\n```bash\r\n#启动压力客户端\r\nkubectl run -i --tty load-generator --image=busybox /bin/sh --namespace dev\r\n#运行压力脚本 \r\nwhile true; do wget -q -O - http://php-apache; done\r\n``` \r\n如下图所示\r\n![](media/15764769332543/1576503695.png)\r\n\r\n\r\n\r\n4.3 观察fargate弹性伸缩变化\r\n我们启动一个新的终端来启动观察HPA变化,Fargate实例变化,通过“watch kubectl get hpa --namespace dev “ 我们可以持续的观察CPU压力，以及对应的Replicas数量, 同时我们也可以观察Fargate工作实例数量。\r\n\r\n```bash\r\n#观察HPA变化\r\nwatch kubectl get hpa -n dev\r\n```\r\n\r\n> 会看到类似下图HPA的变化（CPU使用率，副本数都在增加)\r\n\r\n![](media/15764769332543/1576503810.png)\r\n![](media/15764769332543/1576503840.png)\r\n![](media/15764769332543/1576503883.png)\r\n\r\n\r\n\r\n\r\n> 查看当前fargate节点是否根据自动扩展。\r\n\r\n```bash\r\n#观察fargate实例数\r\nwatch kubectl get nodes\r\n```\r\n\r\n> Fargate 实例会自动根据HPA的策略，副本数增加而自动扩展\r\n\r\n![](media/15764769332543/1576503956.png)\r\n\r\n![](media/15764769332543/1576503975.png)\r\n\r\n\r\n"
  },
  {
    "path": "global/2019_GCR_EKS_Workshop/步骤5-在EKS中使用IAM Role进行权限管理(可选).md",
    "content": "# 步骤5：在EKS中使用IAM Role进行权限管理(可选)\r\n我们将要为ServiceAccount配置一个S3的访问角色，并且部署一个job应用到EKS集群，完成S3的写入。\r\n\r\n5.1 配置IAM Role、ServiceAccount\r\n\r\n```bash\r\n#创建OIDC身份提供商 \r\neksctl utils associate-iam-oidc-provider --cluster eksworkshop --approve\r\n\r\n#创建serviceaccount s3-echoer with IAM role\r\neksctl create iamserviceaccount --name s3-echoer --cluster eksworkshop --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess --approve\r\n\r\n```\r\n\r\n 5.2 部署测试应用\r\n*请确保bucket名字唯一,s3 bucket才能创建成功\r\n\r\n```bash\r\n#获取测试应用源代码\r\ngit clone https://github.com/mhausenblas/s3-echoer.git && cd s3-echoer\r\n\r\n#请替换<user_name> \r\nTARGET_BUCKET=<user_name>-irsa-2019\r\n\r\naws s3api create-bucket  --bucket $TARGET_BUCKET  --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION  --region $AWS_DEFAULT_REGION\r\n\r\n#替换模版里面的BUCKET名字和Region\r\nsed -e \"s/TARGET_BUCKET/${TARGET_BUCKET}/g;s/us-west-2/${AWS_DEFAULT_REGION}/g\" s3-echoer-job.yaml.template > s3-echoer-job.yaml\r\n\r\n#部署job到eks集群\r\nkubectl apply -f s3-echoer-job.yaml\r\n#查看job是否完成\r\nkubectl get job \r\n\r\n#查看bucket是否有文件生成\r\naws s3api list-objects --bucket $TARGET_BUCKET --query 'Contents[].{Key: Key, Size: Size}'\r\n\r\n```\r\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/README.md",
    "content": "### 0730 深圳 Container Day\n### 0923 成都 Container Day\n\n\n\n实验环境设置\n\n[步骤1 , 通过Cloud9搭建准备实验环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A41-%E9%80%9A%E8%BF%87AWS%20Cloud9%E6%90%AD%E5%BB%BA%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%8E%AF%E5%A2%83.md)\n\n\n\nDocker 的安装与应用实战\n\n1. [Lab2-Docker 基本操作](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/docker/Lab2-Docker%20%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C.md)\n2. [Lab3-使用Docker 运行Web服务](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/docker/Lab3-%E4%BD%BF%E7%94%A8Docker%20%E8%BF%90%E8%A1%8CWeb%E6%9C%8D%E5%8A%A1.md)\n3. [Lab4-多容器管理实践](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/docker/Lab4-多容器管理实践.md)\n\n   \n\nEKS 集群创建与应用实战\n\n1.  步骤1 , 通过Cloud9搭建准备实验环境\n2.  [步骤2,  安装eksctl, kubectl , jq等工具](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A42-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n3.  [步骤3,  创建EKS集群](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A43-%E5%88%9B%E5%BB%BAEKS%E9%9B%86%E7%BE%A4.md)\n4.  [步骤4, 使用ALB Ingress](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A44-%E9%85%8D%E7%BD%AEALBIngressController.md)\n5.  [步骤5,使用Kubernetes Dashboard](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A45-%E9%83%A8%E7%BD%B2%E5%AE%98%E6%96%B9%E7%9A%84KubernetesDashboard.md)\n6.  [步骤6,使用EBS存储](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/%E6%AD%A5%E9%AA%A46-%E4%BD%BF%E7%94%A8EBS%E5%AD%98%E5%82%A8.md)\n7.  [步骤7-在EKS中使用IAMRole进行权限管理(可选)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/步骤7-在EKS中使用IAMRole进行权限管理.md)\n8.  [步骤8-实现应用Pod和集群进行自动扩展(可选)](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2020_GCR_SZ_ContainerDay/步骤8-实现应用Pod和集群进行自动扩展.md)\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/docker/Lab2-Docker 基本操作.md",
    "content": "# Docker 基本操作\n\nDocker 是一个开源的商业产品，有两个版本：社区版（Community Edition，缩写为 CE）和企业版（Enterprise Edition，缩写为 EE）。企业版包含了一些收费服务，个人开发者一般用不到。下面的介绍都针对社区版。\n\nAWS Cloud9 已经内置了Docker CE版本，我们可以通过如下命令确认\n\n```\ndocker info\n\n# 或者\n\ndocker version\n```\n\n## Hello World\n\n确认本机已经安装好Docker后，我们可以通过`docker run`来尝试运行一个`hello-world`程序\n\n```\n$ docker run hello-world\n\n...\nHello from Docker.\nThis message shows that your installation appears to be working correctly.\n...\n```\n\n当我们在输出文本中能看到`Hello from Docker.`，证明我们的Docker可以正常运行。\n\n## 小试牛刀 - Playing with Busybox\n\n\n现在我们已经完成了所有设置，现在该小试牛刀了。在本节中，我们将在系统上运行`Busybox`容器，并对`docker run`命令有所了解。\n\n首先，让我们在终端中运行以下命令：\n\n```\ndocker pull busybox\n```\n\n`pull`命令从`Docker注册表`中获取`busybox`镜像并将其保存到我们的系统中。您可以使用docker images命令来查看系统上所有镜像的列表。\n\n```\nadmin:~/environment $ docker images\nREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE\nbusybox             latest              018c9d7b792b        6 hours ago         1.22MB\n```\n\n现在让我们基于该镜像运行一个Docker容器。为此，我们将使用全能的docker run命令。\n\n```\ndocker run busybox\n```\n\n等等，什么都没发生！那是个错误吗？好吧，不。在底层，其实发生了很多事情。当您调用run时，Docker客户端会找到镜像（在本例中为busbox），加载容器，然后在该容器中运行命令。当我们运行docker run busybox时，我们没有提供命令，因此容器启动，运行空命令，然后退出。\n\n```\nadmin:~/environment $ docker run busybox echo \"hello from busybox\"\nhello from busybox\n```\n\n很好-终于我们看到了一些输出。在这种情况下，Docker客户端会在我们的busybox容器中忠实地运行echo命令，然后退出它。好的，现在该看docker ps命令了。 docker ps命令向您显示当前正在运行的所有容器。\n\n```\nadmin:~/environment $ docker ps\nCONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES\n```\n\n由于没有容器在运行，因此我们看到一个空行。让我们尝试一个更有用的命令：docker ps -a\n\n```\nadmin:~/environment $ docker ps -a\nCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES\n28d676f7d6ef        busybox             \"echo 'hello from bu…\"   2 minutes ago       Exited (0) 2 minutes ago                        blissful_jones\n6cdf37f9bffa        busybox             \"sh\"                     2 minutes ago       Exited (0) 2 minutes ago                        reverent_lamarr\n818eb4f23324        hello-world         \"/hello\"                 10 minutes ago      Exited (0) 10 minutes ago                       ecstatic_goodall\n```\n\n因此，我们在上面看到的是我们运行的所有容器的历史列表。请注意，STATUS列显示这些容器是在几分钟前退出的。\n\n您可能想知道是否有一种方法可以在容器中运行多个命令。\n\n```\nadmin:~/environment $ docker run -it busybox sh\n/ # ls\nbin   dev   etc   home  proc  root  sys   tmp   usr   var\n/ # uname -a\nLinux 9c8b02f615cb 4.14.186-110.268.amzn1.x86_64 #1 SMP Tue Jul 14 02:57:34 UTC 2020 x86_64 GNU/Linux\n/ # exit\n```\n\n使用-it标志运行run命令会将我们附加到容器中的交互式tty。现在，我们可以在容器中运行任意数量的命令。\n\n接下来，您可以运行docker rm命令去删除我们刚才运行的容器。只需从上方docker ps -a复制容器ID，然后将其粘贴到命令旁边即可。\n\n\n```\ndocker rm 9c8b02f615cb 28d676f7d6ef 6cdf37f9bffa 818eb4f23324\n```\n\n如果您要一次性删除一堆容器，那么粘贴粘贴的ID可能很繁琐。在这种情况下，您只需运行\n\n```\nadmin:~/environment $ docker rm $(docker ps -a -q -f status=exited)\n9c8b02f615cb\n28d676f7d6ef\n6cdf37f9bffa\n818eb4f23324\n```\n\n最后，我们可以删除我们不需要的镜像，通过docker images 查看所有镜像，然后抽取需要删除的镜像id，通过 docker rmi -f <镜像id> 删除镜像\n\n```\ndocker rmi -f 018c9d7b792b bf756fb1ae65\n```\n\n\n## 清除环境\n\n请注意，由于本次实验的实例环境容量只有10G，因此我们需要尽量减少其他占用资源的空间，所以我们需要删除一些在这次实验中不需要的Docker镜像保证空间足够。我们可以通过`docker rmi <镜像id>` 删除 `docker images` 中的所有镜像内容。\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/docker/Lab3-使用Docker 运行Web服务.md",
    "content": "# 使用Docker 运行Web服务\n\n\n## 实验前准备工作\n\n接下来的实验我们需要构建一个网站，所以我们需要提前开放实例的安全组端口。\n\n- 首先我们需要构建一个额外的安全组开放TCP流量。在运行这个命令前，我们需要提前获取到我们Cloud9实例的vpc-id。该vpc-id可以在EC2页面点击Cloud9 实例获取\n\n\t\n\n\t![image-20200922131439749](../media/image-20200922131439749.png)\n\t\n\t```\n\t$ aws ec2 create-security-group --description allow-web-traffic --group-name allow-web-traffic --vpc-id <vpc-id>\n\t{\n\t    \"GroupId\": \"sg-03a4bafaf94c45139\"\n\t}\n\t```\n\t\n- 配置安全组的入站规则，需要将上面命令获取到的安全组id 填入以下命令的 `--group-id`\n\n\t```\n\taws ec2 authorize-security-group-ingress \\\n\t    --group-id <安全组id> \\\n\t    --ip-permissions IpProtocol=tcp,FromPort=0,ToPort=65535,IpRanges='[{CidrIp=0.0.0.0/0}]'\n\t```\n\t\n- 绑定安全组到我们的Cloud9实例\n\n\t![image-20200922131948815](../media/image-20200922131948815.png)\n\n ![image-20200922132023661](../media/image-20200922132023661.png)\n\n## 开始构建Docker Web应用\n\n我们将使用的镜像是一个单页面的网站，本次实验已经将其托管在Docker Hub中nikosheng/static-site。我们可以使用docker run直接下载并运行镜像。如上所述，-rm标志在容器退出时自动删除。\n\n```\n$ docker run -d -P --rm --name static-site nikosheng/static-site\n1545b3eb32d9e02a864b21248bd7631e016c8c4de3ec16888940ff5fc6ea9372\n```\n在上面的命令中，`-d`表示容器在后端运行，`-P`将所有公开的端口发布到随机端口，最后`--name`对应于我们要提供的名称。现在我们可以通过运行`docker port [CONTAINER]`命令来查看端口\n\n```\nadmin:~/environment $ docker port static-site\n80/tcp -> 0.0.0.0:32769\n```\n\n您可以在浏览器中打开`http://<ec2-dns>:32769`\n\n您还可以指定客户端将连接转发到容器的自定义端口\n\n```\nadmin:~/environment $ docker run -p 8080:80 nikosheng/static-site\nNginx is running...\n```\n\n要停止容器，请提供容器ID来运行docker stop。在这种情况下，我们可以使用用于启动容器的名称static-site\n\n```\ndocker stop static-site\n```\n\n## 构建Dockerfile\n\n现在我们对容器镜像有了更好的了解，是时候创建自己的镜像了。我们在本节中的目标是创建一个将简单Flask应用程序镜像。这是一个有趣的Flask小应用程序，该应用程序每次加载时都会显示一个随机的`cat.gif`\n\n首先我们需要通过Git 下载本次实验的代码\n\n```\ngit clone https://github.com/stevensu1977/docker-workshop.git\n\ncd docker-workshop/1-basic/flask-app\n```\n\nDockerfile是一个简单的文本文件，其中包含Docker客户端在创建镜像时调用的命令列表。您在Dockerfile中编写的命令几乎与它们的等效Linux命令相同。\n\n通过Cloud9打开flask-app中的Dockerfile\n\n```\n# 指定基准镜像\nFROM python:3\n\n# 设置工作目录\nWORKDIR /usr/src/app\n\n# 复制当前目录的文件到容器\nCOPY . .\n\n# 安装依赖\nRUN pip install --no-cache-dir -r requirements.txt\n\n# 容器需要暴露的端口\nEXPOSE 5000\n\n# 运行\nCMD [\"python\", \"./app.py\"]\n```\n\n现在我们有了Dockerfile，我们可以构建镜像了。 docker build命令完成了从Dockerfile创建Docker镜像的繁重工作。（可以替换下面的用户名`nikosheng`）\n\n```\ndocker build -t nikosheng/flask-app .\n```\n\n检查镜像是否构建成功\n\n```\nadmin:~/environment (master) $ docker images\nREPOSITORY            TAG                 IMAGE ID            CREATED             SIZE\nnikosheng/flask-app   latest              15ee6b5ca463        2 minutes ago       943MB\n```\n\n当镜像构建完成后，最后一步是运行镜像，并查看它是否确实有效。\n\n```\ndocker run -p 5000:5000 nikosheng/flask-app\n```\n运行成功后，可以在浏览器中访问\n\n```\nhttp://<ec2-dns>:5000/\n```\n\n恭喜您！现在您应该可以看到一只可爱的小猫咪^_^\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/docker/Lab4-多容器管理实践.md",
    "content": "# 多容器管理实践(可选)\n\n在上一节中，我们从一个简单的静态网站开始，然后尝试了Flask应用。只需少量命令，我们都可以在本地和云中运行这两种方法。这两个应用程序的共同点是它们在单个容器中运行。\n\n那些具有在生产环境中运行服务的经验的人知道，如今通常应用程序并不那么简单。几乎总是涉及一个数据库（或任何其他类型的持久性存储）。 Redis和Memcached之类的系统已成为大多数Web应用程序体系结构的基础。因此，在本节中，我们将花费一些时间来学习如何对依赖于不同服务的应用程序进行Dockerize。\n\n我们将要用于Dockerize的应用程序称为Food Trucks。我构建这个应用程序的目标是要有一个有用的东西（因为它类似于真实世界的应用程序），至少依赖一项服务，但对于本教程而言并不太复杂。\n\n首先，让我们进入我们的程序文件目录\n\n```\ncd docker-workshop/2-advanced/\n```\n\n其中，flask-app文件夹包含Python应用程序，而utils文件夹具有一些实用程序，可将数据加载到Elasticsearch中。该目录还包含一些YAML文件和一个Dockerfile，我们将在本教程中逐步详细介绍所有这些文件。\n\n让我们考虑如何对应用程序进行Docker化。我们可以看到该应用程序由Flask后端服务器和Elasticsearch服务组成。拆分此应用的自然方法是拥有两个容器-一个运行Flask进程，另一个运行Elasticsearch（ES）进程。这样，如果我们的应用程序变得越来越多人用，我们可以根据瓶颈所在的位置添加更多容器来扩展它。因此我们需要两个容器。在上一节中，我们已经构建了自己的Flask容器。对于Elasticsearch，让我们看看是否可以在Docker Hub上找到合适的镜像。\n\n```\ndocker search elasticsearch\n```\n\nElasticsearch存在官方支持的镜像。为了使ES运行，我们可以简单地使用docker run并让一个单节点ES容器立即在本地运行。\n\n```\ndocker pull docker.elastic.co/elasticsearch/elasticsearch:6.3.2\n```\n\n然后通过指定端口并设置一个环境变量将其运行在开发模式下，该环境变量将Elasticsearch集群配置为作为单节点运行。\n\n```\ndocker run -d --rm --name es -p 9200:9200 -p 9300:9300 -e \"discovery.type=single-node\" docker.elastic.co/elasticsearch/elasticsearch:6.3.2\n```\n\n如上所示，我们使用--name es为我们的容器命名，这使得在后续命令中易于使用。启动容器后，我们可以通过运行带有容器名称（或ID）的`docker logs -f <镜像id>`来查看日志，以查看日志。如果Elasticsearch成功启动，您应该看到类似于以下的日志。\n\n```\ndocker logs -f <镜像id>\n```\n\n现在，让我们尝试看看是否可以向Elasticsearch容器发送请求。我们使用9200端口将`cURL`请求发送到容器。\n\n```\n$ curl 0.0.0.0:9200\n{\n  \"name\" : \"kg_udER\",\n  \"cluster_name\" : \"docker-cluster\",\n  \"cluster_uuid\" : \"QTuIzSsKTM2dzdf1zojwKQ\",\n  \"version\" : {\n    \"number\" : \"6.3.2\",\n    \"build_flavor\" : \"default\",\n    \"build_type\" : \"tar\",\n    \"build_hash\" : \"053779d\",\n    \"build_date\" : \"2018-07-20T05:20:23.451332Z\",\n    \"build_snapshot\" : false,\n    \"lucene_version\" : \"7.3.1\",\n    \"minimum_wire_compatibility_version\" : \"5.6.0\",\n    \"minimum_index_compatibility_version\" : \"5.0.0\"\n  },\n  \"tagline\" : \"You Know, for Search\"\n}\n```\n\n看起来不错！在此过程中，让我们也运行Flask容器。但在此之前，我们需要一个Dockerfile。在上一节中，我们使用python：3图像作为基本镜像。但是，这次，除了通过pip安装Python依赖项之外，我们还希望我们的应用程序还生成用于生产的小型Javascript文件。为此，我们将需要Nodejs。由于我们需要自定义构建步骤，因此我们将从ubuntu基本镜像开始，从头开始构建Dockerfile。\n\n可以直接通过Cloud9编辑器打开`2-advanced/Dockerfile`\n\n```\n# start from base\nFROM ubuntu:18.04\n\nLABEL maintainer=\"Prakhar Srivastav <prakhar@prakhar.me>\"\n\n# install system-wide deps for python and node\nRUN apt-get -yqq update\nRUN apt-get -yqq install python3-pip python3-dev curl gnupg\nRUN curl -sL https://deb.nodesource.com/setup_10.x | bash\nRUN apt-get install -yq nodejs\n\n# copy our application code\nADD flask-app /opt/flask-app\nWORKDIR /opt/flask-app\n\n# fetch app specific deps\nRUN npm install\nRUN npm run build\nRUN pip3 install -r requirements.txt\n\n# expose port\nEXPOSE 5000\n\n# start app\nCMD [ \"python3\", \"./app.py\" ]\n```\n\n让我们快速浏览一下此文件。我们从Ubuntu LTS基本镜像开始，然后使用软件包管理器apt-get安装依赖项-Python和Node。\n\n然后，我们使用ADD命令将应用程序复制到容器中的新卷`/opt/flask-app`。这是我们的代码所在的位置。我们还将其设置为工作目录，以便在该位置的上下文中运行以下命令。现在，我们已安装了系统范围的依赖项，接下来我们将逐步安装特定于应用程序的依赖项。首先，我们通过从npm安装软件包并运行`package.json`文件中定义的build命令来安装Node。我们通过安装Python软件包，暴露端口并定义CMD来运行文件。\n\n最后，我们可以继续构建镜像并运行容器\n\n```\ndocker build -t nikosheng/foodtrucks-web .\n```\n\n构建完成后，让我们尝试运行我们的应用程序。\n\n```\n$ docker run -P --rm nikosheng/foodtrucks-web\nUnable to connect to ES. Retrying in 5 secs...\nUnable to connect to ES. Retrying in 5 secs...\nUnable to connect to ES. Retrying in 5 secs...\nOut of retries. Bailing out...\n```\n\n糟糕！由于无法连接到Elasticsearch，我们的flask应用程序无法运行。我们如何将一个容器联通另一个容器，并让他们彼此互通？\n\n### 如果对于Docker比较熟悉的小伙伴可以挑战一下，可以根据项目里面的代码去自己实现解决方法。如果第一次接触Docker的小伙伴，可以展开下面的折叠块来跟随教程一步一步完成实验。\n\n<details>\n<summary>查看解决方案</summary>\n<pre>\n\n## Docker Network\n\n在讨论Docker用于处理此类情况的功能之前，让我们先看看是否可以找到解决问题的方法。希望这会使您对我们将要研究的能有所了解。\n\n好的，让我们运行`docker container ls`（与`docker ps`相同），看看有什么。\n\n```\nadmin:~/environment $ docker ps\nCONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                                            NAMES\nb17bd4d6a319        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   \"/usr/local/bin/dock…\"   20 minutes ago      Up 20 minutes       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   es\nadmin:~/environment $ \n```\n\n因此，我们有一个ES容器运行在0.0.0.0:9200端口上，我们可以直接访问该容器。如果我们可以告诉Flask应用连接到该URL，则它应该可以连接并与ES通信。让我们深入研究Python代码，看看如何定义连接的详细信息。\n\n让我们打开`2-advanced/flask-app/app.py`\n\n```\nes = Elasticsearch(host='es')\n```\n\n在代码中，我们需要告诉Flask容器，ES容器正在0.0.0.0主机上运行（默认端口为9200），这应该使它工作，对吗？不幸的是，这是不正确的，因为IP 0.0.0.0是从主机（localhost）访问ES容器的IP。另一个容器将无法在同一IP地址上访问它。如果不是该IP，那么ES容器应可访问哪个IP地址？\n\n现在是开始探索Docker网络的好时机。安装docker后，它将自动创建三个网络。\n\n```\nadmin:~/environment $ docker network ls\nNETWORK ID          NAME                DRIVER              SCOPE\nd037c38ecd83        bridge              bridge              local\n6a3b3ab8c510        host                host                local\nde2a13d13a7a        none                null                local\n```\n\n桥接网络(bridge)是默认情况下运行容器的网络。因此，这意味着当我运行ES容器时，它正在此桥接网络中运行。为了验证这一点，让我们检查网络。\n\n```\nadmin:~/environment $ docker network inspect bridge\n[\n    {\n        \"Name\": \"bridge\",\n        \"Id\": \"d037c38ecd83d19ab65cd70020b996e9a53dd9c31a457658b47c14208f483410\",\n        \"Created\": \"2020-07-29T01:04:11.675105689Z\",\n        \"Scope\": \"local\",\n        \"Driver\": \"bridge\",\n        \"EnableIPv6\": false,\n        \"IPAM\": {\n            \"Driver\": \"default\",\n            \"Options\": null,\n            \"Config\": [\n                {\n                    \"Subnet\": \"172.17.0.0/16\",\n                    \"Gateway\": \"172.17.0.1\"\n                }\n            ]\n        },\n        \"Internal\": false,\n        \"Attachable\": false,\n        \"Ingress\": false,\n        \"ConfigFrom\": {\n            \"Network\": \"\"\n        },\n        \"ConfigOnly\": false,\n        \"Containers\": {\n            \"b17bd4d6a319e6206d47d9a5496d107a025c5cdfd7a37c64d7aa8e3570232b79\": {\n                \"Name\": \"es\",\n                \"EndpointID\": \"9944409131e57a61f18d86fab2e776126d42a2d20884b5c01ecfa7faecc385ce\",\n                \"MacAddress\": \"02:42:ac:11:00:02\",\n                \"IPv4Address\": \"172.17.0.2/16\",\n                \"IPv6Address\": \"\"\n            }\n        },\n        \"Options\": {\n            \"com.docker.network.bridge.default_bridge\": \"true\",\n            \"com.docker.network.bridge.enable_icc\": \"true\",\n            \"com.docker.network.bridge.enable_ip_masquerade\": \"true\",\n            \"com.docker.network.bridge.host_binding_ipv4\": \"0.0.0.0\",\n            \"com.docker.network.bridge.name\": \"docker0\",\n            \"com.docker.network.driver.mtu\": \"1500\"\n        },\n        \"Labels\": {}\n    }\n]\n```\n您可以看到我们的容器`b17bd4d6a319`在输出的“容器”部分下列出。我们还看到的是此容器已分配的IP地址-172.17.0.2。这是我们要查找的IP地址吗？让我们通过运行Flask容器并尝试访问此IP来找出答案。\n\n```\n$ docker run -it --rm nikosheng/foodtrucks-web curl 172.17.0.2:9200\n{\n  \"name\" : \"-ml6cJ3\",\n  \"cluster_name\" : \"docker-cluster\",\n  \"cluster_uuid\" : \"LoB0rDHaTqKMqoKMnnD2dA\",\n  \"version\" : {\n    \"number\" : \"6.3.2\",\n    \"build_flavor\" : \"default\",\n    \"build_type\" : \"tar\",\n    \"build_hash\" : \"053779d\",\n    \"build_date\" : \"2018-07-20T05:20:23.451332Z\",\n    \"build_snapshot\" : false,\n    \"lucene_version\" : \"7.3.1\",\n    \"minimum_wire_compatibility_version\" : \"5.6.0\",\n    \"minimum_index_compatibility_version\" : \"5.0.0\"\n  },\n  \"tagline\" : \"You Know, for Search\"\n}\n```\n\n我们可以直接在运行docker的时候加上我们希望容器执行的命令，我们看到我们确实可以在172.17.0.2:9200上与ES对话。Awesome！\n\n尽管我们已经找到了一种使容器相互通信的方法，但是这种方法仍然存在两个问题\n\n - 我们如何告诉Flask容器es主机名代表172.17.0.2或其他IP，因为IP可能会随时变化\n\n - 由于默认情况下每个容器都共享桥接网络，因此此方法并不安全。我们如何隔离我们的网络？\n\n好消息是Docker对我们的问题有很好的答案。它允许我们定义自己的网络，同时使用docker network命令将它们隔离。\n\n首先，让我们创建自己的网络。\n\n```\n$ docker network create aws-net\n\n$ docker network ls\nNETWORK ID          NAME                DRIVER              SCOPE\na5e79e75b97b        aws-net             bridge              local\n```\n\n`docker network create`命令创建一个新的网桥网络，这是我们目前需要的。就Docker而言，网桥网络使用软件网桥，该软件网桥允许连接到同一网桥网络的容器进行通信，同时将未连接到该网桥网络的容器隔离。 Docker网桥驱动程序会自动在主机中部署规则，以使不同网桥网络上的容器无法直接相互通信。\n\n现在我们有了一个自定义网络，我们可以使用--net标志在该网络内启动容器。但首先，为了启动具有相同名称的新容器，我们将停止并删除在网桥（默认）网络中运行的ES容器。\n\n```\n$ docker container stop es\nes\n\n$ docker container rm es\nes\n\n$ docker run -d --name es --net aws-net -p 9200:9200 -p 9300:9300 -e \"discovery.type=single-node\" docker.elastic.co/elasticsearch/elasticsearch:6.3.2\n\n$ docker network inspect aws-net\n[\n    {\n        \"Name\": \"aws-net\",\n        \"Id\": \"a5e79e75b97bddc921f59cc233e3d4fd47cf05753fe9cba833dcf6d0e39e9fb2\",\n        \"Created\": \"2020-07-29T01:52:29.251280599Z\",\n        \"Scope\": \"local\",\n        \"Driver\": \"bridge\",\n        \"EnableIPv6\": false,\n        \"IPAM\": {\n            \"Driver\": \"default\",\n            \"Options\": {},\n            \"Config\": [\n                {\n                    \"Subnet\": \"172.18.0.0/16\",\n                    \"Gateway\": \"172.18.0.1\"\n                }\n            ]\n        },\n        \"Internal\": false,\n        \"Attachable\": false,\n        \"Ingress\": false,\n        \"ConfigFrom\": {\n            \"Network\": \"\"\n        },\n        \"ConfigOnly\": false,\n        \"Containers\": {\n            \"aa04d18a7d073df6159717029ae5b42aa10a476d93a637fab24f122b94eee651\": {\n                \"Name\": \"es\",\n                \"EndpointID\": \"1ab25adb60508edc9d422095c89a8a6f28da0eb3576882be16ca0f234a8b8f46\",\n                \"MacAddress\": \"02:42:ac:12:00:02\",\n                \"IPv4Address\": \"172.18.0.2/16\",\n                \"IPv6Address\": \"\"\n            }\n        },\n        \"Options\": {},\n        \"Labels\": {}\n    }\n]\n```\n\n如您所见，我们的es容器现在在aws-net网桥网络中运行。现在，让我们检查一下在aws-net网络中启动时发生的情况。\n\n```\n$ docker run -it --rm --net aws-net nikosheng/foodtrucks-web curl es:9200\n{\n  \"name\" : \"8HgCcmE\",\n  \"cluster_name\" : \"docker-cluster\",\n  \"cluster_uuid\" : \"-C8xgQccSVmqx3KQFteyZA\",\n  \"version\" : {\n    \"number\" : \"6.3.2\",\n    \"build_flavor\" : \"default\",\n    \"build_type\" : \"tar\",\n    \"build_hash\" : \"053779d\",\n    \"build_date\" : \"2018-07-20T05:20:23.451332Z\",\n    \"build_snapshot\" : false,\n    \"lucene_version\" : \"7.3.1\",\n    \"minimum_wire_compatibility_version\" : \"5.6.0\",\n    \"minimum_index_compatibility_version\" : \"5.0.0\"\n  },\n  \"tagline\" : \"You Know, for Search\"\n}\n```\n可行！在用户定义的网络（如aws-net）上，容器不仅可以通过IP地址进行通信，而且还可以将容器名称解析为IP地址。此功能称为自动服务发现。让我们立即启动Flask容器\n\n请注意，如果出现`The container name \"foodtrucks-web\" is already in use by container` 的错误，可以先通过 docker container ls -a 获取停止的容器id，然后通过docker container stop <容器id> 以及 docker container rm <容器id> 来彻底注销容器\n\n```\n$ docker run -d --net aws-net -p 5000:5000 --name foodtrucks-web nikosheng/foodtrucks-web\n\n$ docker container ls\nCONTAINER ID        IMAGE                                                 COMMAND                  CREATED             STATUS              PORTS                                            NAMES\n308e2ed9d218        nikosheng/foodtrucks-web                              \"python3 ./app.py\"       18 seconds ago      Up 17 seconds       0.0.0.0:5000->5000/tcp                           foodtrucks-web\naa04d18a7d07        docker.elastic.co/elasticsearch/elasticsearch:6.3.2   \"/usr/local/bin/dock…\"   42 minutes ago      Up 42 minutes       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp   es\n\n$ curl -I 0.0.0.0:5000\nHTTP/1.0 200 OK\nContent-Type: text/html; charset=utf-8\nContent-Length: 3685\nServer: Werkzeug/1.0.1 Python/3.6.9\nDate: Wed, 29 Jul 2020 02:40:47 GMT\n```\n\n我们可以看到web服务已经可以成功调用es服务啦。\n\n</pre>\n</details>"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/IRSA/iam-pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: s3-echoer\nspec:\n  serviceAccountName: s3-echoer\n  containers:\n  - name: main\n    image: atlassian/pipelines-awscli\n    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']\n    env:\n    - name: AWS_DEFAULT_REGION\n      value: \"us-east-1\"\n    - name: ENABLE_IRP\n      value: \"true\"\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/alb-ingress-controller/alb-ingress-controller.yaml",
    "content": "# Application Load Balancer (ALB) Ingress Controller Deployment Manifest.\n# This manifest details sensible defaults for deploying an ALB Ingress Controller.\n# GitHub: https://github.com/kubernetes-sigs/aws-alb-ingress-controller\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\n  # Namespace the ALB Ingress Controller should run in. Does not impact which\n  # namespaces it's able to resolve ingress resource for. For limiting ingress\n  # namespace scope, see --watch-namespace.\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app.kubernetes.io/name: alb-ingress-controller\n  template:\n    metadata:\n      labels:\n        app.kubernetes.io/name: alb-ingress-controller\n    spec:\n      containers:\n        - name: alb-ingress-controller\n          args:\n            # Limit the namespace where this ALB Ingress Controller deployment will\n            # resolve ingress resources. If left commented, all namespaces are used.\n            # - --watch-namespace=your-k8s-namespace\n\n            # Setting the ingress-class flag below ensures that only ingress resources with the\n            # annotation kubernetes.io/ingress.class: \"alb\" are respected by the controller. You may\n            # choose any class you'd like for this controller to respect.\n            - --ingress-class=alb\n\n            # REQUIRED\n            # Name of your cluster. Used when naming resources created\n            # by the ALB Ingress Controller, providing distinction between\n            # clusters.\n            - --cluster-name=eksworkshop\n\n            # AWS VPC ID this ingress controller will use to create AWS resources.\n            # If unspecified, it will be discovered from ec2metadata.\n            # - --aws-vpc-id=vpc-xxxxxx\n            - --aws-vpc-id=vpc-08dadffbfb706d49c\n\n            # AWS region this ingress controller will operate in.\n            # If unspecified, it will be discovered from ec2metadata.\n            # List of regions: http://docs.aws.amazon.com/general/latest/gr/rande.html#vpc_region\n            - --aws-region=cn-northwest-1\n\n            # Enables logging on all outbound requests sent to the AWS API.\n            # If logging is desired, set to true.\n            # - --aws-api-debug\n            # Maximum number of times to retry the aws calls.\n            # defaults to 10.\n            # - --aws-max-retries=10\n            # 如果你在中国区使用alb-ingress-controller 1.1.7以及以上版本 需要禁用\n            #- --feature-gates=waf=false,wafv2=false \n          env:\n            - name: AWS_REGION\n              value: us-east-1\n            # AWS key id for authenticating with the AWS API.\n            # This is only here for examples. It's recommended you instead use\n            # a project like kube2iam for granting access.\n            #- name: AWS_ACCESS_KEY_ID\n            #  value: KEYVALUE\n\n            # AWS key secret for authenticating with the AWS API.\n            # This is only here for examples. It's recommended you instead use\n            # a project like kube2iam for granting access.\n            #- name: AWS_SECRET_ACCESS_KEY\n            #  value: SECRETVALUE\n          # Repository location of the ALB Ingress Controller.\n          image: docker.io/amazon/aws-alb-ingress-controller:v1.1.8\n      serviceAccountName: alb-ingress-controller\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/alb-ingress-controller/iam-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"acm:DescribeCertificate\",\n        \"acm:ListCertificates\",\n        \"acm:GetCertificate\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:AuthorizeSecurityGroupIngress\",\n        \"ec2:CreateSecurityGroup\",\n        \"ec2:CreateTags\",\n        \"ec2:DeleteTags\",\n        \"ec2:DeleteSecurityGroup\",\n        \"ec2:DescribeAccountAttributes\",\n        \"ec2:DescribeAddresses\",\n        \"ec2:DescribeInstances\",\n        \"ec2:DescribeInstanceStatus\",\n        \"ec2:DescribeInternetGateways\",\n        \"ec2:DescribeNetworkInterfaces\",\n        \"ec2:DescribeSecurityGroups\",\n        \"ec2:DescribeSubnets\",\n        \"ec2:DescribeTags\",\n        \"ec2:DescribeVpcs\",\n        \"ec2:ModifyInstanceAttribute\",\n        \"ec2:ModifyNetworkInterfaceAttribute\",\n        \"ec2:RevokeSecurityGroupIngress\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"elasticloadbalancing:AddListenerCertificates\",\n        \"elasticloadbalancing:AddTags\",\n        \"elasticloadbalancing:CreateListener\",\n        \"elasticloadbalancing:CreateLoadBalancer\",\n        \"elasticloadbalancing:CreateRule\",\n        \"elasticloadbalancing:CreateTargetGroup\",\n        \"elasticloadbalancing:DeleteListener\",\n        \"elasticloadbalancing:DeleteLoadBalancer\",\n        \"elasticloadbalancing:DeleteRule\",\n        \"elasticloadbalancing:DeleteTargetGroup\",\n        \"elasticloadbalancing:DeregisterTargets\",\n        \"elasticloadbalancing:DescribeListenerCertificates\",\n        \"elasticloadbalancing:DescribeListeners\",\n        \"elasticloadbalancing:DescribeLoadBalancers\",\n        \"elasticloadbalancing:DescribeLoadBalancerAttributes\",\n        \"elasticloadbalancing:DescribeRules\",\n        \"elasticloadbalancing:DescribeSSLPolicies\",\n        \"elasticloadbalancing:DescribeTags\",\n        \"elasticloadbalancing:DescribeTargetGroups\",\n        \"elasticloadbalancing:DescribeTargetGroupAttributes\",\n        \"elasticloadbalancing:DescribeTargetHealth\",\n        \"elasticloadbalancing:ModifyListener\",\n        \"elasticloadbalancing:ModifyLoadBalancerAttributes\",\n        \"elasticloadbalancing:ModifyRule\",\n        \"elasticloadbalancing:ModifyTargetGroup\",\n        \"elasticloadbalancing:ModifyTargetGroupAttributes\",\n        \"elasticloadbalancing:RegisterTargets\",\n        \"elasticloadbalancing:RemoveListenerCertificates\",\n        \"elasticloadbalancing:RemoveTags\",\n        \"elasticloadbalancing:SetIpAddressType\",\n        \"elasticloadbalancing:SetSecurityGroups\",\n        \"elasticloadbalancing:SetSubnets\",\n        \"elasticloadbalancing:SetWebAcl\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iam:CreateServiceLinkedRole\",\n        \"iam:GetServerCertificate\",\n        \"iam:ListServerCertificates\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"cognito-idp:DescribeUserPoolClient\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"waf-regional:GetWebACLForResource\",\n        \"waf-regional:GetWebACL\",\n        \"waf-regional:AssociateWebACL\",\n        \"waf-regional:DisassociateWebACL\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"tag:GetResources\",\n        \"tag:TagResources\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"waf:GetWebACL\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"wafv2:GetWebACL\",\n        \"wafv2:GetWebACLForResource\",\n        \"wafv2:AssociateWebACL\",\n        \"wafv2:DisassociateWebACL\"\n      ],\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"shield:DescribeProtection\",\n        \"shield:GetSubscriptionState\",\n        \"shield:DeleteProtection\",\n        \"shield:CreateProtection\",\n        \"shield:DescribeSubscription\",\n        \"shield:ListProtections\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/alb-ingress-controller/nginx-alb-ingress.yaml",
    "content": "---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment-ingress\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n     matchLabels:\n        app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: \"service-nginx-clusterip\"\nspec:\n  selector:\n    app: nginx\n  type: ClusterIP\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\n---\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: \"alb-ingress\"\n  namespace: \"default\"\n  annotations:\n    kubernetes.io/ingress.class: alb\n    alb.ingress.kubernetes.io/scheme: internet-facing\n    alb.ingress.kubernetes.io/target-type: ip\n  labels:\n    app: nginx\nspec:\n  rules:\n    - http:\n        paths:\n          - path: /*\n            backend:\n              serviceName: \"service-nginx-clusterip\"\n              servicePort: 80\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/alb-ingress-controller/rbac-role.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\nrules:\n  - apiGroups:\n      - \"\"\n      - extensions\n    resources:\n      - configmaps\n      - endpoints\n      - events\n      - ingresses\n      - ingresses/status\n      - services\n    verbs:\n      - create\n      - get\n      - list\n      - update\n      - watch\n      - patch\n  - apiGroups:\n      - \"\"\n      - extensions\n    resources:\n      - nodes\n      - pods\n      - secrets\n      - services\n      - namespaces\n    verbs:\n      - get\n      - list\n      - watch\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: alb-ingress-controller\nsubjects:\n  - kind: ServiceAccount\n    name: alb-ingress-controller\n    namespace: kube-system\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    app.kubernetes.io/name: alb-ingress-controller\n  name: alb-ingress-controller\n  namespace: kube-system\n...\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/.helmignore",
    "content": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation (prefixed with !). Only one pattern per line.\n.DS_Store\n# Common VCS dirs\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n# Common backup files\n*.swp\n*.bak\n*.tmp\n*~\n# Various IDEs\n.project\n.idea/\n*.tmproj\n.vscode/\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/Chart.yaml",
    "content": "apiVersion: v1\nappVersion: \"0.5.0\"\nname: aws-ebs-csi-driver\ndescription: A Helm chart for AWS EBS CSI Driver\nversion: 0.3.0\nkubeVersion: \">=1.13.0-0\"\nhome: https://github.com/kubernetes-sigs/aws-ebs-csi-driver\nsources:\n  - https://github.com/kubernetes-sigs/aws-ebs-csi-driver\nkeywords:\n  - aws\n  - ebs\n  - csi\nmaintainers:\n  - name: leakingtapan\n    email: chengpan@amazon.com\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/NOTES.txt",
    "content": "To verify that aws-ebs-csi-driver has started, run:\n\n    kubectl get pod -n kube-system -l \"app.kubernetes.io/name={{ include \"aws-ebs-csi-driver.name\" . }},app.kubernetes.io/instance={{ .Release.Name }}\"\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/_helpers.tpl",
    "content": "{{/* vim: set filetype=mustache: */}}\n{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"aws-ebs-csi-driver.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n\n{{/*\nCreate a default fully qualified app name.\nWe truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).\nIf release name contains chart name it will be used as a full name.\n*/}}\n{{- define \"aws-ebs-csi-driver.fullname\" -}}\n{{- if .Values.fullnameOverride -}}\n{{- .Values.fullnameOverride | trunc 63 | trimSuffix \"-\" -}}\n{{- else -}}\n{{- $name := default .Chart.Name .Values.nameOverride -}}\n{{- if contains $name .Release.Name -}}\n{{- .Release.Name | trunc 63 | trimSuffix \"-\" -}}\n{{- else -}}\n{{- printf \"%s-%s\" .Release.Name $name | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n{{- end -}}\n{{- end -}}\n\n{{/*\nCreate chart name and version as used by the chart label.\n*/}}\n{{- define \"aws-ebs-csi-driver.chart\" -}}\n{{- printf \"%s-%s\" .Chart.Name .Chart.Version | replace \"+\" \"_\" | trunc 63 | trimSuffix \"-\" -}}\n{{- end -}}\n\n{{/*\nCommon labels\n*/}}\n{{- define \"aws-ebs-csi-driver.labels\" -}}\napp.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\nhelm.sh/chart: {{ include \"aws-ebs-csi-driver.chart\" . }}\napp.kubernetes.io/instance: {{ .Release.Name }}\n{{- if .Chart.AppVersion }}\napp.kubernetes.io/version: {{ .Chart.AppVersion | quote }}\n{{- end }}\napp.kubernetes.io/managed-by: {{ .Release.Service }}\n{{- end -}}\n\n{{/*\nConvert the `--extra-volume-tags` command line arg from a map.\n*/}}\n{{- define \"aws-ebs-csi-driver.extra-volume-tags\" -}}\n{{- $result := dict \"pairs\" (list) -}}\n{{- range $key, $value := .Values.extraVolumeTags -}}\n{{- $noop := printf \"%s=%s\" $key $value | append $result.pairs | set $result \"pairs\" -}}\n{{- end -}}\n{{- if gt (len $result.pairs) 0 -}}\n- --extra-volume-tags={{- join \",\" $result.pairs -}}\n{{- end -}}\n{{- end -}}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/csidriver.yaml",
    "content": "apiVersion: storage.k8s.io/v1beta1\nkind: CSIDriver\nmetadata:\n  name: ebs.csi.aws.com\nspec:\n  attachRequired: true\n  podInfoOnMount: false\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/daemonset.yaml",
    "content": "# Node Service\nkind: DaemonSet\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-node\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app: ebs-csi-node\n      app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n      app.kubernetes.io/instance: {{ .Release.Name }}\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-node\n        app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n        app.kubernetes.io/instance: {{ .Release.Name }}\n      {{- if .Values.node.podAnnotations }}\n      annotations: {{ toYaml .Values.node.podAnnotations | nindent 8 }}\n      {{- end }}\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      hostNetwork: true\n      priorityClassName: system-node-critical\n      tolerations:\n        - operator: Exists\n        {{- with .Values.node.tolerations }}\n{{ toYaml . | indent 8 }}\n        {{- end }}\n      containers:\n        - name: ebs-plugin\n          securityContext:\n            privileged: true\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n          args:\n            - node\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:/csi/csi.sock\n          volumeMounts:\n            - name: kubelet-dir\n              mountPath: /var/lib/kubelet\n              mountPropagation: \"Bidirectional\"\n            - name: plugin-dir\n              mountPath: /csi\n            - name: device-dir\n              mountPath: /dev\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n        - name: node-driver-registrar\n          image: {{ printf \"%s:%s\" .Values.sidecars.nodeDriverRegistrarImage.repository .Values.sidecars.nodeDriverRegistrarImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)\n            - --v=5\n          lifecycle:\n            preStop:\n              exec:\n                command: [\"/bin/sh\", \"-c\", \"rm -rf /registration/ebs.csi.aws.com-reg.sock /csi/csi.sock\"]\n          env:\n            - name: ADDRESS\n              value: /csi/csi.sock\n            - name: DRIVER_REG_SOCK_PATH\n              value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n            - name: registration-dir\n              mountPath: /registration\n        - name: liveness-probe\n          image: {{ printf \"%s:%s\" .Values.sidecars.livenessProbeImage.repository .Values.sidecars.livenessProbeImage.tag }}\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n      volumes:\n        - name: kubelet-dir\n          hostPath:\n            path: /var/lib/kubelet\n            type: Directory\n        - name: plugin-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins/ebs.csi.aws.com/\n            type: DirectoryOrCreate\n        - name: registration-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins_registry/\n            type: Directory\n        - name: device-dir\n          hostPath:\n            path: /dev\n            type: Directory\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/deployment.yaml",
    "content": "# Controller Service\nkind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  replicas: {{ .Values.replicaCount }}\n  selector:\n    matchLabels:\n      app: ebs-csi-controller\n      app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n      app.kubernetes.io/instance: {{ .Release.Name }}\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-controller\n        app.kubernetes.io/name: {{ include \"aws-ebs-csi-driver.name\" . }}\n        app.kubernetes.io/instance: {{ .Release.Name }}\n      {{- if .Values.podAnnotations }}\n      annotations: {{ toYaml .Values.podAnnotations | nindent 8 }}\n      {{- end }}\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n        {{- with .Values.nodeSelector }}\n{{ toYaml . | indent 8 }}\n        {{- end }}\n      serviceAccountName: ebs-csi-controller-sa\n      priorityClassName: system-cluster-critical\n      {{- with .Values.affinity }}\n      affinity: {{ toYaml . | nindent 8 }}\n      {{- end }}\n      tolerations:\n        - operator: Exists\n      {{- with .Values.tolerations }}\n{{ toYaml . | indent 8 }}\n      {{- end }}\n      containers:\n        - name: ebs-plugin\n          image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n          imagePullPolicy: {{ .Values.image.pullPolicy }}\n          args:\n            - controller\n            - --endpoint=$(CSI_ENDPOINT)\n            {{ include \"aws-ebs-csi-driver.extra-volume-tags\" . }}\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock\n            - name: AWS_ACCESS_KEY_ID\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: key_id\n                  optional: true\n            - name: AWS_SECRET_ACCESS_KEY\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: access_key\n                  optional: true\n            {{- if .Values.region }}\n            - name: AWS_REGION\n              value: {{ .Values.region }}\n            {{- end }}\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n          {{- with .Values.resources }}\n          resources: {{ toYaml . | nindent 12 }}\n          {{- end }}\n        - name: csi-provisioner\n          image: {{ printf \"%s:%s\" .Values.sidecars.provisionerImage.repository .Values.sidecars.provisionerImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            {{- if .Values.enableVolumeScheduling }}\n            - --feature-gates=Topology=true\n            {{- end}}\n            - --enable-leader-election\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        - name: csi-attacher\n          image: {{ printf \"%s:%s\" .Values.sidecars.attacherImage.repository .Values.sidecars.attacherImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            - --leader-election=true\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        {{- if .Values.enableVolumeSnapshot }}\n        - name: csi-snapshotter\n          image: {{ printf \"%s:%s\" .Values.sidecars.snapshotterImage.repository .Values.sidecars.snapshotterImage.tag }}\n          args:\n            - --csi-address=$(ADDRESS)\n            - --leader-election=true\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        {{- end }}\n        {{- if .Values.enableVolumeResizing }}\n        - name: csi-resizer\n          image: {{ printf \"%s:%s\" .Values.sidecars.resizerImage.repository .Values.sidecars.resizerImage.tag }}\n          imagePullPolicy: Always\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        {{- end }}\n        - name: liveness-probe\n          image: {{ printf \"%s:%s\" .Values.sidecars.livenessProbeImage.repository .Values.sidecars.livenessProbeImage.tag }}\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /csi\n      volumes:\n        - name: socket-dir\n          emptyDir: {}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/rbac.yaml",
    "content": "---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-provisioner-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"delete\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"csinodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"coordination.k8s.io\"]\n    resources: [\"leases\"]\n    verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-provisioner-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-provisioner-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-attacher-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"csi.storage.k8s.io\"]\n    resources: [\"csinodeinfos\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"volumeattachments\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-attacher-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-attacher-role\n  apiGroup: rbac.authorization.k8s.io\n\n{{- if .Values.enableVolumeSnapshot }}\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-snapshotter-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"secrets\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents/status\"]\n    verbs: [\"update\"]\n  - apiGroups: [\"apiextensions.k8s.io\"]\n    resources: [\"customresourcedefinitions\"]\n    verbs: [\"create\", \"list\", \"watch\", \"delete\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshotter-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-snapshotter-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots/status\"]\n    verbs: [\"update\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshot-controller-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-snapshot-controller-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-leaderelection\n  namespace: kube-system \nrules:\n- apiGroups: [\"coordination.k8s.io\"]\n  resources: [\"leases\"]\n  verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: snapshot-controller-leaderelection\n  namespace: kube-system \nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system \nroleRef:\n  kind: Role\n  name: snapshot-controller-leaderelection\n  apiGroup: rbac.authorization.k8s.io\n\n{{- end }}\n\n{{- if .Values.enableVolumeResizing }}\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-resizer-role\nrules:\n  # The following rule should be uncommented for plugins that require secrets\n  # for provisioning.\n  # - apiGroups: [\"\"]\n  #   resources: [\"secrets\"]\n  #   verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims/status\"]\n    verbs: [\"update\", \"patch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-resizer-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-resizer-role\n  apiGroup: rbac.authorization.k8s.io\n{{- end}}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/serviceaccount.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-csi-controller-sa\n  namespace: kube-system\n  {{- with .Values.serviceAccount.controller.annotations }}\n  annotations: {{ toYaml . | nindent 4 }}\n  {{- end }}\n\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-snapshot-controller\n  namespace: kube-system\n  {{- with .Values.serviceAccount.snapshot.annotations }}\n  annotations: {{ toYaml . | nindent 4 }}\n  {{- end }}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/templates/statefulset.yaml",
    "content": "{{- if .Values.enableVolumeSnapshot }}\r\n#Snapshot controller\r\nkind: StatefulSet\r\napiVersion: apps/v1\r\nmetadata:\r\n  name: ebs-snapshot-controller\r\n  namespace: kube-system\r\nspec:\r\n  serviceName: ebs-snapshot-controller\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      app: ebs-snapshot-controller\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: ebs-snapshot-controller\r\n    spec:\r\n      serviceAccount: ebs-snapshot-controller\r\n      containers:\r\n        - name: snapshot-controller\r\n          image: quay.io/k8scsi/snapshot-controller:v2.0.1\r\n          args:\r\n            - --v=5\r\n            - --leader-election=false\r\n{{- end }}\r\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/aws-ebs-csi-driver/values.yaml",
    "content": "# Default values for aws-ebs-csi-driver.\n# This is a YAML-formatted file.\n# Declare variables to be passed into your templates.\n\nreplicaCount: 2\n\nimage:\n  repository: amazon/aws-ebs-csi-driver\n  tag: \"v0.5.0\"\n  pullPolicy: IfNotPresent\n\nsidecars:\n  provisionerImage:\n    repository: quay.io/k8scsi/csi-provisioner\n    tag: \"v1.5.0\"\n  attacherImage:\n    repository: quay.io/k8scsi/csi-attacher\n    tag: \"v1.2.0\"\n  snapshotterImage:\n    repository: quay.io/k8scsi/csi-snapshotter\n    tag: \"v2.0.1\"\n  livenessProbeImage:\n    repository: quay.io/k8scsi/livenessprobe\n    tag: \"v1.1.0\"\n  resizerImage:\n    repository: quay.io/k8scsi/csi-resizer\n    tag: \"v0.3.0\"\n  nodeDriverRegistrarImage:\n    repository: quay.io/k8scsi/csi-node-driver-registrar\n    tag: \"v1.1.0\"\n\nimagePullSecrets: []\nnameOverride: \"\"\nfullnameOverride: \"\"\n\npodAnnotations: {}\n\n# True if enable volume scheduling for dynamic volume provisioning\nenableVolumeScheduling: false\n\n# True if enable volume resizing\nenableVolumeResizing: false\n\n# True if enable volume snapshot\nenableVolumeSnapshot: false\n\nresources: {}\n  # We usually recommend not to specify default resources and to leave this as a conscious\n  # choice for the user. This also increases chances charts run on environments with little\n  # resources, such as Minikube. If you do want to specify resources, uncomment the following\n  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.\n  # limits:\n  #   cpu: 100m\n  #   memory: 128Mi\n  # requests:\n  #   cpu: 100m\n  #   memory: 128Mi\n\nnodeSelector: {}\n\ntolerations: []\n\naffinity: {}\n\n# Extra volume tags to attach to each dynamically provisioned volume.\n# ---\n# extraVolumeTags:\n#   key1: value1\n#   key2: value2\nextraVolumeTags: {}\n\n# AWS region to use. If not specified then the region will be looked up via the AWS EC2 metadata\n# service.\n# ---\n# region: us-east-1\nregion: \"\"\n\nnode:\n  podAnnotations: {}\n  tolerations: []\n\nserviceAccount:\n  controller:\n    annotations: {}\n  snapshot:\n    annotations: {}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/base/controller.yaml",
    "content": "---\n# Controller Service\nkind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: ebs-csi-controller\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-controller\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      serviceAccount: ebs-csi-controller-sa\n      priorityClassName: system-cluster-critical\n      tolerations:\n        - key: CriticalAddonsOnly\n          operator: Exists\n      containers:\n        - name: ebs-plugin\n          image: amazon/aws-ebs-csi-driver:latest\n          args :\n          # - {all,controller,node} # specify the driver mode\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock\n            - name: AWS_ACCESS_KEY_ID\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: key_id\n                  optional: true\n            - name: AWS_SECRET_ACCESS_KEY\n              valueFrom:\n                secretKeyRef:\n                  name: aws-secret\n                  key: access_key\n                  optional: true\n          # overwrite the AWS region instead of looking it up dynamically via the AWS EC2 metadata svc\n          # - name: AWS_REGION\n          #   value: us-east-1\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n        - name: csi-provisioner\n          image: quay.io/k8scsi/csi-provisioner:v1.5.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            - --feature-gates=Topology=true\n            - --enable-leader-election\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        - name: csi-attacher\n          image: quay.io/k8scsi/csi-attacher:v1.2.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n            - --leader-election=true\n            - --leader-election-type=leases\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n        - name: liveness-probe\n          image: quay.io/k8scsi/livenessprobe:v1.1.0\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /csi\n      volumes:\n        - name: socket-dir\n          emptyDir: {}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/base/csidriver.yaml",
    "content": "---\n\napiVersion: storage.k8s.io/v1beta1\nkind: CSIDriver\nmetadata:\n  name: ebs.csi.aws.com\nspec:\n  attachRequired: true\n  podInfoOnMount: false\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/base/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nnamespace: kube-system\nresources:\n- controller.yaml\n- node.yaml\n- rbac.yaml\n- csidriver.yaml\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/base/node.yaml",
    "content": "---\n# Node Service\nkind: DaemonSet\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-node\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      app: ebs-csi-node\n  template:\n    metadata:\n      labels:\n        app: ebs-csi-node\n    spec:\n      nodeSelector:\n        beta.kubernetes.io/os: linux\n      hostNetwork: true\n      priorityClassName: system-node-critical\n      tolerations:\n        - operator: Exists\n      containers:\n        - name: ebs-plugin\n          securityContext:\n            privileged: true\n          image: amazon/aws-ebs-csi-driver:latest\n          args:\n            - --endpoint=$(CSI_ENDPOINT)\n            - --logtostderr\n            - --v=5\n          env:\n            - name: CSI_ENDPOINT\n              value: unix:/csi/csi.sock\n          volumeMounts:\n            - name: kubelet-dir\n              mountPath: /var/lib/kubelet\n              mountPropagation: \"Bidirectional\"\n            - name: plugin-dir\n              mountPath: /csi\n            - name: device-dir\n              mountPath: /dev\n          ports:\n            - name: healthz\n              containerPort: 9808\n              protocol: TCP\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: healthz\n            initialDelaySeconds: 10\n            timeoutSeconds: 3\n            periodSeconds: 10\n            failureThreshold: 5\n        - name: node-driver-registrar\n          image: quay.io/k8scsi/csi-node-driver-registrar:v1.1.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)\n            - --v=5\n          lifecycle:\n            preStop:\n              exec:\n                command: [\"/bin/sh\", \"-c\", \"rm -rf /registration/ebs.csi.aws.com-reg.sock /csi/csi.sock\"]\n          env:\n            - name: ADDRESS\n              value: /csi/csi.sock\n            - name: DRIVER_REG_SOCK_PATH\n              value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n            - name: registration-dir\n              mountPath: /registration\n        - name: liveness-probe\n          image: quay.io/k8scsi/livenessprobe:v1.1.0\n          args:\n            - --csi-address=/csi/csi.sock\n          volumeMounts:\n            - name: plugin-dir\n              mountPath: /csi\n      volumes:\n        - name: kubelet-dir\n          hostPath:\n            path: /var/lib/kubelet\n            type: Directory\n        - name: plugin-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins/ebs.csi.aws.com/\n            type: DirectoryOrCreate\n        - name: registration-dir\n          hostPath:\n            path: /var/lib/kubelet/plugins_registry/\n            type: Directory\n        - name: device-dir\n          hostPath:\n            path: /dev\n            type: Directory\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/base/rbac.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-csi-controller-sa\n  namespace: kube-system\n  #Enable if EKS IAM for SA is used\n  #annotations:\n  #  eks.amazonaws.com/role-arn: arn:aws:iam::586565787010:role/ebs-csi-role\n\n---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-provisioner-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"create\", \"delete\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"csinodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"coordination.k8s.io\"]\n    resources: [\"leases\"]\n    verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-provisioner-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-provisioner-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-attacher-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"\"]\n    resources: [\"nodes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"csi.storage.k8s.io\"]\n    resources: [\"csinodeinfos\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"volumeattachments\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-attacher-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-attacher-role\n  apiGroup: rbac.authorization.k8s.io\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/cluster/crd_snapshotter.yaml",
    "content": "---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: (devel)\n    api-approved.kubernetes.io: \"https://github.com/kubernetes-csi/external-snapshotter/pull/139\"\n  creationTimestamp: null\n  name: volumesnapshotclasses.snapshot.storage.k8s.io\nspec:\n  group: snapshot.storage.k8s.io\n  names:\n    kind: VolumeSnapshotClass\n    listKind: VolumeSnapshotClassList\n    plural: volumesnapshotclasses\n    singular: volumesnapshotclass\n  scope: Cluster\n  preserveUnknownFields: false\n  validation:\n    openAPIV3Schema:\n      description: VolumeSnapshotClass specifies parameters that a underlying storage\n        system uses when creating a volume snapshot. A specific VolumeSnapshotClass\n        is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses\n        are non-namespaced\n      properties:\n        apiVersion:\n          description: 'APIVersion defines the versioned schema of this representation\n            of an object. Servers should convert recognized schemas to the latest\n            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'\n          type: string\n        deletionPolicy:\n          description: deletionPolicy determines whether a VolumeSnapshotContent created\n            through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot\n            is deleted. Supported values are \"Retain\" and \"Delete\". \"Retain\" means\n            that the VolumeSnapshotContent and its physical snapshot on underlying\n            storage system are kept. \"Delete\" means that the VolumeSnapshotContent\n            and its physical snapshot on underlying storage system are deleted. Required.\n          enum:\n          - Delete\n          - Retain\n          type: string\n        driver:\n          description: driver is the name of the storage driver that handles this\n            VolumeSnapshotClass. Required.\n          type: string\n        kind:\n          description: 'Kind is a string value representing the REST resource this\n            object represents. Servers may infer this from the endpoint the client\n            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n          type: string\n        parameters:\n          additionalProperties:\n            type: string\n          description: parameters is a key-value map with storage driver specific\n            parameters for creating snapshots. These values are opaque to Kubernetes.\n          type: object\n      required:\n      - deletionPolicy\n      - driver\n      type: object\n  version: v1beta1\n  versions:\n  - name: v1beta1\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n\n---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: (devel)\n    api-approved.kubernetes.io: \"https://github.com/kubernetes-csi/external-snapshotter/pull/139\"\n  creationTimestamp: null\n  name: volumesnapshotcontents.snapshot.storage.k8s.io\nspec:\n  group: snapshot.storage.k8s.io\n  names:\n    kind: VolumeSnapshotContent\n    listKind: VolumeSnapshotContentList\n    plural: volumesnapshotcontents\n    singular: volumesnapshotcontent\n  scope: Cluster\n  subresources:\n    status: {}\n  preserveUnknownFields: false\n  validation:\n    openAPIV3Schema:\n      description: VolumeSnapshotContent represents the actual \"on-disk\" snapshot\n        object in the underlying storage system\n      properties:\n        apiVersion:\n          description: 'APIVersion defines the versioned schema of this representation\n            of an object. Servers should convert recognized schemas to the latest\n            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'\n          type: string\n        kind:\n          description: 'Kind is a string value representing the REST resource this\n            object represents. Servers may infer this from the endpoint the client\n            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n          type: string\n        spec:\n          description: spec defines properties of a VolumeSnapshotContent created\n            by the underlying storage system. Required.\n          properties:\n            deletionPolicy:\n              description: deletionPolicy determines whether this VolumeSnapshotContent\n                and its physical snapshot on the underlying storage system should\n                be deleted when its bound VolumeSnapshot is deleted. Supported values\n                are \"Retain\" and \"Delete\". \"Retain\" means that the VolumeSnapshotContent\n                and its physical snapshot on underlying storage system are kept. \"Delete\"\n                means that the VolumeSnapshotContent and its physical snapshot on\n                underlying storage system are deleted. In dynamic snapshot creation\n                case, this field will be filled in with the \"DeletionPolicy\" field\n                defined in the VolumeSnapshotClass the VolumeSnapshot refers to. For\n                pre-existing snapshots, users MUST specify this field when creating\n                the VolumeSnapshotContent object. Required.\n              enum:\n              - Delete\n              - Retain\n              type: string\n            driver:\n              description: driver is the name of the CSI driver used to create the\n                physical snapshot on the underlying storage system. This MUST be the\n                same as the name returned by the CSI GetPluginName() call for that\n                driver. Required.\n              type: string\n            source:\n              description: source specifies from where a snapshot will be created.\n                This field is immutable after creation. Required.\n              properties:\n                snapshotHandle:\n                  description: snapshotHandle specifies the CSI \"snapshot_id\" of a\n                    pre-existing snapshot on the underlying storage system. This field\n                    is immutable.\n                  type: string\n                volumeHandle:\n                  description: volumeHandle specifies the CSI \"volume_id\" of the volume\n                    from which a snapshot should be dynamically taken from. This field\n                    is immutable.\n                  type: string\n              type: object\n            volumeSnapshotClassName:\n              description: name of the VolumeSnapshotClass to which this snapshot\n                belongs.\n              type: string\n            volumeSnapshotRef:\n              description: volumeSnapshotRef specifies the VolumeSnapshot object to\n                which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName\n                field must reference to this VolumeSnapshotContent's name for the\n                bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent\n                object, name and namespace of the VolumeSnapshot object MUST be provided\n                for binding to happen. This field is immutable after creation. Required.\n              properties:\n                apiVersion:\n                  description: API version of the referent.\n                  type: string\n                fieldPath:\n                  description: 'If referring to a piece of an object instead of an\n                    entire object, this string should contain a valid JSON/Go field\n                    access statement, such as desiredState.manifest.containers[2].\n                    For example, if the object reference is to a container within\n                    a pod, this would take on a value like: \"spec.containers{name}\"\n                    (where \"name\" refers to the name of the container that triggered\n                    the event) or if no container name is specified \"spec.containers[2]\"\n                    (container with index 2 in this pod). This syntax is chosen only\n                    to have some well-defined way of referencing a part of an object.\n                    TODO: this design is not final and this field is subject to change\n                    in the future.'\n                  type: string\n                kind:\n                  description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n                  type: string\n                name:\n                  description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'\n                  type: string\n                namespace:\n                  description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'\n                  type: string\n                resourceVersion:\n                  description: 'Specific resourceVersion to which this reference is\n                    made, if any. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency'\n                  type: string\n                uid:\n                  description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'\n                  type: string\n              type: object\n          required:\n          - deletionPolicy\n          - driver\n          - source\n          - volumeSnapshotRef\n          type: object\n        status:\n          description: status represents the current information of a snapshot.\n          properties:\n            creationTime:\n              description: creationTime is the timestamp when the point-in-time snapshot\n                is taken by the underlying storage system. In dynamic snapshot creation\n                case, this field will be filled in with the \"creation_time\" value\n                returned from CSI \"CreateSnapshotRequest\" gRPC call. For a pre-existing\n                snapshot, this field will be filled with the \"creation_time\" value\n                returned from the CSI \"ListSnapshots\" gRPC call if the driver supports\n                it. If not specified, it indicates the creation time is unknown. The\n                format of this field is a Unix nanoseconds time encoded as an int64.\n                On Unix, the command `date +%s%N` returns the current time in nanoseconds\n                since 1970-01-01 00:00:00 UTC.\n              format: int64\n              type: integer\n            error:\n              description: error is the latest observed error during snapshot creation,\n                if any.\n              properties:\n                message:\n                  description: 'message is a string detailing the encountered error\n                    during snapshot creation if specified. NOTE: message may be logged,\n                    and it should not contain sensitive information.'\n                  type: string\n                time:\n                  description: time is the timestamp when the error was encountered.\n                  format: date-time\n                  type: string\n              type: object\n            readyToUse:\n              description: readyToUse indicates if a snapshot is ready to be used\n                to restore a volume. In dynamic snapshot creation case, this field\n                will be filled in with the \"ready_to_use\" value returned from CSI\n                \"CreateSnapshotRequest\" gRPC call. For a pre-existing snapshot, this\n                field will be filled with the \"ready_to_use\" value returned from the\n                CSI \"ListSnapshots\" gRPC call if the driver supports it, otherwise,\n                this field will be set to \"True\". If not specified, it means the readiness\n                of a snapshot is unknown.\n              type: boolean\n            restoreSize:\n              description: restoreSize represents the complete size of the snapshot\n                in bytes. In dynamic snapshot creation case, this field will be filled\n                in with the \"size_bytes\" value returned from CSI \"CreateSnapshotRequest\"\n                gRPC call. For a pre-existing snapshot, this field will be filled\n                with the \"size_bytes\" value returned from the CSI \"ListSnapshots\"\n                gRPC call if the driver supports it. When restoring a volume from\n                this snapshot, the size of the volume MUST NOT be smaller than the\n                restoreSize if it is specified, otherwise the restoration will fail.\n                If not specified, it indicates that the size is unknown.\n              format: int64\n              minimum: 0\n              type: integer\n            snapshotHandle:\n              description: snapshotHandle is the CSI \"snapshot_id\" of a snapshot on\n                the underlying storage system. If not specified, it indicates that\n                dynamic snapshot creation has either failed or it is still in progress.\n              type: string\n          type: object\n      required:\n      - spec\n      type: object\n  version: v1beta1\n  versions:\n  - name: v1beta1\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n\n---\napiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: (devel)\n    api-approved.kubernetes.io: \"https://github.com/kubernetes-csi/external-snapshotter/pull/139\"\n  creationTimestamp: null\n  name: volumesnapshots.snapshot.storage.k8s.io\nspec:\n  group: snapshot.storage.k8s.io\n  names:\n    kind: VolumeSnapshot\n    listKind: VolumeSnapshotList\n    plural: volumesnapshots\n    singular: volumesnapshot\n  scope: Namespaced\n  subresources:\n    status: {}\n  preserveUnknownFields: false\n  validation:\n    openAPIV3Schema:\n      description: VolumeSnapshot is a user's request for either creating a point-in-time\n        snapshot of a persistent volume, or binding to a pre-existing snapshot.\n      properties:\n        apiVersion:\n          description: 'APIVersion defines the versioned schema of this representation\n            of an object. Servers should convert recognized schemas to the latest\n            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'\n          type: string\n        kind:\n          description: 'Kind is a string value representing the REST resource this\n            object represents. Servers may infer this from the endpoint the client\n            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'\n          type: string\n        spec:\n          description: 'spec defines the desired characteristics of a snapshot requested\n            by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots\n            Required.'\n          properties:\n            source:\n              description: source specifies where a snapshot will be created from.\n                This field is immutable after creation. Required.\n              properties:\n                persistentVolumeClaimName:\n                  description: persistentVolumeClaimName specifies the name of the\n                    PersistentVolumeClaim object in the same namespace as the VolumeSnapshot\n                    object where the snapshot should be dynamically taken from. This\n                    field is immutable.\n                  type: string\n                volumeSnapshotContentName:\n                  description: volumeSnapshotContentName specifies the name of a pre-existing\n                    VolumeSnapshotContent object. This field is immutable.\n                  type: string\n              type: object\n            volumeSnapshotClassName:\n              description: 'volumeSnapshotClassName is the name of the VolumeSnapshotClass\n                requested by the VolumeSnapshot. If not specified, the default snapshot\n                class will be used if one exists. If not specified, and there is no\n                default snapshot class, dynamic snapshot creation will fail. Empty\n                string is not allowed for this field. TODO(xiangqian): a webhook validation\n                on empty string. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshot-classes'\n              type: string\n          required:\n          - source\n          type: object\n        status:\n          description: 'status represents the current information of a snapshot. NOTE:\n            status can be modified by sources other than system controllers, and must\n            not be depended upon for accuracy. Controllers should only use information\n            from the VolumeSnapshotContent object after verifying that the binding\n            is accurate and complete.'\n          properties:\n            boundVolumeSnapshotContentName:\n              description: 'boundVolumeSnapshotContentName represents the name of\n                the VolumeSnapshotContent object to which the VolumeSnapshot object\n                is bound. If not specified, it indicates that the VolumeSnapshot object\n                has not been successfully bound to a VolumeSnapshotContent object\n                yet. NOTE: Specified boundVolumeSnapshotContentName alone does not\n                mean binding       is valid. Controllers MUST always verify bidirectional\n                binding between       VolumeSnapshot and VolumeSnapshotContent to\n                avoid possible security issues.'\n              type: string\n            creationTime:\n              description: creationTime is the timestamp when the point-in-time snapshot\n                is taken by the underlying storage system. In dynamic snapshot creation\n                case, this field will be filled in with the \"creation_time\" value\n                returned from CSI \"CreateSnapshotRequest\" gRPC call. For a pre-existing\n                snapshot, this field will be filled with the \"creation_time\" value\n                returned from the CSI \"ListSnapshots\" gRPC call if the driver supports\n                it. If not specified, it indicates that the creation time of the snapshot\n                is unknown.\n              format: date-time\n              type: string\n            error:\n              description: error is the last observed error during snapshot creation,\n                if any. This field could be helpful to upper level controllers(i.e.,\n                application controller) to decide whether they should continue on\n                waiting for the snapshot to be created based on the type of error\n                reported.\n              properties:\n                message:\n                  description: 'message is a string detailing the encountered error\n                    during snapshot creation if specified. NOTE: message may be logged,\n                    and it should not contain sensitive information.'\n                  type: string\n                time:\n                  description: time is the timestamp when the error was encountered.\n                  format: date-time\n                  type: string\n              type: object\n            readyToUse:\n              description: readyToUse indicates if a snapshot is ready to be used\n                to restore a volume. In dynamic snapshot creation case, this field\n                will be filled in with the \"ready_to_use\" value returned from CSI\n                \"CreateSnapshotRequest\" gRPC call. For a pre-existing snapshot, this\n                field will be filled with the \"ready_to_use\" value returned from the\n                CSI \"ListSnapshots\" gRPC call if the driver supports it, otherwise,\n                this field will be set to \"True\". If not specified, it means the readiness\n                of a snapshot is unknown.\n              type: boolean\n            restoreSize:\n              description: restoreSize represents the complete size of the snapshot\n                in bytes. In dynamic snapshot creation case, this field will be filled\n                in with the \"size_bytes\" value returned from CSI \"CreateSnapshotRequest\"\n                gRPC call. For a pre-existing snapshot, this field will be filled\n                with the \"size_bytes\" value returned from the CSI \"ListSnapshots\"\n                gRPC call if the driver supports it. When restoring a volume from\n                this snapshot, the size of the volume MUST NOT be smaller than the\n                restoreSize if it is specified, otherwise the restoration will fail.\n                If not specified, it indicates that the size is unknown.\n              type: string\n          type: object\n      required:\n      - spec\n      type: object\n  version: v1beta1\n  versions:\n  - name: v1beta1\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/controller_add_resizer.yaml",
    "content": "kind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  template:\n    spec:\n      containers:\n        - name: csi-resizer\n          image: quay.io/k8scsi/csi-resizer:v0.3.0\n          args:\n            - --csi-address=$(ADDRESS)\n            - --v=5\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/controller_add_snapshotter.yaml",
    "content": "kind: Deployment\napiVersion: apps/v1\nmetadata:\n  name: ebs-csi-controller\n  namespace: kube-system\nspec:\n  template:\n    spec:\n      containers:\n        - name: csi-snapshotter\n          image: quay.io/k8scsi/csi-snapshotter:v2.0.1\n          args:\n            - --csi-address=$(ADDRESS)\n            - --leader-election=true\n          env:\n            - name: ADDRESS\n              value: /var/lib/csi/sockets/pluginproxy/csi.sock\n          volumeMounts:\n            - name: socket-dir\n              mountPath: /var/lib/csi/sockets/pluginproxy/\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\npatches:\n- controller_add_snapshotter.yaml\n- controller_add_resizer.yaml\nresources:\n- rbac_add_snapshotter.yaml\n- rbac_add_resizer.yaml\n- rbac_add_snapshot_controller.yaml\n- snapshot_controller.yaml\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/rbac_add_resizer.yaml",
    "content": "---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-resizer-role\nrules:\n  # The following rule should be uncommented for plugins that require secrets\n  # for provisioning.\n  # - apiGroups: [\"\"]\n  #   resources: [\"secrets\"]\n  #   verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims/status\"]\n    verbs: [\"update\", \"patch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-resizer-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-resizer-role\n  apiGroup: rbac.authorization.k8s.io\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/rbac_add_snapshot_controller.yaml",
    "content": "# RBAC file for the snapshot controller.\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: ebs-snapshot-controller\n  namespace: kube-system\n\n---\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots/status\"]\n    verbs: [\"update\"]\n\n---\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshot-controller-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-snapshot-controller-role\n  apiGroup: rbac.authorization.k8s.io\n\n---\nkind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-snapshot-controller-leaderelection\n  namespace: kube-system \nrules:\n- apiGroups: [\"coordination.k8s.io\"]\n  resources: [\"leases\"]\n  verbs: [\"get\", \"watch\", \"list\", \"delete\", \"update\", \"create\"]\n\n---\nkind: RoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: snapshot-controller-leaderelection\n  namespace: kube-system \nsubjects:\n  - kind: ServiceAccount\n    name: ebs-snapshot-controller\n    namespace: kube-system \nroleRef:\n  kind: Role\n  name: snapshot-controller-leaderelection\n  apiGroup: rbac.authorization.k8s.io\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/rbac_add_snapshotter.yaml",
    "content": "---\n\nkind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-external-snapshotter-role\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumes\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"storage.k8s.io\"]\n    resources: [\"storageclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"events\"]\n    verbs: [\"list\", \"watch\", \"create\", \"update\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"secrets\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotclasses\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshots\"]\n    verbs: [\"get\", \"list\", \"watch\", \"update\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents\"]\n    verbs: [\"create\", \"get\", \"list\", \"watch\", \"update\", \"delete\"]\n  - apiGroups: [\"snapshot.storage.k8s.io\"]\n    resources: [\"volumesnapshotcontents/status\"]\n    verbs: [\"update\"]\n  - apiGroups: [\"apiextensions.k8s.io\"]\n    resources: [\"customresourcedefinitions\"]\n    verbs: [\"create\", \"list\", \"watch\", \"delete\"]\n---\n\nkind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: ebs-csi-snapshotter-binding\nsubjects:\n  - kind: ServiceAccount\n    name: ebs-csi-controller-sa\n    namespace: kube-system\nroleRef:\n  kind: ClusterRole\n  name: ebs-external-snapshotter-role\n  apiGroup: rbac.authorization.k8s.io\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/alpha/snapshot_controller.yaml",
    "content": "---\nkind: StatefulSet\napiVersion: apps/v1\nmetadata:\n  name: ebs-snapshot-controller\n  namespace: kube-system\nspec:\n  serviceName: ebs-snapshot-controller\n  replicas: 1\n  selector:\n    matchLabels:\n      app: ebs-snapshot-controller\n  template:\n    metadata:\n      labels:\n        app: ebs-snapshot-controller\n    spec:\n      serviceAccount: ebs-snapshot-controller\n      containers:\n        - name: snapshot-controller\n          image: quay.io/k8scsi/snapshot-controller:v2.0.1\n          args:\n            - --v=5\n            - --leader-election=false\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/dev/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\nimages:\n- name: amazon/aws-ebs-csi-driver\n  newTag: latest\n  newName: chengpan/aws-ebs-csi-driver\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/kustomization.yaml",
    "content": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nbases:\n- ../../base\nimages:\n- name: amazon/aws-ebs-csi-driver\n  newTag: v0.5.0\n- name: quay.io/k8scsi/csi-provisioner\n  newTag: v1.3.0\n- name: quay.io/k8scsi/csi-attacher\n  newTag: v1.2.0\n- name: quay.io/k8scsi/livenessprobe\n  newTag: v1.1.0\n- name: quay.io/k8scsi/csi-node-driver-registrar\n  newTag: v1.1.0\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/deploy/kubernetes/secret.yaml",
    "content": "apiVersion: v1\nkind: Secret\nmetadata:\n  name: aws-secret\n  namespace: kube-system\nstringData:\n  key_id: \"\"\n  access_key: \"\"\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/ebs-csi-iam-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"ec2:AttachVolume\",\n        \"ec2:CreateSnapshot\",\n        \"ec2:CreateTags\",\n        \"ec2:CreateVolume\",\n        \"ec2:DeleteSnapshot\",\n        \"ec2:DeleteTags\",\n        \"ec2:DeleteVolume\",\n        \"ec2:DescribeInstances\",\n        \"ec2:DescribeSnapshots\",\n        \"ec2:DescribeTags\",\n        \"ec2:DescribeVolumes\",\n        \"ec2:DetachVolume\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/block-volume/README.md",
    "content": "## Raw Block Volume\nThis example shows how to consume a dynamically-provisioned EBS volume as a raw block device.\n\n### Edit [Persistence Volume Claim Spec](./specs/raw-claim.yaml)\nMake sure the `volumeMode` is `Block`.\n\n### Edit [Application Pod](./specs/pod.yaml)\nMake sure the pod is consuming the PVC with the defined name and `volumeDevices` is used instead of `volumeMounts`.\n\n### Deploy the Application\n```sh\nkubectl apply -f examples/kubernetes/block-volume/specs/storageclass.yaml\nkubectl apply -f examples/kubernetes/block-volume/specs/raw-claim.yaml\nkubectl apply -f examples/kubernetes/block-volume/specs/pod.yaml\n```\n\n### Access Block Device\nAfter the objects are created, verify that pod is running:\n\n```sh\n$ kubectl get pods\nNAME   READY   STATUS    RESTARTS   AGE\napp    1/1     Running   0          16m\n```\nVerify the device node is mounted inside the container:\n\n```sh\n$ kubectl exec -ti app -- ls -al /dev/xvda\nbrw-rw----    1 root     disk      202, 23296 Mar 12 04:23 /dev/xvda\n```\n\nWrite to the device using:\n\n```sh\ndd if=/dev/zero of=/dev/xvda bs=1024k count=100\n100+0 records in\n100+0 records out\n104857600 bytes (105 MB, 100 MiB) copied, 0.0492386 s, 2.1 GB/s\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/block-volume/specs/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app \nspec:\n  containers:\n  - name: app \n    image: busybox \n    command: [\"/bin/sh\", \"-c\"]\n    args: [\"tail -f /dev/null\"]\n    volumeDevices:\n    - name: data\n      devicePath: /dev/xvda\n  volumes:\n  - name: data\n    persistentVolumeClaim:\n      claimName: block-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/block-volume/specs/raw-claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: block-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  volumeMode: Block\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 10Gi\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/block-volume/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/README.md",
    "content": "# Dynamic Volume Provisioning\nThis example shows how to create a EBS volume and consume it from container dynamically.\n\n## Prerequisites\n\n1. Kubernetes 1.13+ (CSI 1.0).\n\n1. The [aws-ebs-csi-driver driver](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) is installed.\n\n## Usage\n\n1. Create a sample app along with the StorageClass and the PersistentVolumeClaim:\n```\nkubectl apply -f specs/\n```\n\n2. Validate the volume was created and `volumeHandle` contains an EBS volumeID:\n```\nkubectl describe pv\n```\n\n3. Validate the pod successfully wrote data to the volume:\n```\nkubectl exec -it app cat /data/out.txt\n```\n\n4. Cleanup resources:\n```\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: busybox\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/resizing/README.md",
    "content": "## Volume Resizing\nThis example shows how to resize EBS persistence volume using volume resizing features.\n\n**Note**\n1. CSI volume resizing is still alpha as of Kubernetes 1.15\n2. EBS has a limit of one volume modification every 6 hours. Refer to [EBS documentation](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyVolume.html) for more details.\n\n## Usage\n1. Add `allowVolumeExpansion: true` in the StorageClass spec in [example manifest](./specs/example.yaml) to enable volume expansion. You can only expand a PVC if its storage class’s allowVolumeExpansion field is set to true\n\n2. Deploy the example:\n```sh\nkubectl apply -f specs/\n``` \n\n3. Verify the volume is created and Pod is running:\n```sh\nkubectl get pv\nkubectl get po app\n```\n\n4. Expand the volume size by increasing the capacity in PVC's `spec.resources.requests.storage`:\n```sh\nkubectl edit pvc ebs-claim\n```\nSave the result at the end of the edit.\n\n5. Verify that both the persistence volume and persistence volume claim are resized:\n```sh\nkubectl get pv\nkubectl get pvc\n```\nYou should see that both should have the new value relfected in the capacity fields.\n\n6. Verify that the application is continuously running without any interruption:\n```sh\nkubectl exec -it app cat /data/out.txt\n```\n\n7. Cleanup resources:\n```\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/resizing/spec/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: resize-sc\nprovisioner: ebs.csi.aws.com\nallowVolumeExpansion: true\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: resize-sc\n  resources:\n    requests:\n      storage: 4Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/README.md",
    "content": "# Volume Snapshots\n\n## Overview\n\nThis driver implements basic volume snapshotting functionality using the [external snapshotter](https://github.com/kubernetes-csi/external-snapshotter) sidecar and creates snapshots of EBS volumes using the `VolumeSnapshot` custom resources.\n\n## Prerequisites\n\n1. Kubernetes 1.13+ (CSI 1.0).\n\n1. The `VolumeSnapshotDataSource` must be set in `--feature-gates=` in the `kube-apiserver`.\n\n1. The [aws-ebs-csi-driver driver](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) is installed.\n\n### Usage\n\n1. Create the `StorageClass` and `VolumeSnapshotClass`:\n```\nkubectl apply -f specs/classes/\n```\n\n2. Create a sample app and the `PersistentVolumeClaim`: \n```\nkubectl apply -f specs/app/\n```\n\n3. Validate the volume was created and `volumeHandle` contains an EBS volumeID: \n```\nkubectl describe pv\n```\n\n4. Validate the pod successfully wrote data to the volume, taking note of the timestamp of the first entry:\n```\nkubectl exec -it app cat /data/out.txt\n```\n\n5. Create a `VolumeSnapshot` referencing the `PersistentVolumeClaim` name:\n```\nkubectl apply -f specs/snapshot/\n```\n\n6. Wait for the `Ready To Use:  true` attribute of the `VolumeSnapshot`: \n```\nkubectl describe volumesnapshot.snapshot.storage.k8s.io ebs-volume-snapshot\n```\n\n7. Delete the existing app:\n```\nkubectl delete -f specs/app/\n```\n\n8. Restore a volume from the snapshot with a `PersistentVolumeClaim` referencing the `VolumeSnapshot` in its `dataSource`:\n```\nkubectl apply -f specs/snapshot-restore/\n```\n\n9. Validate the new pod has the restored data by comparing the timestamp of the first entry to that of in step 4:\n```\nkubectl exec -it app cat /data/out.txt\n```\n\n10. Cleanup resources:\n```\nkubectl delete -f specs/snapshot-restore\nkubectl delete -f specs/snapshot\nkubectl delete -f specs/classes\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/app/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/app/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/classes/snapshotclass.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshotClass\nmetadata:\n  name: csi-aws-vsc\ndriver: ebs.csi.aws.com\ndeletionPolicy: Delete\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/classes/storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot/snapshot.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshot\nmetadata:\n  name: ebs-volume-snapshot\nspec:\n  volumeSnapshotClassName: csi-aws-vsc\n  source:\n    persistentVolumeClaimName: ebs-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-import/volume-snapshot-content.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshotContent\nmetadata:\n  name: static-snapshot-content\nspec:\n  volumeSnapshotRef:\n    kind: VolumeSnapshot\n    name: static-snapshot-demo\n    namespace: default \n  source:\n    snapshotHandle: snap-0fba4d7649d765c50\n  driver: ebs.csi.aws.com\n  volumeSnapshotClassName: csi-aws-vsc\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-import/volume-snapshot.yaml",
    "content": "apiVersion: snapshot.storage.k8s.io/v1beta1\nkind: VolumeSnapshot\nmetadata:\n  name: static-snapshot-demo\n  namespace: default \nspec:\n  volumeSnapshotClassName: csi-aws-vsc\n  source:\n    volumeSnapshotContentName: static-snapshot-content\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-restore/claim.yaml",
    "content": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-snapshot-restored-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n  dataSource:\n    name: ebs-volume-snapshot\n    kind: VolumeSnapshot\n    apiGroup: snapshot.storage.k8s.io\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/snapshot/specs/snapshot-restore/pod.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-snapshot-restored-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/static-provisioning/README.md",
    "content": "# Static Provisioning \nThis example shows how to create and consume persistence volume from exising EBS using static provisioning. \n\n## Usage\n1. Edit the PersistentVolume spec in [example manifest](./specs/example.yaml). Update `volumeHandle` with EBS volume ID that you are going to use, and update the `fsType` with the filesystem type of the volume. In this example, I have a pre-created EBS  volume in us-east-1c availability zone and it is formatted with xfs filesystem.\n\n```\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: test-pv\nspec:\n  capacity:\n    storage: 50Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  csi:\n    driver: ebs.csi.aws.com\n    volumeHandle: {volumeId} \n    fsType: xfs\n  nodeAffinity:\n    required:\n      nodeSelectorTerms:\n      - matchExpressions:\n        - key: topology.ebs.csi.aws.com/zone\n          operator: In\n          values:\n          - us-east-1c \n```\nNote that node affinity is used here since EBS volume is created in us-east-1c, hence only node in the same AZ can consume this persisence volume. \n\n2. Deploy the example:\n```sh\nkubectl apply -f specs/\n```\n\n3. Verify application pod is running:\n```sh\nkubectl describe po app\n```\n\n4. Validate the pod successfully wrote data to the volume:\n```sh\nkubectl exec -it app cat /data/out.txt\n```\n\n5. Cleanup resources:\n```sh\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/static-provisioning/specs/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\nreclaimPolicy: Retain\n---\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: test-pv\nspec:\n  capacity:\n    storage: 50Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  csi:\n    driver: ebs.csi.aws.com\n    volumeHandle: vol-05786ec9ec9526b67\n    fsType: xfs\n  nodeAffinity:\n    required:\n      nodeSelectorTerms:\n      - matchExpressions:\n        - key: topology.ebs.csi.aws.com/zone\n          operator: In\n          values:\n          - us-east-1c \n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 50Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/storageclass/README.md",
    "content": "# Configuring StorageClass\nThis example shows how to configure Kubernetes storageclass to provision EBS volumes with various configuration parameters. EBS CSI driver is compatiable with in-tree EBS plugin on StorageClass parameters. For the full list of in-tree EBS plugin parameters, please refer to Kubernetes documentation of [StorageClass Parameter](https://kubernetes.io/docs/concepts/storage/storage-classes/#aws-ebs).\n\n## Usage\n1. Edit the StorageClass spec in [example manifest](./specs/example.yaml) and update storageclass parameters to desired value. In this example, a `io1` EBS volume will be created and formatted to `xfs` filesystem with encryption enabled using the default KMS key.\n\n2. Deploy the example:\n```sh\nkubectl apply -f specs/\n```\n\n3. Verify the volume is created:\n```sh\nkubectl describe pv\n```\n\n4. Validate the pod successfully wrote data to the volume:\n```sh\nkubectl exec -it app cat /data/out.txt\n```\n\n5. Cleanup resources:\n```sh\nkubectl delete -f specs/\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/examples/kubernetes/storageclass/specs/example.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: ebs-sc\nprovisioner: ebs.csi.aws.com\nvolumeBindingMode: WaitForFirstConsumer\nparameters:\n  csi.storage.k8s.io/fstype: xfs\n  type: io1\n  iopsPerGB: \"50\"\n  encrypted: \"true\"\nallowedTopologies:\n- matchLabelExpressions:\n  - key: topology.ebs.csi.aws.com/zone\n    values:\n    - us-east-1a\n---\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: ebs-claim\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: ebs-sc\n  resources:\n    requests:\n      storage: 4Gi\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: app\nspec:\n  containers:\n  - name: app\n    image: centos\n    command: [\"/bin/sh\"]\n    args: [\"-c\", \"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done\"]\n    volumeMounts:\n    - name: persistent-storage\n      mountPath: /data\n  volumes:\n  - name: persistent-storage\n    persistentVolumeClaim:\n      claimName: ebs-claim\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/aws-ebs-csi-driver/updaterole.sh",
    "content": "\necho  \"CSI Policy ARN| $1\"\n\nCSI_ARN=$1\nROLES=$(aws iam list-roles --query 'Roles[?contains(RoleName,`nodegr`)].RoleName' --output text)\n\nfor i in $ROLES\ndo\n    echo attach [$CSI_ARN] to [$i]\n    aws iam attach-role-policy \\\n            --policy-arn $CSI_ARN \\\n             --role-name $i \\\n             --region cn-northwest-1\n\ndone\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/cluster-autoscaler/cluster_autoscaler.yml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\n  name: cluster-autoscaler\n  namespace: kube-system\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRole\nmetadata:\n  name: cluster-autoscaler\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nrules:\n- apiGroups: [\"\"]\n  resources: [\"events\",\"endpoints\"]\n  verbs: [\"create\", \"patch\"]\n- apiGroups: [\"\"]\n  resources: [\"pods/eviction\"]\n  verbs: [\"create\"]\n- apiGroups: [\"\"]\n  resources: [\"pods/status\"]\n  verbs: [\"update\"]\n- apiGroups: [\"\"]\n  resources: [\"endpoints\"]\n  resourceNames: [\"cluster-autoscaler\"]\n  verbs: [\"get\",\"update\"]\n- apiGroups: [\"\"]\n  resources: [\"nodes\"]\n  verbs: [\"watch\",\"list\",\"get\",\"update\"]\n- apiGroups: [\"\"]\n  resources: [\"pods\",\"services\",\"replicationcontrollers\",\"persistentvolumeclaims\",\"persistentvolumes\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"extensions\"]\n  resources: [\"replicasets\",\"daemonsets\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"policy\"]\n  resources: [\"poddisruptionbudgets\"]\n  verbs: [\"watch\",\"list\"]\n- apiGroups: [\"apps\"]\n  resources: [\"statefulsets\",\"replicasets\",\"daemonsets\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"storage.k8s.io\"]\n  resources: [\"storageclasses\", \"csinodes\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"batch\",\"extensions\"]\n  resources: [\"jobs\"]\n  verbs: [\"watch\",\"list\",\"get\",\"patch\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: Role\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nrules:\n- apiGroups: [\"\"]\n  resources: [\"configmaps\"]\n  verbs: [\"create\",\"list\",\"watch\"]\n- apiGroups: [\"\"]\n  resources: [\"configmaps\"]\n  resourceNames: [\"cluster-autoscaler-status\",\"cluster-autoscaler-priority-expander\"]\n  verbs: [\"delete\",\"get\",\"update\",\"watch\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBinding\nmetadata:\n  name: cluster-autoscaler\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: cluster-autoscaler\nsubjects:\n  - kind: ServiceAccount\n    name: cluster-autoscaler\n    namespace: kube-system\n\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleBinding\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: cluster-autoscaler\nsubjects:\n  - kind: ServiceAccount\n    name: cluster-autoscaler\n    namespace: kube-system\n\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    app: cluster-autoscaler\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: cluster-autoscaler\n  template:\n    metadata:\n      labels:\n        app: cluster-autoscaler\n    spec:\n      serviceAccountName: cluster-autoscaler\n      containers:\n        - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v1.16.5\n          name: cluster-autoscaler\n          resources:\n            limits:\n              cpu: 100m\n              memory: 300Mi\n            requests:\n              cpu: 100m\n              memory: 300Mi\n          command:\n            - ./cluster-autoscaler\n            - --v=4\n            - --stderrthreshold=info\n            - --cloud-provider=aws\n            - --skip-nodes-with-local-storage=false\n            - --nodes=2:8:eks-c6b9c9dd-492f-4df0-098c-82f0a7f1355a\n          env:\n            - name: AWS_REGION\n              value: us-east-1\n          volumeMounts:\n            - name: ssl-certs\n              mountPath: /etc/ssl/certs/ca-certificates.crt\n              readOnly: true\n          imagePullPolicy: \"Always\"\n      volumes:\n        - name: ssl-certs\n          hostPath:\n            path: \"/etc/ssl/certs/ca-bundle.crt\"\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/cluster-autoscaler/cluster_autoscaler.yml.orgin",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\n  name: cluster-autoscaler\n  namespace: kube-system\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRole\nmetadata:\n  name: cluster-autoscaler\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nrules:\n- apiGroups: [\"\"]\n  resources: [\"events\",\"endpoints\"]\n  verbs: [\"create\", \"patch\"]\n- apiGroups: [\"\"]\n  resources: [\"pods/eviction\"]\n  verbs: [\"create\"]\n- apiGroups: [\"\"]\n  resources: [\"pods/status\"]\n  verbs: [\"update\"]\n- apiGroups: [\"\"]\n  resources: [\"endpoints\"]\n  resourceNames: [\"cluster-autoscaler\"]\n  verbs: [\"get\",\"update\"]\n- apiGroups: [\"\"]\n  resources: [\"nodes\"]\n  verbs: [\"watch\",\"list\",\"get\",\"update\"]\n- apiGroups: [\"\"]\n  resources: [\"pods\",\"services\",\"replicationcontrollers\",\"persistentvolumeclaims\",\"persistentvolumes\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"extensions\"]\n  resources: [\"replicasets\",\"daemonsets\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"policy\"]\n  resources: [\"poddisruptionbudgets\"]\n  verbs: [\"watch\",\"list\"]\n- apiGroups: [\"apps\"]\n  resources: [\"statefulsets\",\"replicasets\",\"daemonsets\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"storage.k8s.io\"]\n  resources: [\"storageclasses\", \"csinodes\"]\n  verbs: [\"watch\",\"list\",\"get\"]\n- apiGroups: [\"batch\",\"extensions\"]\n  resources: [\"jobs\"]\n  verbs: [\"watch\",\"list\",\"get\",\"patch\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: Role\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nrules:\n- apiGroups: [\"\"]\n  resources: [\"configmaps\"]\n  verbs: [\"create\",\"list\",\"watch\"]\n- apiGroups: [\"\"]\n  resources: [\"configmaps\"]\n  resourceNames: [\"cluster-autoscaler-status\",\"cluster-autoscaler-priority-expander\"]\n  verbs: [\"delete\",\"get\",\"update\",\"watch\"]\n\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBinding\nmetadata:\n  name: cluster-autoscaler\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: cluster-autoscaler\nsubjects:\n  - kind: ServiceAccount\n    name: cluster-autoscaler\n    namespace: kube-system\n\n---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleBinding\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    k8s-addon: cluster-autoscaler.addons.k8s.io\n    k8s-app: cluster-autoscaler\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: cluster-autoscaler\nsubjects:\n  - kind: ServiceAccount\n    name: cluster-autoscaler\n    namespace: kube-system\n\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: cluster-autoscaler\n  namespace: kube-system\n  labels:\n    app: cluster-autoscaler\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: cluster-autoscaler\n  template:\n    metadata:\n      labels:\n        app: cluster-autoscaler\n    spec:\n      serviceAccountName: cluster-autoscaler\n      containers:\n        - image: us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v${AUTOSCALER_VERSION}\n          name: cluster-autoscaler\n          resources:\n            limits:\n              cpu: 100m\n              memory: 300Mi\n            requests:\n              cpu: 100m\n              memory: 300Mi\n          command:\n            - ./cluster-autoscaler\n            - --v=4\n            - --stderrthreshold=info\n            - --cloud-provider=aws\n            - --skip-nodes-with-local-storage=false\n            - --nodes=2:8:<AUTOSCALING GROUP NAME>\n          env:\n            - name: AWS_REGION\n              value: ${AWS_REGION}\n          volumeMounts:\n            - name: ssl-certs\n              mountPath: /etc/ssl/certs/ca-certificates.crt\n              readOnly: true\n          imagePullPolicy: \"Always\"\n      volumes:\n        - name: ssl-certs\n          hostPath:\n            path: \"/etc/ssl/certs/ca-bundle.crt\"\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/cluster-autoscaler/k8s-asg-policy.json",
    "content": "{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"autoscaling:DescribeAutoScalingGroups\",\n        \"autoscaling:DescribeAutoScalingInstances\",\n        \"autoscaling:SetDesiredCapacity\",\n        \"autoscaling:TerminateInstanceInAutoScalingGroup\",\n        \"autoscaling:DescribeTags\"\n      ],\n      \"Resource\": \"*\"\n    }\n  ]\n}\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/cluster-autoscaler/nginx-to-scaleout.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-to-scaleout\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        service: nginx\n        app: nginx\n    spec:\n      containers:\n      - image: nginx\n        name: nginx-to-scaleout\n        resources:\n          limits:\n            cpu: 500m\n            memory: 512Mi\n          requests:\n            cpu: 500m\n            memory: 512Mi\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/.gitignore",
    "content": "/_output\n.cover\nzz_generated.openapi.go\n\n# Vim-related files\n[._]*.s[a-w][a-z]\n[._]s[a-w][a-z]\n*~\n*.un~\nSession.vim\n.netrwhist\n.idea\n*manifest-tool\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/.golangci.yml",
    "content": "run:\n  deadline: 2m\n\nlinters:\n  disable-all: true\n  enable:\n    - gofmt\n    - goimports\n    - gosimple\n    - gocyclo\n    - ineffassign\n    - misspell\n    - govet\n\nlinters-settings:\n  goimports:\nlocal-prefixes: github.com/kubernetes-incubator/metrics-server\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/.travis.yml",
    "content": "sudo: false\n\nlanguage: go\n\ngo:\n- \"1.10\"\n\nscript:\n  - make lint\n  - make\n  - make test-unit\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/CONTRIBUTING.md",
    "content": "# Contributing guidelines\n\nWelcome to Kubernetes! If you are interested in contributing to the Metric-server code repo then checkout the [Contributor's Guide](https://github.com/kubernetes/community/tree/master/contributors/guide)\n\nThe [Kubernetes community repo](https://github.com/kubernetes/community) contains information on how the community is organized and other information that is pertinent to contributing. \n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/Makefile",
    "content": "# Common User-Settable Flags\n# ==========================\n# Push to staging registry.\nPREFIX?=staging-k8s.gcr.io\nFLAGS=\nARCH?=amd64\nGOLANG_VERSION?=1.10\nGOLANGCI_VERSION := v1.15.0\nHAS_GOLANGCI := $(shell which golangci-lint)\n\n# by default, build the current arch's binary\n# (this needs to be pre-include, for some reason)\nall: _output/$(ARCH)/metrics-server\n\n# Constants\n# =========\nALL_ARCHITECTURES=amd64 arm arm64 ppc64le s390x\n\n# Calculated Variables\n# ====================\nREPO_DIR:=$(shell pwd)\nLDFLAGS=-w $(VERSION_LDFLAGS)\n# get the appropriate version information\ninclude hack/Makefile.buildinfo\nBASEIMAGE?=gcr.io/distroless/static:latest\n# Rules\n# =====\n\n.PHONY: all test-unit container container-* clean container-only container-only-* tmpdir push do-push-* sub-push-* lint\n\n# Build Rules\n# -----------\n\npkg/generated/openapi/zz_generated.openapi.go:\n\tgo run vendor/k8s.io/kube-openapi/cmd/openapi-gen/openapi-gen.go --logtostderr -i k8s.io/metrics/pkg/apis/metrics/v1beta1,k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/apimachinery/pkg/api/resource,k8s.io/apimachinery/pkg/version -p github.com/kubernetes-incubator/metrics-server/pkg/generated/openapi/ -O zz_generated.openapi -h $(REPO_DIR)/hack/boilerplate.go.txt -r /dev/null\n\n# building depends on all go files (this is mostly redundant in the face of go 1.10's incremental builds,\n# but it allows us to safely write actual dependency rules in our makefile)\nsrc_deps=$(shell find pkg cmd -type f -name \"*.go\" -and ! -name \"zz_generated.*.go\")\n_output/%/metrics-server: $(src_deps) pkg/generated/openapi/zz_generated.openapi.go\n\tGOARCH=$* CGO_ENABLED=0 go build -ldflags \"$(LDFLAGS)\" -o _output/$*/metrics-server github.com/kubernetes-incubator/metrics-server/cmd/metrics-server\n\n# Image Rules\n# -----------\n\n# build a container using containerized build (the current arch by default)\ncontainer: container-$(ARCH)\n\ncontainer-%: pkg/generated/openapi/zz_generated.openapi.go tmpdir-%\n\t# Run the build in a container in order to have reproducible builds\n\tdocker run --rm -v $(TEMP_DIR):/build -v $(REPO_DIR):/go/src/github.com/kubernetes-incubator/metrics-server -w /go/src/github.com/kubernetes-incubator/metrics-server golang:$(GOLANG_VERSION) /bin/bash -c \"\\\n\t\tGOARCH=$* CGO_ENABLED=0 go build -ldflags \\\"$(LDFLAGS)\\\" -o /build/metrics-server github.com/kubernetes-incubator/metrics-server/cmd/metrics-server\"\n\n\n\t# copy the base Dockerfile into the temp dir, and set the base image\n\tcp deploy/docker/Dockerfile $(TEMP_DIR)\n\tsed -i -e \"s|BASEIMAGE|$(BASEIMAGE)|g\" $(TEMP_DIR)/Dockerfile\n\n\t# run the actual build\n\tdocker build --pull -t $(PREFIX)/metrics-server-$*:$(VERSION) $(TEMP_DIR)\n\n\t# remove our TEMP_DIR, as needed\n\trm -rf $(TEMP_DIR)\n\n# build a container using a locally-built binary (the current arch by default)\ncontainer-only: container-only-$(ARCH)\n\ncontainer-only-%: _output/$(ARCH)/metrics-server tmpdir-%\n\t# copy the base Dockerfile and binary into the temp dir, and set the base image\n\tcp deploy/docker/Dockerfile $(TEMP_DIR)\n\tcp _output/$*/metrics-server $(TEMP_DIR)\n\tsed -i -e \"s|BASEIMAGE|$(BASEIMAGE)|g\" $(TEMP_DIR)/Dockerfile\n\n\t# run the actual build\n\tdocker build --pull -t $(PREFIX)/metrics-server-$*:$(VERSION) $(TEMP_DIR)\n\n\t# remove our TEMP_DIR, as needed\n\trm -rf $(TEMP_DIR)\n\n# Official Container Push Rules\n# -----------------------------\n\n# do the actual push for official images\ndo-push-%:\n\t# push with main tag\n\tdocker push $(PREFIX)/metrics-server-$*:$(VERSION)\n\n\t# push alternate tags\nifeq ($*,amd64)\n\t# TODO: Remove this and push the manifest list as soon as it's working\n\tdocker tag $(PREFIX)/metrics-server-$*:$(VERSION) $(PREFIX)/metrics-server:$(VERSION)\n\tdocker push $(PREFIX)/metrics-server:$(VERSION)\nendif\n\n# do build and then push a given official image\nsub-push-%: container-% do-push-% ;\n\n# do build and then push all official images\npush: gcr-login $(addprefix sub-push-,$(ALL_ARCHITECTURES)) ;\n\t# TODO: push with manifest-tool?\n\t# Should depend on target: ./manifest-tool\n\n# log in to the official container registry\ngcr-login:\nifeq ($(findstring gcr.io,$(PREFIX)),gcr.io)\n\t@echo \"If you are pushing to a gcr.io registry, you have to be logged in via 'docker login'; 'gcloud docker push' can't push manifest lists yet.\"\n\t@echo \"This script is automatically logging you in now with 'gcloud docker -a'\"\n\tgcloud docker -a\nendif\n\n# Utility Rules\n# -------------\n\nclean:\n\trm -rf _output\n\trm pkg/generated/openapi/zz_generated.openapi.go\n\nfmt:\n\tfind pkg cmd -type f -name \"*.go\" | xargs gofmt -s -w\n\ntest-unit: pkg/generated/openapi/zz_generated.openapi.go\nifeq ($(ARCH),amd64)\n\tGOARCH=$(ARCH) go test --test.short -race ./pkg/... $(FLAGS)\nelse\n\tGOARCH=$(ARCH) go test --test.short ./pkg/... $(FLAGS)\nendif\n\n# set up a temporary director when we need it\n# it's the caller's responsibility to clean it up\ntmpdir-%:\n\t$(eval TEMP_DIR:=$(shell mktemp -d /tmp/metrics-server.XXXXXX))\nlint:\nifndef HAS_GOLANGCI\n\tcurl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin ${GOLANGCI_VERSION}\nendif\n\tgolangci-lint run\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/OWNERS",
    "content": "# See the OWNERS docs: https://go.k8s.io/owners\nowners:\n- s-urbaniak\n- piosz\n- brancz\napprovers:\n- metrics-server-approvers\nreviewers:\n- metrics-server-approvers\n- metrics-server-reviewers\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/OWNERS_ALIASES",
    "content": "# See the OWNERS docs: https://go.k8s.io/owners\naliases:\n  metrics-server-approvers:\n  - s-urbaniak\n  - piosz\n  - brancz\n  - kawych\n  metrics-server-reviewers: []\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/README.md",
    "content": "# Kubernetes Metrics Server\n\n## User guide\n\nYou can find the user guide in\n[the official Kubernetes documentation](https://kubernetes.io/docs/tasks/debug-application-cluster/resource-metrics-pipeline/).\n\n## Design\n\nThe detailed design of the project can be found in the following docs:\n\n- [Metrics API](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md)\n- [Metrics Server](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/metrics-server.md)\n\nFor the broader view of monitoring in Kubernetes take a look into\n[Monitoring architecture](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/monitoring_architecture.md)\n\n## Deployment\n\nCompatibility matrix:\n\nMetrics Server | Metrics API group/version | Supported Kubernetes version\n---------------|---------------------------|-----------------------------\n0.3.x          | `metrics.k8s.io/v1beta1`  | 1.8+\n0.2.x          | `metrics.k8s.io/v1beta1`  | 1.8+\n0.1.x          | `metrics/v1alpha1`        | 1.7\n\n\nIn order to deploy metrics-server in your cluster run the following command from\nthe top-level directory of this repository:\n\n```console\n# Kubernetes 1.7\n$ kubectl create -f deploy/1.7/\n\n# Kubernetes > 1.8\n$ kubectl create -f deploy/1.8+/\n```\n\nYou can also use this helm chart to deploy the metric-server in your cluster (This isn't supported by the metrics-server maintainers): https://github.com/helm/charts/tree/master/stable/metrics-server\n\nIf you want to test `metric-server` in a `minikube` cluster, please follow the steps below:\n\n```console\n$ minikube version\nminikube version: v1.2.0\n\n# disable the metrics-server addon for minikube in case it was enabled, because it installs the metric-server@v0.2.1\n$ minikube addons disable metrics-server\n\n# now start a new minikube\n$ minikube delete; minikube start --extra-config=kubelet.authentication-token-webhook=true\n🔥  Deleting \"minikube\" from virtualbox ...\n💔  The \"minikube\" cluster has been deleted.\n😄  minikube v1.2.0 on linux (amd64)\n🔥  Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...\n🐳  Configuring environment for Kubernetes v1.15.0 on Docker 18.09.6\n    ▪ kubelet.authentication-token-webhook=true\n🚜  Pulling images ...\n🚀  Launching Kubernetes ...\n⌛  Verifying: apiserver proxy etcd scheduler controller dns\n🏄  Done! kubectl is now configured to use \"minikube\"\n\n# deploy the latest metric-server\n$ kubectl create -f deploy/1.8+/\nclusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created\nclusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created\nrolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created\napiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created\nserviceaccount/metrics-server created\ndeployment.extensions/metrics-server created\nservice/metrics-server created\nclusterrole.rbac.authorization.k8s.io/system:metrics-server created\nclusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created\n\n# edit metric-server deployment to add the flags\n# args:\n# - --kubelet-insecure-tls\n# - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname\n$ kubectl edit deploy -n kube-system metrics-server\n```\n![minikube-metric-server-args](deploy/minikube/metric-server-args.png)\n\n## Flags\n\nMetrics Server supports all the standard Kubernetes API server flags, as\nwell as the standard Kubernetes `glog` logging flags.  The most\ncommonly-used ones are:\n\n- `--logtostderr`: log to standard error instead of files in the\n  container.  You generally want this on.\n\n- `--v=<X>`: set log verbosity.  It's generally a good idea to run a log\n  level 1 or 2 unless you're encountering errors.  At log level 10, large\n  amounts of diagnostic information will be reported, include API request\n  and response bodies, and raw metric results from Kubelet.\n\n- `--secure-port=<port>`: set the secure port.  If you're not running as\n  root, you'll want to set this to something other than the default (port\n  443).\n\n- `--tls-cert-file`, `--tls-private-key-file`: the serving certificate and\n  key files.  If not specified, self-signed certificates will be\n  generated, but it's recommended that you use non-self-signed\n  certificates in production.\n\nAdditionally, Metrics Server defines a number of flags for configuring its\nbehavior:\n\n- `--metric-resolution=<duration>`: the interval at which metrics will be\n  scraped from Kubelets (defaults to 60s).\n\n- `--kubelet-insecure-tls`: skip verifying Kubelet CA certificates.  Not\n  recommended for production usage, but can be useful in test clusters\n  with self-signed Kubelet serving certificates.\n\n- `--kubelet-port`: the port to use to connect to the Kubelet (defaults to\n  the default secure Kubelet port, 10250).\n\n- `--kubelet-preferred-address-types`: the order in which to consider\n  different Kubelet node address types when connecting to Kubelet.\n  Functions similarly to the flag of the same name on the API server.\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/SECURITY_CONTACTS",
    "content": "# Defined below are the security contacts for this repo.\n#\n# They are the contact point for the Product Security Team to reach out\n# to for triaging and handling of incoming issues.\n#\n# The below names agree to abide by the\n# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-document\nation/security-release-process.md#embargo-policy)\n# and will be removed and replaced if they violate that agreement.\n#\n# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE\n# INSTRUCTIONS AT https://kubernetes.io/security/\n\ns-urbaniak\npiosz\nbrancz\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/code-of-conduct.md",
    "content": "# Kubernetes Community Code of Conduct\n\nPlease refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.7/auth-delegator.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBinding\nmetadata:\n  name: metrics-server:system:auth-delegator\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:auth-delegator\nsubjects:\n- kind: ServiceAccount\n  name: metrics-server\n  namespace: kube-system\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.7/auth-reader.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleBinding\nmetadata:\n  name: metrics-server-auth-reader\n  namespace: kube-system\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: extension-apiserver-authentication-reader\nsubjects:\n- kind: ServiceAccount\n  name: metrics-server\n  namespace: kube-system\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.7/metrics-apiservice.yaml",
    "content": "---\napiVersion: apiregistration.k8s.io/v1beta1\nkind: APIService\nmetadata:\n  name: v1alpha1.metrics\nspec:\n  service:\n    name: metrics-server\n    namespace: kube-system\n  group: metrics\n  version: v1alpha1\n  insecureSkipTLSVerify: true\n  groupPriorityMinimum: 100\n  versionPriority: 100\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.7/metrics-server-deployment.yaml",
    "content": "---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: metrics-server\n  namespace: kube-system\n---\napiVersion: extensions/v1beta1\nkind: Deployment\nmetadata:\n  name: metrics-server\n  namespace: kube-system\n  labels:\n    k8s-app: metrics-server\nspec:\n  selector:\n    matchLabels:\n      k8s-app: metrics-server\n  template:\n    metadata:\n      name: metrics-server\n      labels:\n        k8s-app: metrics-server\n    spec:\n      serviceAccountName: metrics-server\n      containers:\n      - name: metrics-server\n        image: gcr.io/google_containers/metrics-server-amd64:v0.1.0\n        imagePullPolicy: Always\n        command:\n        - /metrics-server\n        - --source=kubernetes.summary_api:''\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.7/metrics-server-service.yaml",
    "content": "---\napiVersion: v1\nkind: Service\nmetadata:\n  name: metrics-server\n  namespace: kube-system\n  labels:\n    kubernetes.io/name: \"Metrics-server\"\nspec:\n  selector:\n    k8s-app: metrics-server\n  ports:\n  - port: 443\n    protocol: TCP\n    targetPort: 443\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/aggregated-metrics-reader.yaml",
    "content": "kind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: system:aggregated-metrics-reader\n  labels:\n    rbac.authorization.k8s.io/aggregate-to-view: \"true\"\n    rbac.authorization.k8s.io/aggregate-to-edit: \"true\"\n    rbac.authorization.k8s.io/aggregate-to-admin: \"true\"\nrules:\n- apiGroups: [\"metrics.k8s.io\"]\n  resources: [\"pods\", \"nodes\"]\n  verbs: [\"get\", \"list\", \"watch\"]\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/auth-delegator.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBinding\nmetadata:\n  name: metrics-server:system:auth-delegator\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:auth-delegator\nsubjects:\n- kind: ServiceAccount\n  name: metrics-server\n  namespace: kube-system\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/auth-reader.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleBinding\nmetadata:\n  name: metrics-server-auth-reader\n  namespace: kube-system\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: extension-apiserver-authentication-reader\nsubjects:\n- kind: ServiceAccount\n  name: metrics-server\n  namespace: kube-system\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/metrics-apiservice.yaml",
    "content": "---\napiVersion: apiregistration.k8s.io/v1beta1\nkind: APIService\nmetadata:\n  name: v1beta1.metrics.k8s.io\nspec:\n  service:\n    name: metrics-server\n    namespace: kube-system\n  group: metrics.k8s.io\n  version: v1beta1\n  insecureSkipTLSVerify: true\n  groupPriorityMinimum: 100\n  versionPriority: 100\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/metrics-server-deployment.yaml",
    "content": "---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: metrics-server\n  namespace: kube-system\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: metrics-server\n  namespace: kube-system\n  labels:\n    k8s-app: metrics-server\nspec:\n  selector:\n    matchLabels:\n      k8s-app: metrics-server\n  template:\n    metadata:\n      name: metrics-server\n      labels:\n        k8s-app: metrics-server\n    spec:\n      serviceAccountName: metrics-server\n      volumes:\n      # mount in tmp so we can safely use from-scratch images and/or read-only containers\n      - name: tmp-dir\n        emptyDir: {}\n      containers:\n      - name: metrics-server\n        image: k8s.gcr.io/metrics-server-amd64:v0.3.6\n        imagePullPolicy: Always\n        volumeMounts:\n        - name: tmp-dir\n          mountPath: /tmp\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/metrics-server-service.yaml",
    "content": "---\napiVersion: v1\nkind: Service\nmetadata:\n  name: metrics-server\n  namespace: kube-system\n  labels:\n    kubernetes.io/name: \"Metrics-server\"\n    kubernetes.io/cluster-service: \"true\"\nspec:\n  selector:\n    k8s-app: metrics-server\n  ports:\n  - port: 443\n    protocol: TCP\n    targetPort: 443\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/1.8+/resource-reader.yaml",
    "content": "---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: system:metrics-server\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - pods\n  - nodes\n  - nodes/stats\n  - namespaces\n  verbs:\n  - get\n  - list\n  - watch\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: system:metrics-server\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:metrics-server\nsubjects:\n- kind: ServiceAccount\n  name: metrics-server\n  namespace: kube-system\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/metrics-server-v0.3.6/deploy/docker/Dockerfile",
    "content": "FROM BASEIMAGE\n\nCOPY metrics-server /\n\nENTRYPOINT [\"/metrics-server\"]\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/resources/hpa/php-apache.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: php-apache\nspec:\n  selector:\n    matchLabels:\n      run: php-apache\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        run: php-apache\n    spec:\n      containers:\n      - name: php-apache\n        image: k8s.gcr.io/hpa-example\n        ports:\n        - containerPort: 80\n        resources:\n          limits:\n            cpu: 500m\n          requests:\n            cpu: 200m\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: php-apache\n  labels:\n    run: php-apache\nspec:\n  ports:\n  - port: 80\n  selector:\n    run: php-apache\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤1-通过AWS Cloud9搭建服务器环境.md",
    "content": "# 进入实验环境\n\n\n# 步骤1: 通过AWS Cloud9搭建服务器环境\nAWS Cloud9 为您提供了EC2基础设施资源并且一个可视化的编辑器。在本次实验中，您将通过Cloud9去创建一台具有公网访问权限的EC2 实例，运行后续的实验。\n\n1.1 通过浏览器进入 https://dashboard.eventengine.run/ ,填入12位hash code\n\n<img src=\"media/image-20200729204214972.png\" alt=\"image-20200729204214972\" style=\"zoom:33%;\" />\n\n\n\n通过点击AWS Console , Open AWS Console 进入aws 控制台\n\n![image-20200729204258710](media/image-20200729204258710.png)\n\n1.2 打开AWS管理控制台，在Service菜单栏中输入关键字Cloud9，进入Cloud9 管理页面\n![](media/15764751257913/15764752078709.jpg?raw=true\")\n\n\n\n1.3 点击Create environment,在Environment name and Description内输入 环境的名称 [username]_cloud9，点击 Next Step。\n![](media/15764751257913/15764752501954.jpg)\n\n1.4 保持界面上的默认配置，本次实验不需要改动任何实例环境和网路环境， 点击 Next step\n\n\n   ![](media/15764751257913/15764752786196.jpg)\n\n1.5 进入Review界面后，确认无误，点击Create Environment完成创建。此后界面会跳转到 Cloud9 的编辑器页面\n![](media/15764751257913/15764753072137.jpg)\n\n\n\n**样式**默认是深色,可以修改为白色\n\n![image-20200729211802528](media/image-20200729211802528.png)\n\n1.6\tCloud9 通常使用动态生成 IAM 的认证授权信息，但目前和 EKS IAM Authentication 不兼容，因此我们直接给 Cloud 9 EC2 实例附加一个管理员权限的 IAM 角色，并禁止掉 Cloud9 默认的动态 IAM认证授权信息：\n\n* 1）\t创建 IAM 角色\n\n> (1)请新开一个页面,进入[https://console.aws.amazon.com/iam/home#/roles](https://console.aws.amazon.com/iam/home#/roles),选择创建角色 第一步选择 AWS service 并选择 EC2,点击下一步\n\n![](media/15764751257913/15764753509904.png)\n\n> (2)权限中选择 AdministratorAccess,点击下一步\n\n![](media/15764751257913/15764753504307.png)\n\n> (3)输入角色名字 eksworkshop-admin,点击创建角色\n\n![](media/15764751257913/15764753507358.png)\n\n* 2）\t在EC2 Instances界面选择cloud9的EC2实例(名字为aws-cloud9-xxxxx),点击Actions/Instance Settings/Attach/Replace IAM Role,为该实例设置正确的角色\n\n  ![](media/15764751257913/1576503061.png)\n  \n>   选择eksworkshop-admin 角色,点击Apply完成\n\n![](media/15764751257913/15764754031465.png)\n\n* 3）\t关闭cloud9临时权限，并验证角色是否生效\n\n>点击AWS Cloud9图标 -> Preferences - >AWS Settings ->关闭临时权限\n\n* ![](media/15764751257913/15765030614319.png)\n\n输入:\n\n```bash\n#设置默认region\nexport AWS_DEFAULT_REGION=us-west-2\necho \"export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}\" >> ~/.bashrc\n\n\n#测试角色是否生效\naws sts get-caller-identity\n```\n如果可以正常返回以下内容(包含eksworkshop-admin),则表示已经正确设置角色权限\n```json\n{\n    \"Account\": \"<your account id, etc.11111111>\", \n    \"UserId\": \"AROAYVRRQ4TUEIX4VRZLN:i-0e011f5bb16f38173\", \n    \"Arn\": \"arn:aws:sts:: <your account id, etc.11111111>:assumed-role/eksworkshop-admin/i-0e011f5bb16f38173\"\n}\n```\n\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤2-设置默认region, 安装eksctl, kubectl工具.md",
    "content": "# 步骤2: 设置默认region, 安装eksctl, kubectl工具\n\n我们将在步骤1创建的AWS Cloud9 环境里面安装eksctl,kubectl。进入Cloud9编辑器环境后，在终端中输入以下命令,进行安装。\n\n```bash\n#设置默认region\nexport AWS_DEFAULT_REGION=us-west-2\necho \"export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}\" >> ~/.bashrc\n\n#eksctl 版本= v0.20.0\ncurl -L \"https://github.com/weaveworks/eksctl/releases/download/0.24.0/eksctl_$(uname -s)_amd64.tar.gz\" | tar xz -C .\nsudo mv ./eksctl /usr/local/bin\n\n#kubectl >v1.16.0\ncurl -LO --silent https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl\nchmod 775 ./kubectl\nsudo mv ./kubectl /usr/local/bin\n\n#安装jq\nsudo yum install -y jq\n\n```\n\n>检查工具的版本 eksctl (版本>=0.20.0), kubectl(版本>=1.16)\n\n```bash\neksctl version\nkubectl version\n```\n\n> 下载所需要的配置文件到本地\n\n```bash\ncurl -OL https://github.com/aws-samples/eks-workshop-greater-china/raw/master/global/2020_GCR_SZ_ContainerDay/resources.tgz\n\ntar -zxf resources.tgz\n```\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤3-创建EKS集群.md",
    "content": "# 步骤3: 创建EKS集群\n\n3.1 打开Cloud9终端管理控制台， 使用eksctl 创建EKS集群(操作需要10-15分钟),该命令同时会创建一个包含2个m5.large 实例的受管节点组。\n\n ```bash\n export CLUSTER_NAME=eksworkshop\n echo \"export CLUSTER_NAME=${CLUSTER_NAME}\" >> ~/.bashrc\n eksctl create cluster \\\n       --name $CLUSTER_NAME \\\n       --version 1.16 \\\n       --managed\n ```\n\n ![](media/15764759782724/15764761011094.jpg)\n\n  查看EKS集群工作节点\n  ```bash\n   kubectl cluster-info\n   kubectl get node\n  ```\n  ![](media/15764759782724/15764762619982.jpg)\n\n3.2 (可选)部署一个测试应用\n在Cloud9创建一个nginx.yaml,内容如下\n\n```yaml\ncat << EOF >> nginx.yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: \"service-nginx\"\n  annotations:\n        service.beta.kubernetes.io/aws-load-balancer-type: nlb\nspec:\n  selector:\n    app: nginx\n  type: LoadBalancer\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\nEOF\n\n```\n\n > 部署nginx\n\n ```bash\n#部署\nkubectl apply -f nginx.yaml\nkubectl get deploy\nkubectl get svc\n\n#测试\nELB=$(kubectl get svc service-nginx -o json |  jq -r '.status.loadBalancer.ingress[].hostname')\necho $ELB\ncurl $ELB\n  \n ```\n\n>清除\n>\n\n```bash\nkubectl delete -f nginx.yaml\n```\n\n\n\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤4-配置ALBIngressController.md",
    "content": "# 步骤4 配置ALB Ingress Controller\n\n4. 1使用ALB Ingress Controller\n\n> 4.2.1 创建ALB Ingress Controller所需要的IAM policy , EKS OIDC provider, service account\n\n```bash\n#创建odic provider\neksctl utils associate-iam-oidc-provider --region=${AWS_DEFAULT_REGION} --cluster=${CLUSTER_NAME}  --approve\n\n```\n\n> 4.2.1.2 创建所需要的IAM policy\n> \n>https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/iam-policy.json\n```bash\naws iam create-policy --policy-name ALBIngressControllerIAMPolicy \\\n  --policy-document file://./alb-ingress-controller/iam-policy.json \n\n# 记录返回的Plociy ARN\nPOLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==`ALBIngressControllerIAMPolicy`].Arn' --output text )\n\n#查看是否正常返回Plicy ARN \necho $POLICY_NAME\n\n```\n\n>4.2.1.3 请使用上述返回的policy ARN创建service account\n\n```bash\n\neksctl create iamserviceaccount \\\n       --cluster=${CLUSTER_NAME} \\\n       --namespace=kube-system \\\n       --name=alb-ingress-controller \\\n       --attach-policy-arn=${POLICY_NAME} \\\n       --override-existing-serviceaccounts \\\n       --approve\n\n参考输出\n[ℹ]  eksctl version 0.24.0\n[ℹ]  using region us-west-2\n[ℹ]  1 iamserviceaccount (kube-system/alb-ingress-controller) was included (based on the include/exclude rules)\n[!]  metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set\n[ℹ]  1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount \"kube-system/alb-ingress-controller\", create serviceaccount \"kube-system/alb-ingress-controller\" } }\n[ℹ]  building iamserviceaccount stack \"eksctl-ekslab-addon-iamserviceaccount-kube-system-alb-ingress-controller\"\n[ℹ]  deploying stack \"eksctl-ekslab-addon-iamserviceaccount-kube-system-alb-ingress-controller\"\n[ℹ]  created serviceaccount \"kube-system/alb-ingress-controller\"\n```\n\n\n\n4.3 部署 ALB Ingress Controller\n\n 相关文件已经resource/alb-ingress-controller目录下，并且修改好，下面步骤为你全新Step-by-Step操作\n\n >4.3.1 创建 ALB Ingress Controller 所需要的RBAC\n\n ```bash\n kubectl apply -f alb-ingress-controller/rbac-role.yaml\n \n ```\n\n>4.2.2 创建 ALB Ingress Controller 配置文件\n\n 修改alb-ingress-controller.yaml 以下配置，参考示例 resource/alb-ingress-controller/alb-ingress-controller.yaml\n(eksctl 自动创建的 vpc 默认为 eksctl-<集群名字>-cluster/VPC)\n\n  ```bash\n #查找EKS集群使用的vpc\n aws ec2 describe-vpcs --filters \"Name=tag:Name,Values=eksctl-${CLUSTER_NAME}-cluster/VPC\" --query \"Vpcs[0].VpcId\" --out text\n \n  \n  #使用vi修改alb-ingress-controller/alb-ingress-controller.yaml 将vpc-xxxxxx替换成上面查询回来的vpc id\n  - --aws-vpc-id=vpc-xxxxxx  \n  \n  #其他参数已经设置好了不用修改\n  #- --cluster-name=eksworkshop\n  #- --aws-region=us-west-2\n              \n  \n  #中国区 1.1.7 waf,wafv2修复方式\n  #如果你使用alb-ingress-controller 1.1.8 需要禁用waf,wafv2\n  - --feature-gates=waf=false,wafv2=false\n\n             \n #使用修改好的yaml文件部署ALB Ingress Controller\n kubectl apply -f alb-ingress-controller/alb-ingress-controller.yaml\n\n \n #确认ALB Ingress Controller是否工作\n kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o alb-ingress[a-zA-Z0-9-]+)\n\n #参考输出\n-------------------------------------------------------------------------------\nAWS ALB Ingress controller\n  Release:    v1.1.8\n  Build:      git-ec387ad1\n  Repository: https://github.com/kubernetes-sigs/aws-alb-ingress-controller.git\n-------------------------------------------------------------------------------\n  ```\n\n\n 4.4 使用ALB Ingress   \n>4.4.1 为nginx service创建ingress\n\n```bash\nkubectl apply -f alb-ingress-controller/nginx-alb-ingress.yaml\nkubectl get ingress\n```\n\n>4.4.2 验证\n\n```bash\nALB=$(kubectl get ingress -o json | jq -r '.items[0].status.loadBalancer.ingress[].hostname')\ncurl -v $ALB\n\n# 如果遇到问题，请查看日志\nkubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o alb-ingress[a-zA-Z0-9-]+)\n```\n\n> 4.4.3 清理测试应用\n```bash\nkubectl delete -f alb-ingress-controller/nginx-alb-ingress.yaml\n```\n\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤5-部署官方的KubernetesDashboard.md",
    "content": "# 步骤5 部署官方的Kubernetes dashboard\n\n5.1 下载配置文件\n\n```bash\n#2.0.0rc3\n\n#部署\nkubectl apply -f dashboard/recommended.yaml\n\nkubectl get pods -n kubernetes-dashboard\nkubectl get services -n kubernetes-dashboard\n\n\n\n#获取登录的token\naws eks get-token --cluster-name ${CLUSTER_NAME} | jq -r '.status.token'\n\n\n#方法1 将Dashboard 服务类型从默认的cluster 修改为LoadBalancer 通过AWS ELB提供对外服务,生产系统不推荐\n#最新版本chrome不能访问，firefox 可以点高级点继续\n\n#获取Dashboard访问地址\nkubectl get svc kubernetes-dashboard -n kubernetes-dashboard -o json |  jq -r '.status.loadBalancer.ingress[].hostname'\n#使用firefox 打开上述地址\n\n\n\n#方法2 通过kubectl proxy 进行访问\n#由于我们部署的EKS cluster是private cluster，所以我们需要通过 proxy. Kube-proxy进行访问Dashboard\nkubectl proxy --port=8080 --address='0.0.0.0' --disable-filter=true &\n\n#通过proxy进行访问\nhttp://localhost:8080/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#!/login\n\n#登录\n#在cloud9里面选择tools -> preview -> preview run application\n\n选择 Dashbaord 登录页面的 “Token” 单选按钮，复制上述命令的输出，粘贴，之后点击 Sign In。\n\n\n```\n\n\n\n![image-20200728161147477](media/image-20200728161147477.png)\n\n\n\n**注意:** 新版本的chrome浏览器会禁止使用自签名https访问,所以推荐使用firefox访问dashboard\n\n登录界面, 通过\"aws eks get-token\" 获取的TOKEN登录\n\n```bash\naws eks get-token --cluster-name ${CLUSTER_NAME} --region ${AWS_REGION} | jq -r '.status.token'\n```\n\n![image-20200728161032875](media/image-20200728161032875.png)"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤6-使用EBS存储.md",
    "content": "# 步骤6 配置使用EBS CSI\n\n6.1 创建所需要的IAM policy , EKS OIDC provider, service account\n\n> 6.1.1 创建所需要的IAM policy\n\n\n```bash\n\n#创建ebs CSI 需要的IAM策略,如果报错请检查策略是否已经存在\naws iam create-policy \\\n    --policy-name Amazon_EBS_CSI_Driver \\\n    --policy-document file://./aws-ebs-csi-driver/ebs-csi-iam-policy.json   \n\n#返回示例,请记录返回的Plociy ARN\nPOLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==`Amazon_EBS_CSI_Driver`].Arn' --output text)\n```\n\n> 6.1.2 获取EKS工作节点的IAM role\n\n```bash\n#获取单个节点组的ROLE\nROLE_NAME=$(aws iam list-roles --query 'Roles[?contains(RoleName,`nodegr`)].RoleName' --output text)\naws iam attach-role-policy --policy-arn ${POLICY_NAME} \\\n    --role-name ${ROLE_NAME} \n\n```\n\n> 6.1.3 部署EBS CSI 驱动到eks 集群\n\n```bash\nkubectl apply -k aws-ebs-csi-driver/deploy/kubernetes/overlays/stable\n\n#验证部署是否正确 \nkubectl get pods -n kube-system | grep csi\n#参考输出,每个节点会各自部署ebs-csi-controller和ebs-csi-node \nNAME                                      READY   STATUS              RESTARTS   AGE\nebs-csi-controller-78bc69cb98-cddl6       4/4     Running   0          4m5s\nebs-csi-controller-78bc69cb98-ng6nx       4/4     Running   0          4m5s\nebs-csi-node-l4m88                        3/3     Running   0          4m5s\nebs-csi-node-z86xc                        3/3     Running   0          4m5s\n```\n\n6.2 部署EBS动态卷实例应用\n\n```bash\nkubectl apply -f aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/\n\n#查看storageclass\nkubectl describe storageclass ebs-sc\n\n#查看示例app状态\nkubectl get pods\n\n#查看是否有失败事件(可选)\n#kubectl get events\n\nkubectl get pv\nPV_NAME=$(kubectl get pv -o json | jq -r '.items[0].metadata.name')\nkubectl describe persistentvolumes ${PV_NAME}\n\nkubectl exec -it app --  tail -f  /data/out.txt\n# Thu Mar 5 14:19:43 UTC 2020\n# Thu Mar 5 14:19:48 UTC 2020\n\n#删除示例程序\nkubectl delete -f aws-ebs-csi-driver/examples/kubernetes/dynamic-provisioning/specs/\n```"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤7-在EKS中使用IAMRole进行权限管理.md",
    "content": "# 步骤7 在EKS中使用IAM Role进行权限管理\n我们将要为ServiceAccount配置一个S3的访问角色，并且部署一个job应用到EKS集群，完成S3的写入。\n\n\n\n7.1 配置IAM Role、ServiceAccount\n\n>7.1.1 使用eksctl 创建service account \n\n```bash\n# 在步骤3我们已经创建了OIDC身份提供商 \n# 请检查IAM OpenID Connect (OIDC) 身份提供商是否已经创建\naws eks describe-cluster --name ${CLUSTER_NAME} --query cluster.identity.oidc.issuer --output text\n# 如果上述命令无输出，请执行以下命令创建OpenID Connect (OIDC) 身份提供商\n#eksctl utils associate-iam-oidc-provider --cluster=${CLUSTER_NAME} --approve --region ${AWS_REGION}\n\n#创建serviceaccount s3-echoer with IAM role\neksctl create iamserviceaccount --name s3-echoer --namespace default \\\n    --cluster ${CLUSTER_NAME} --attach-policy-arn arn:aws-cn:iam::aws:policy/AmazonS3FullAccess \\\n    --approve --override-existing-serviceaccounts \n\n```\n\n7.2 部署测试访问S3的应用\n*使用已有s3 bucket或创建s3 bucket, 请确保bucket名字唯一才能创建成功.\n\n```bash\n# 设置环境变量TARGET_BUCKET,Pod访问的S3 bucket\nTARGET_BUCKET=eksworkshop-irsa-2020\nif [ $(aws s3 ls | grep $TARGET_BUCKET | wc -l) -eq 0 ]; then\n    aws s3api create-bucket  --bucket $TARGET_BUCKET   --create-bucket-configuration LocationConstraint=$AWS_DEFAULT_REGION  --region $AWS_DEFAULT_REGION\nelse\n    echo \"S3 bucket $TARGET_BUCKET existed, skip creation\"\nfi\n\n# 修改Region,部署Job\nsed -e \"s/TARGET_BUCKET/${TARGET_BUCKET}/g;s/us-west-2/${AWS_DEFAULT_REGION}/g\" s3-echoer/s3-echoer-job.yaml.template > s3-echoer/s3-echoer-job.yaml\nkubectl apply -f s3-echoer/s3-echoer-job.yaml\n\n# 验证\nkubectl get job/s3-echoer\nkubectl logs job/s3-echoer\n## 参考输出\nUploading user input to S3 using eksworkshop-irsa-2019/s3echoer-1583415691\n\n# 检查S3 bucket上面的文件\naws s3api list-objects --bucket $TARGET_BUCKET --query 'Contents[].{Key: Key, Size: Size}'  \n[\n    {\n        \"Key\": \"s3echoer-1583415691\",\n        \"Size\": 27\n    }\n]\n\n#清理\nkubectl delete job/s3-echoer\n```\n\n7.3 部署第二个IAM 权限测试Pod(可选)\n\n```bash\ncd china/2020_EKS_Launch_Workshop/resource/\n\n# Apply the testing\nkubectl apply -f IRSA/iam-pod.yaml\npod/s3-echoer created created\n\nkubectl get pod  s3-echoer\nNAME                            READY   STATUS    RESTARTS   AGE\ns3-echoer                       1/1     Running   0          2m38s\n\n# 验证IAM Role 是否生效\nkubectl exec -it s3-echoer bash\n# In promote input, the output Arn should looks like assumed-role/eksctl-gcr-zhy-eksworkshop-addon-iamservicea-Role\naws sts get-caller-identity\n# output shoudld list all the S3 bucket in AWS_REGION under the account \naws s3 ls\naws ec2 describe-instances\n# output should be like: An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation.\n\n# cleanup\nkubectl delete -f IRSA/iam-pod.yaml\n\n```\n"
  },
  {
    "path": "global/2020_GCR_SZ_ContainerDay/步骤8-实现应用Pod和集群进行自动扩展.md",
    "content": "# 步骤8 使用HPA对Pod进行自动扩展， 使用CA对集群进行自动扩展\n\n> 本节内容概要\n* 配置kube-ops-view 观察pod与node的变化,如果是生产系统service请不要对外开放访问。\n* 为集群配置一个HPA，并且部署一个应用进行压力测试，验证Pod 横向扩展能力。\n* 为集群配置一个CA，使用CA对集群进行自动扩展。\n* 为集群配置一个HPA，并且部署一个应用进行压力测试，验证Pod 横向扩展能力。\n* 为集群配置一个CA，使用CA对集群进行自动扩展\n\n \n\n8.1 配置kube-ops-view, 在8.2,8.3操作中持续观察pod和node的变化\n\n   ```bash\n   \n   kubectl apply -f kube-ops-view/deploy\n   \n   kubectl get svc kube-ops-view \n   NAME            TYPE           CLUSTER-IP      EXTERNAL-IP                                                             PORT(S)        AGE\n   kube-ops-view   LoadBalancer   10.100.41.212   ae8b0671ef684478e82309532558792d-75589102.us-east-1.elb.amazonaws.com   80:32354/TCP   13m\n   ```\n\n   ![image-20200728214630797](/Users/wsuam/Library/Application Support/typora-user-images/image-20200728214630797.png)\n\n\n\n8.2 使用HPA对Pod进行自动扩展\n\n8.2.1 Install Metrics Server\n\n```bash\n# 安装Metrics Server\ncd hpa\nkubectl apply -f metrics-server-v0.3.6/deploy/1.8+/\n\n# 验证 Metrics Server installation\nkubectl get deployment metrics-server -n kube-system\nkubectl get apiservice v1beta1.metrics.k8s.io -o yaml\n#输出:all checks passed\n conditions:\n  - lastTransitionTime: \"2020-07-29T15:04:11Z\"\n    message: all checks passed\n    reason: Passed\n    status: \"True\"\n    type: Available\n```\n\n8.2.2 安装 HPA sample application php-apache\n\n```bash\nkubectl apply -f php-apache.yaml\n\n# Set threshold to CPU30% auto-scaling, and up to 5 pod replicas\nkubectl autoscale deployment php-apache --cpu-percent=30 --min=1 --max=5\nkubectl get hpa\n```\n\n8.2.3 开启 load-generator\n\n```bash\nkubectl run --generator=run-pod/v1 -it --rm load-generator --image=busybox /bin/sh\n\n# 提示框输入\nwhile true; do wget -q -O- http://php-apache.default.svc.cluster.local; done\n```\n\n8.2.4 Check HPA\n\n```bash\n#在cloud9中新开一个终端,观察pod变化\nkubectl get hpa --watch\nNAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE\nphp-apache   Deployment/php-apache   250%/30%   1         5         4          3m22s\n\nkubectl get deployment php-apache\nNAME         READY   UP-TO-DATE   AVAILABLE   AGE\nphp-apache   5/5     5            5           6m2s\n\n```\n\n8.3 使用CA对集群进行自动扩展\n\n适用于AWS的Cluster Autoscaler提供与Auto Scaling Group 集成。 它使用户可以从四个不同的部署选项中进行选择：\n1. 一个Auto Scaling Group - 本节使用的方式\n2. 多个Auto Scaling组\n3. 自动发现 Auto-Discovery\n4. 主节点设置\n\n8.3.1 修改默认ASG弹性组最大容量Max\n\n修改Capacity为\nMin: 2\nMax: 6\n\n![image-20200729231230494](media/image-20200729231230494.png)\n\n8.3.3 配置Cluster Autoscaler (CA)\n\n```bash\ncd cluster-autoscaler\n\n#查看ASG组\naws autoscaling describe-auto-scaling-groups --query \"AutoScalingGroups[0].AutoScalingGroupName\" --output text\n\n\n\n#使用vi编辑cluster_autoscaler.yml替换为你的ASG组，比如eks-deb9cd6d-75ff-2124-ff17-b6f3c4b5a4ef\n--nodes=2:6:<AUTOSCALING GROUP NAME>\n\n\n\n# Apply IAM Policy\nSTACK_NAME=$(eksctl get nodegroup --cluster ${CLUSTER_NAME} --region=${AWS_REGION} -o json | jq -r '.[].StackName')\necho $STACK_NAME\nROLE_NAME=$(aws cloudformation describe-stack-resources --stack-name $STACK_NAME --region=${AWS_DEFAULT_REGION} | jq -r '.StackResources[] | select(.ResourceType==\"AWS::IAM::Role\") | .PhysicalResourceId')\necho $ROLE_NAME\n\n\n\naws iam put-role-policy --role-name $ROLE_NAME --policy-name ASG-Policy-For-Worker --policy-document file://./k8s-asg-policy.json --region ${AWS_DEFAULT_REGION}\n\naws iam get-role-policy --role-name $ROLE_NAME --policy-name ASG-Policy-For-Worker --region ${AWS_DEFAULT_REGION}\n\n# 部署 CA\nkubectl apply -f cluster_autoscaler.yml\nkubectl get pod -n kube-system -o wide \\\n    $(kubectl get po -n kube-system | egrep -o cluster-autoscaler[a-zA-Z0-9-]+)\n#查看日志\n#kubectl logs -f deployment/cluster-autoscaler -n kube-system\n\n\n```\n\n8.3.4 水平扩展集群\n\n```bash\n#部署测试应用\nkubectl apply -f nginx-to-scaleout.yaml\nkubectl get deployment/nginx-to-scaleout\n\n# Scale out the ReplicaSet\nkubectl scale --replicas=20 deployment/nginx-to-scaleout\n\nkubectl get pods --watch\nNAME                                 READY   STATUS    RESTARTS   AGE\nbusybox                              1/1     Running   0          22h\nnginx-to-scaleout-84f9cdbd84-2tklw   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-4rs5d   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-72sb7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-7rdjb   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-9kpt6   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-h4fd7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-hxxq7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-pxhc5   1/1     Running   0          19m\nnginx-to-scaleout-84f9cdbd84-snbc7   1/1     Running   0          17m\nnginx-to-scaleout-84f9cdbd84-snd56   1/1     Running   0          17m\n\nkubectl logs -f deployment/cluster-autoscaler -n kube-system\n\n#Check the AWS Management Console to confirm that the Auto Scaling groups are scaling up to meet demand. \naws ec2 describe-instances --filters \"Name=tag:eks:cluster-name,Values=${CLUSTER_NAME}\" --query \"Reservations[].Instances[].[InstanceId,State.Name]\" --region ${AWS_REGION}\n\n[\n    [\n        \"i-00a58166f01483577\",\n        \"running\"\n    ],\n    [\n        \"i-028933f3a55edae59\",\n        \"running\"\n    ],\n    [\n        \"i-01adcd8b6e3c7ce8c\",\n        \"running\"\n    ],\n    [\n        \"i-02e545c32952d9879\",\n        \"running\"\n    ]\n]\n\n```\n\n8.3.5 clean up\n\n```bash\nkubectl delete -f cluster-autoscaler/nginx-to-scaleout.yaml\nkubectl delete -f cluster-autoscaler/cluster_autoscaler.yml\n```\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/README.md",
    "content": "### \n### 0903 成都 MAD Day\n\n\n\n实验环境设置\n\n[通过Cloud9搭建准备实验环境](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/%E9%80%9A%E8%BF%87AWS%20Cloud9%E6%90%AD%E5%BB%BA%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83.md)\n\n\n\nLab1  Serverless\n\n1. [步骤1-从头开始写一个 serverless API](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A41-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n\n2. [步骤2-使用serverless 快速构建Express应用](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab1-serverless/%E6%AD%A5%E9%AA%A41-%E4%BD%BF%E7%94%A8serverless%20%E5%BF%AB%E9%80%9F%E6%9E%84%E5%BB%BAExpress%E5%BA%94%E7%94%A8.md)\n\n   \n\nLab2 EKS 动手训练营\n\n1.  [步骤1-设置默认region, 安装eksctl, kubectl工具](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A41-%E8%AE%BE%E7%BD%AE%E9%BB%98%E8%AE%A4region%2C%20%E5%AE%89%E8%A3%85eksctl%2C%20kubectl%E5%B7%A5%E5%85%B7.md)\n3.  [步骤2,  创建EKS集群](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A42-%E5%88%9B%E5%BB%BAEKS%E9%9B%86%E7%BE%A4.md)\n4.  [步骤3, 配置aws-load-balancer-controller&部署2048游戏]()\n5.  [步骤4-可观测性-日志收集](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A44-%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7-%E6%97%A5%E5%BF%97%E6%94%B6%E9%9B%86.md)\n6.  [步骤5-可观测性-prometheus-grafana.md](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A45-%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7-prometheus-grafana.md)\n7.  [步骤6-使用CodePipeline 实现EKS环境CICD.md](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A46-%E4%BD%BF%E7%94%A8CodePipeline%20%E5%AE%9E%E7%8E%B0EKS%E7%8E%AF%E5%A2%83CICD.md)\n7.  [步骤7-使用Karpenter实现EKS工作节点弹性伸缩](https://github.com/aws-samples/eks-workshop-greater-china/blob/master/global/2021_GCR_MAD_Day/lab2-eks/%E6%AD%A5%E9%AA%A47-%E4%BD%BF%E7%94%A8Karpenter%E5%AE%9E%E7%8E%B0EKS%E5%B7%A5%E4%BD%9C%E8%8A%82%E7%82%B9%E5%BC%B9%E6%80%A7%E4%BC%B8%E7%BC%A9.md)\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab1-serverless/步骤1-从头开始写一个 serverless API.md",
    "content": "## Serverless 快速简易 API\n\n### 目的\n\n快速从零开始写一个简易 API。\n\n### 步骤\n\n1. 创建 Lambda 函数并写入逻辑\n2. 创建 HTTP API 触发器\n3. 测试\n\n### 1. 创建 Lambda 函数并写入逻辑\n\n打开 Lambda 服务。\n\n![](steps/s1.png)\n\n点击「Create function」创建 Lambda 函数。\n\n![](steps/s2.png)\n\n输入 Lambda 名字。我们使用一个 Lambda 函数来应对所有的 API，这种模式叫做「fat Lambda」。反之，如果使用不同的 Lambda 函数来对应不同的 API，就叫做「lean Lambda」。\n\n![](steps/s3.png)\n\n创建完如下。\n\n![](steps/s4.png)\n\n写入代码。\n\n![](steps/s5.png)\n\n代码如下。\n\n```node\nexports.handler = async (event) => {\n    // console.log(event);\n\n    const queryParams = event.queryStringParameters;\n    const pathParams = event.pathParameters;\n\n    let body = 'No params';    \n    if (pathParams) {\n        body = `${JSON.stringify(pathParams)} is what I got.`\n    } else if (queryParams) {\n        body = `${JSON.stringify(queryParams)} is what I got.`\n    }\n\n    // TODO implement\n    const response = {\n        statusCode: 200,\n        body: body,\n    };\n    return response;\n};\n```\n\n这部分代码会优先打印路径参数，比如 `/topics/{id}` 中的 `{id}`，如果没有的话则打印请求字符串路径，比如 `?id=100` 中的 `id`。\n\n点击「Deploy」保存代码。\n\n![](steps/s6.png)\n\n接下来我们做下测试。\n\n![](steps/s7.png)\n\n点击「Test」旁边的小三角，点击「Configure test event」，创建测试事件。选择 `apigateway-aws-proxy`，因为后续我们会使用 API Gateway，它发送给 Lambda 的事件就是这个类型。事件名字写作「test」。\n\n![](steps/s8.png)\n\n接下来点击测试，选择「test」事件。结果应该如下，成功打印路径参数。\n\n![](steps/s9.png)\n\n### 2. 创建触发器\n\n接下来创建 API Gateway 触发器。我们可以从 API Gateway 界面添加，也可以在 Lambda 内直接创建添加。为了简便我们从 Lambda 界面添加。点击「Add trigger」。\n\n![](steps/s10.png)\n\n选择「API Gateway」，点击「Create an API」，选择「HTTP API」。为了快速演示效果，我们不使用外部鉴权机制，所以「Security」选择「Open」，即不鉴权。\n\n![](steps/s11.png)\n\n这里我们需要修改一下默认的调用策略，方便我们做更多测试。先刷新一下页面。\n\n接下来，选择「Configuration」标签，在左边选择「Permissions」，下拉至「Resource-based policy」，点击唯一一条记录的链接，点击「Edit」按钮。\n\n![](steps/s12.png)\n\n把「Source Arn」下尾部的 `.../*/*/fat-lambda` 改成 `.../*`，并保存。\n\n### 3. 测试\n\n接下来，找到「Configuration」标签页下的「Triggers」，然后点击 API Gateway 的链接到 API Gateway 界面。\n\n![](steps/s13.png)\n\n找到如下链接。\n\n![](steps/s14.png)\n\n直接在浏览器调用，显示「No params」。\n\n![](steps/s15.png)\n\n加一个请求字符串测试。\n\n![](steps/s16.png)\n\n要使用路径参数需要先在路径中添加。点击 API Gateway 下的「Routes」，点击「/fat-lambda」之下的 `ANY`。\n\n![](steps/s17.png)\n\n给路径添加一个参数，成 `/fat-lambda/{id}`。\n\n![](steps/s18.png)\n\n在浏览器地址末尾加入任意字符串，刷新，可见结果。\n\n![](steps/s19.png)\n\n### 自由探索\n\n你可以随意添加 API 路径和参数，然后指向我们的 Lambda 函数，并且在 Lambda 函数内做处理。\n\n\n\n\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab1-serverless/步骤1-使用serverless 快速构建Express应用.md",
    "content": "## 步骤1- 使用serverless 快速构建Express应用\r\n\r\n\r\n\r\n### 目的\r\n\r\n通过把一个传统 Web 应用使用容器化方式部署到 AWS Lambda，体验 AWS 无服务器服务。涉及服务：AWS Lambda、Amazon API Gateway、Amazon ECR、AWS SAM、AWS Cloud9。\r\n\r\n### 步骤\r\n\r\n1. 构建本地应用。在本地搭建 Express 应用，这是最传统的应用构建方式。\r\n2. 改造成容器。将前述 Express 应用改造成容器。\r\n3. 改造成无服务器应用。将容器应用改造成无服务器应用。\r\n\r\n### 1. 构建本地应用\r\n\r\n- 下载 Express 和 EJS\r\n- 创建网页文件\r\n- 本地测试\r\n\r\n#### 1-1. 下载 Express 和 EJS\r\n\r\n我们先下载 Express 和 EJS 以及 Body Parser 工具。\r\n\r\nExpress 是 Web 服务器，EJS（Embedded JavaScript）是一个用 JS 来写模板的工具，Body Parser 用于提取 HTTP 请求中的信息。\r\n\r\n```shell\r\n\r\n# 进入 environment 文件夹\r\n\r\ncd ~/environment\r\n\r\n# 创建子文件夹\r\n\r\nmkdir serverless-express\r\ncd serverless-express\r\n\r\n# 初始化 Node 项目\r\n\r\nnpm init -y\r\n\r\n# 下载 Express 和 EJS\r\nnpm i express ejs body-parser\r\n\r\n\r\n```\r\n\r\n#### 1-2. 创建网页文件\r\n\r\n接下来我们创建一个非常简单的待办事项 Web 应用。复制下面的代码，粘贴到命令行，并执行。\r\n\r\n```shell\r\n# 创建入口文件（index.js）\r\n\r\ncat <<\"EOF\" > index.js\r\nvar express = require('express');\r\nvar app = express();\r\nvar port = 8081;\r\nvar bodyParser = require(\"body-parser\");\r\n\r\napp.use(bodyParser.urlencoded({ extended: true }));\r\n\r\napp.set('view engine', 'ejs');\r\n\r\nvar task = [\"buy milk\", \"learn javascript\", \"learn express\"];\r\n\r\napp.post('/addtask', function (req, res) {\r\n    var newTask = req.body.newtask;\r\n    task.push(newTask);\r\n    res.redirect(\"/\");\r\n});\r\n\r\napp.get(\"/\", function(req, res) {\r\n    res.render('index', { task, completed });\r\n});\r\n\r\nvar completed = [\"finish learning nodejs\"];\r\n\r\napp.post(\"/removetask\", function(req, res) {\r\n    var completedTask = req.body.check;\r\n    \r\n    if (typeof completedTask === \"string\") {\r\n        completed.push(completedTask);\r\n        task.splice(task.indexOf(completedTask), 1);\r\n    } else if (typeof completedTask === \"object\") {\r\n        for (var i = 0; i < completedTask.length; i++){\r\n            completed.push(completedTask[i]);\r\n            task.splice(task.indexOf(completedTask[i]), 1);\r\n        }\r\n    }\r\n\r\n    res.redirect(\"/\");\r\n});\r\n\r\napp.listen(port, function () {\r\n  console.log(`LISTENING PORT ${port}`);\r\n});\r\nEOF\r\n```\r\n\r\n然后我们创建一个网页模板。同样，复制下面的代码，粘贴到命令行，并执行。\r\n\r\n```shell\r\n\r\n# 创建模板文件夹\r\n\r\nmkdir views\r\n\r\n# 创建模板（views/index.ejs）\r\n\r\ncat <<\"EOF\" > views/index.ejs\r\n<html>\r\n  <head>\r\n    <title> Todo </title>\r\n    <link href=\"/styles.css\" rel=\"stylesheet\">\r\n  </head>\r\n<body>\r\n  <div class=\"container\">\r\n     <h2> Simple Todo app </h2>\r\n<form action =\"/addtask\" method=\"POST\">\r\n       <input type=\"text\" name=\"newtask\" placeholder=\"add new task\">        <button> Add Task </button>\r\n<h2> Added Task </h2>\r\n   <% for( var i = 0; i < task.length; i++){ %>\r\n<li><input type=\"checkbox\" name=\"check\" value=\"<%= task[i] %>\" /> <%= task[i] %> </li>\r\n<% } %>\r\n<button formaction=\"/removetask\" type=\"submit\"> Remove </button>\r\n</form>\r\n<h2> Completed task </h2>\r\n    <% for(var i = 0; i < completed.length; i++){ %>\r\n      <li><input type=\"checkbox\" checked><%= completed[i] %> </li>\r\n<% } %>\r\n</div>\r\n</body>\r\n</html>\r\nEOF\r\n\r\n```\r\n\r\n#### 1-3. 本地测试\r\n\r\n接下来我们在本地测试一下。\r\n\r\n先运行一下这个 Express 应用。\r\n\r\n```shell\r\n\r\nnode index.js\r\n\r\n```\r\n\r\n看到显示 `LISTENING PORT 8081` 就启动成功了。接下来我们测试一下。\r\n\r\n点击终端标签页旁边的绿色加号，选择 `New Terminal`，开启一个新的终端标签页输入如下命令。\r\n\r\n```shell\r\n\r\ncurl localhost:8081\r\n\r\n```\r\n\r\n应该可以看到与下面框内类似的 HTML 输出。这就说明应用正常运行了。\r\n\r\n```html\r\n...\r\n\r\n<li><input type=\"checkbox\" name=\"check\" value=\"learn javascript\" /> learn javascript </li>\r\n\r\n<li><input type=\"checkbox\" name=\"check\" value=\"learn express\" /> learn express </li>\r\n\r\n<button formaction=\"/removetask\" type=\"submit\"> Remove </button>\r\n</form>\r\n<h2> Completed task </h2>\r\n    \r\n      <li><input type=\"checkbox\" checked>finish learning nodejs </li>\r\n\r\n</div>\r\n</body>\r\n</html>\r\n\r\n```\r\n\r\n也可以直接通过 Cloud9 提供的代理预览在本地运行中的应用。\r\n\r\n点击菜单 `Tools → Preview → Preview Running Application`，右下角会出现一个预览窗口。\r\n\r\n点击预览窗口地址栏 `Browser` 字样右边的新窗口图标，会打开一个 `xxxxxxxx.vfs.cloud9.us-west-2.amazonaws.com` 的地址。你应该会看到蓝色 `Oops` 字样，这是因为默认浏览的是 `80` 端口，而我们的应用部署在 `8081` 端口。\r\n\r\n在该地址末尾加上 `:8081`，可以看到这个 Todo 应用。可随意测试添加和删除一些条目。\r\n\r\n部分区域可能不支持 `8080` 之外的其他端口，此时可以回去打开 `index.js` 将 `port` 从 `8081` 修改成 `8080` 再进行操作。如果此处做了修改，后续 `8081` 的部分请都修改成 `8080`。\r\n\r\n这样我们就做好了一个正常可运行的 Express 应用。\r\n\r\n### 2. 容器化\r\n\r\n回到 Cloud9 窗口，点击预览标签页上的叉，关闭预览标签。注意不是控制台最右边的叉，会整个关掉控制台界面。如果不小心关闭控制台界面，点击菜单 `View → Console` 可以重新打开。\r\n\r\n点击之前运行 `node index.js` 并且在显示 `LISTENING PORT 8081` 的控制台标签页，然后按 `Ctrl + C` 来终止 Express 应用。\r\n\r\n接下来我们使用容器来封装应用。\r\n\r\n```bash\r\n#cloud9 环境安装docker\r\nsudo yum install docker -y\r\n\r\n```\r\n\r\n\r\n\r\n#### 2-1. 创建 Dockerfile\r\n\r\n首先我们创建一个 Dockerfile。复制如下代码并粘贴到命令行执行。\r\n\r\n```shell\r\n\r\ncat <<\"EOF\" > Dockerfile\r\nFROM node:14\r\nWORKDIR /usr/src/app\r\nCOPY package*.json ./\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 8081\r\nCMD [ \"node\", \"index.js\" ]\r\n\r\nCOPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:latest /opt/bootstrap /opt/bootstrap\r\nENV READINESS_CHECK_PORT=8081 PORT=8081 RUST_LOG=debug\r\nENTRYPOINT [\"/opt/bootstrap\"]\r\nEOF\r\n\r\n```\r\n\r\n这个 Dockerfile 包括两个部分，中间用空行隔开。\r\n\r\n第一部分是普通的镜像构建，用户可以使用任意命令来构建镜像，基础镜像也可以随意选择。\r\n\r\n第二部分是一个 Lambda 运行时客户端（Lambda Runtime Client）。Lambda 在调用容器的时候，会激活容器，然后期待容器自己去某个地址去获取调用信息，自己执行，执行完了再把结果发到某个地址。\r\n\r\n- 获取调用信息 `http://{AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next`\r\n- 返回结果 `/runtime/invocation/<request-id>/response`\r\n\r\n而我们这个 Lambda 运行时客户端的作用，就是帮用户解决这个转发问题。它把 Lambda 调用转换成 HTTP 请求，然后把返回的结果再转换成 Lambda 的响应。对于应用来说，这个过程是透明的。\r\n\r\n如果应用没有运行在 Lambda 环境中，那么 `AWS_LAMBDA_RUNTIME_API` 环境变量就不会被设置，此时运行时客户端则会直接执行用户在 `CMD` 中指定的命令，不做任何变动。这也意味着我们的传统版应用和服务器版应用，可以使用同一个镜像，更方便。\r\n\r\n接下来，我们添加一个 `.dockerignore` 避免把已经存在的包复制进镜像。这些包会在镜像构建时再下载，而不会被纳入镜像构建的版本追踪。\r\n\r\n```shell\r\n\r\ncat <<\"EOF\" > .dockerignore\r\nnode_modules\r\nnpm-debug.log\r\nEOF\r\n\r\n```\r\n\r\n#### 2-2. 构建镜像\r\n\r\n接下来我们测试下这个镜像。先进行构建。\r\n\r\n```shell\r\n\r\ndocker build . -t serverless-express\r\n\r\ndocker images\r\n\r\n```\r\n\r\n#### 2-3. 运行容器\r\n\r\n构建完成后，我们直接使用这个镜像来启动容器。这个容器将运行在后台。\r\n\r\n```shell\r\n\r\ndocker run -d -p 8081:8081 serverless-express\r\n\r\n```\r\n\r\n同样，使用一个命令来测试效果。\r\n\r\n```shell\r\n\r\ncurl localhost:8081\r\n\r\n```\r\n\r\n应该是和之前一样的效果。此时我们也可以使用之前同样的预览方式来进行预览。\r\n\r\n预览完成之后，我们可以用 `docker ps` 来查看在后台运行的容器，找到第一列的容器 ID，然后用 `docker kill` 命令把这个容器停止掉。\r\n\r\n```shell\r\n\r\ndocker ps\r\n\r\ndocker kill <container-id>\r\n\r\n```\r\n\r\n### 部署到无服务器服务\r\n\r\n接下来我们用 AWS Lambda 来运行容器，并使用 Amazon API Gateway 来作为入口。\r\n\r\n#### 创建 ECR 镜像仓库\r\n\r\n首先，Lambda 只能使用 Amazon ECR 上的镜像来启动容器，所以我们先要创建一个 ECR 仓库。\r\n\r\n```shell\r\n\r\naws ecr create-repository --repository-name serverless-express --query repository.repositoryUri\r\n\r\n```\r\n\r\n上面这条命令会输出一个地址，将它复制下来备用（不包含引号）。然后，我们需要登录到这个仓库。ECR 提供了一条命令来帮助我们登录仓库，把下面的 `<repo-uri>` 换成实际的仓库地址。\r\n\r\n\r\n```shell\r\n\r\naws ecr get-login-password | docker login --username AWS --password-stdin <repo-uri>\r\n\r\n```\r\n\r\n接下来，我们使用 AWS SAM 来快速创建一个 Lambda 函数，以及对应的 API Gateway 入口。SAM 用模板的方式来描述需要创建的资源。\r\n\r\n点击菜单 `File → New File`，将下面的模板粘贴进去，然后保存为 `template.yaml`。注意这个文件置于 `~/environment` 目录，即 `serverless-express/` 的上层目录。\r\n\r\n```yaml\r\nAWSTemplateFormatVersion: '2010-09-09'\r\nTransform: AWS::Serverless-2016-10-31\r\nDescription: >\r\n  sam-app\r\n\r\nGlobals:\r\n  Function:\r\n    Timeout: 10\r\n\r\nResources:\r\n  ExpressFunction:\r\n    Type: AWS::Serverless::Function\r\n    Properties:\r\n      PackageType: Image\r\n      MemorySize: 128\r\n      Policies:\r\n        - CloudWatchLambdaInsightsExecutionRolePolicy # Add IAM Permission for Lambda Insight Extension\r\n      Environment:\r\n        Variables:\r\n          RUST_LOG: debug\r\n      Events:\r\n        Root:\r\n          Type: HttpApi\r\n          Properties:\r\n            Path: /\r\n            Method: ANY\r\n        Petstore:\r\n          Type: HttpApi\r\n          Properties:\r\n            Path: /{proxy+}\r\n            Method: ANY\r\n    Metadata:\r\n      DockerTag: v1\r\n      DockerContext: ./serverless-express\r\n      Dockerfile: Dockerfile\r\n\r\nOutputs:\r\n  ExpressApi:\r\n    Description: \"API Gateway endpoint URL for Prod stage for Express function\"\r\n    Value: !Sub \"https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/\"\r\n```\r\n\r\n接下来我们可以直接用下面的命令构建容器，并且创建 API Gateway 等资源，并部署容器到 Lambda 服务。注意把下面的 `<repo-uri>` 替换成你上面保存的 ECR 仓库地址。\r\n\r\n\r\n```shell\r\n\r\ncd ~/environment\r\n\r\nsam build\r\nsam deploy --stack-name serverless-express --image-repository <repo-uri> --capabilities CAPABILITY_IAM\r\n\r\n```\r\n\r\n运行完成后，我们可以看到类似下面的一个输出：\r\n\r\n- `https://xxxxxx.execute-api.us-west-2.amazonaws.com/`\r\n\r\n打开这个地址，我们就能看到 Express 应用了。这个应用和我们在本地运行的效果是一样的。\r\n\r\n### 自由探索\r\n\r\n我们可以打开 AWS CloudFormation 来查看刚刚通过 SAM 创建的模板和对应的资源。\r\n\r\n在 Amazon API Gateway 下我们可以看到 API 网关和对应的 API 模型。\r\n\r\n在 Lambda 中我们可以看到创建的函数、对应的镜像地址、触发器、权限等。\r\n\r\n在 CloudWatch 中可以看到 Lambda 函数的日志以及实际运行时间，每个请求与通常在十数到数十毫秒。\r\n\r\n### 注意\r\n\r\n为了方便演示，我们没有使用数据库，数据临时存在了进程内。当容器被回收时，数据也就消失了，所以在使用过程中用户可能会发现数据归零。\r\n\r\n在实际应用中，容器通常都是不保存状态的，数据的持久化会置于容器外，所以不存在这个问题。\r\n\r\n\r\n\r\n\r\n\r\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab1-serverless/步骤2-使用serverless 快速构建Express应用.md",
    "content": "## 步骤1- 使用serverless 快速构建Express应用\r\n\r\n\r\n\r\n### 目的\r\n\r\n通过把一个传统 Web 应用使用容器化方式部署到 AWS Lambda，体验 AWS 无服务器服务。涉及服务：AWS Lambda、Amazon API Gateway、Amazon ECR、AWS SAM、AWS Cloud9。\r\n\r\n### 步骤\r\n\r\n1. 构建本地应用。在本地搭建 Express 应用，这是最传统的应用构建方式。\r\n2. 改造成容器。将前述 Express 应用改造成容器。\r\n3. 改造成无服务器应用。将容器应用改造成无服务器应用。\r\n\r\n### 1. 构建本地应用\r\n\r\n- 下载 Express 和 EJS\r\n- 创建网页文件\r\n- 本地测试\r\n\r\n#### 1-1. 下载 Express 和 EJS\r\n\r\n我们先下载 Express 和 EJS 以及 Body Parser 工具。\r\n\r\nExpress 是 Web 服务器，EJS（Embedded JavaScript）是一个用 JS 来写模板的工具，Body Parser 用于提取 HTTP 请求中的信息。\r\n\r\n```shell\r\n\r\n# 进入 environment 文件夹\r\n\r\ncd ~/environment\r\n\r\n# 创建子文件夹\r\n\r\nmkdir serverless-express\r\ncd serverless-express\r\n\r\n# 初始化 Node 项目\r\n\r\nnpm init -y\r\n\r\n# 下载 Express 和 EJS\r\nnpm i express ejs body-parser\r\n\r\n\r\n```\r\n\r\n#### 1-2. 创建网页文件\r\n\r\n接下来我们创建一个非常简单的待办事项 Web 应用。复制下面的代码，粘贴到命令行，并执行。\r\n\r\n```shell\r\n# 创建入口文件（index.js）\r\n\r\ncat <<\"EOF\" > index.js\r\nvar express = require('express');\r\nvar app = express();\r\nvar port = 8081;\r\nvar bodyParser = require(\"body-parser\");\r\n\r\napp.use(bodyParser.urlencoded({ extended: true }));\r\n\r\napp.set('view engine', 'ejs');\r\n\r\nvar task = [\"buy milk\", \"learn javascript\", \"learn express\"];\r\n\r\napp.post('/addtask', function (req, res) {\r\n    var newTask = req.body.newtask;\r\n    task.push(newTask);\r\n    res.redirect(\"/\");\r\n});\r\n\r\napp.get(\"/\", function(req, res) {\r\n    res.render('index', { task, completed });\r\n});\r\n\r\nvar completed = [\"finish learning nodejs\"];\r\n\r\napp.post(\"/removetask\", function(req, res) {\r\n    var completedTask = req.body.check;\r\n    \r\n    if (typeof completedTask === \"string\") {\r\n        completed.push(completedTask);\r\n        task.splice(task.indexOf(completedTask), 1);\r\n    } else if (typeof completedTask === \"object\") {\r\n        for (var i = 0; i < completedTask.length; i++){\r\n            completed.push(completedTask[i]);\r\n            task.splice(task.indexOf(completedTask[i]), 1);\r\n        }\r\n    }\r\n\r\n    res.redirect(\"/\");\r\n});\r\n\r\napp.listen(port, function () {\r\n  console.log(`LISTENING PORT ${port}`);\r\n});\r\nEOF\r\n```\r\n\r\n然后我们创建一个网页模板。同样，复制下面的代码，粘贴到命令行，并执行。\r\n\r\n```shell\r\n\r\n# 创建模板文件夹\r\n\r\nmkdir views\r\n\r\n# 创建模板（views/index.ejs）\r\n\r\ncat <<\"EOF\" > views/index.ejs\r\n<html>\r\n  <head>\r\n    <title> Todo </title>\r\n    <link href=\"/styles.css\" rel=\"stylesheet\">\r\n  </head>\r\n<body>\r\n  <div class=\"container\">\r\n     <h2> Simple Todo app </h2>\r\n<form action =\"/addtask\" method=\"POST\">\r\n       <input type=\"text\" name=\"newtask\" placeholder=\"add new task\">        <button> Add Task </button>\r\n<h2> Added Task </h2>\r\n   <% for( var i = 0; i < task.length; i++){ %>\r\n<li><input type=\"checkbox\" name=\"check\" value=\"<%= task[i] %>\" /> <%= task[i] %> </li>\r\n<% } %>\r\n<button formaction=\"/removetask\" type=\"submit\"> Remove </button>\r\n</form>\r\n<h2> Completed task </h2>\r\n    <% for(var i = 0; i < completed.length; i++){ %>\r\n      <li><input type=\"checkbox\" checked><%= completed[i] %> </li>\r\n<% } %>\r\n</div>\r\n</body>\r\n</html>\r\nEOF\r\n\r\n```\r\n\r\n#### 1-3. 本地测试\r\n\r\n接下来我们在本地测试一下。\r\n\r\n先运行一下这个 Express 应用。\r\n\r\n```shell\r\n\r\nnode index.js\r\n\r\n```\r\n\r\n看到显示 `LISTENING PORT 8081` 就启动成功了。接下来我们测试一下。\r\n\r\n点击终端标签页旁边的绿色加号，选择 `New Terminal`，开启一个新的终端标签页输入如下命令。\r\n\r\n```shell\r\n\r\ncurl localhost:8081\r\n\r\n```\r\n\r\n应该可以看到与下面框内类似的 HTML 输出。这就说明应用正常运行了。\r\n\r\n```html\r\n...\r\n\r\n<li><input type=\"checkbox\" name=\"check\" value=\"learn javascript\" /> learn javascript </li>\r\n\r\n<li><input type=\"checkbox\" name=\"check\" value=\"learn express\" /> learn express </li>\r\n\r\n<button formaction=\"/removetask\" type=\"submit\"> Remove </button>\r\n</form>\r\n<h2> Completed task </h2>\r\n    \r\n      <li><input type=\"checkbox\" checked>finish learning nodejs </li>\r\n\r\n</div>\r\n</body>\r\n</html>\r\n\r\n```\r\n\r\n也可以直接通过 Cloud9 提供的代理预览在本地运行中的应用。\r\n\r\n点击菜单 `Tools → Preview → Preview Running Application`，右下角会出现一个预览窗口。\r\n\r\n点击预览窗口地址栏 `Browser` 字样右边的新窗口图标，会打开一个 `xxxxxxxx.vfs.cloud9.us-west-2.amazonaws.com` 的地址。你应该会看到蓝色 `Oops` 字样，这是因为默认浏览的是 `80` 端口，而我们的应用部署在 `8081` 端口。\r\n\r\n在该地址末尾加上 `:8081`，可以看到这个 Todo 应用。可随意测试添加和删除一些条目。\r\n\r\n部分区域可能不支持 `8080` 之外的其他端口，此时可以回去打开 `index.js` 将 `port` 从 `8081` 修改成 `8080` 再进行操作。如果此处做了修改，后续 `8081` 的部分请都修改成 `8080`。\r\n\r\n这样我们就做好了一个正常可运行的 Express 应用。\r\n\r\n### 2. 容器化\r\n\r\n回到 Cloud9 窗口，点击预览标签页上的叉，关闭预览标签。注意不是控制台最右边的叉，会整个关掉控制台界面。如果不小心关闭控制台界面，点击菜单 `View → Console` 可以重新打开。\r\n\r\n点击之前运行 `node index.js` 并且在显示 `LISTENING PORT 8081` 的控制台标签页，然后按 `Ctrl + C` 来终止 Express 应用。\r\n\r\n接下来我们使用容器来封装应用。\r\n\r\n```bash\r\n#cloud9 环境安装docker\r\nsudo yum install docker -y\r\n\r\n```\r\n\r\n\r\n\r\n#### 2-1. 创建 Dockerfile\r\n\r\n首先我们创建一个 Dockerfile。复制如下代码并粘贴到命令行执行。\r\n\r\n```shell\r\n\r\ncat <<\"EOF\" > Dockerfile\r\nFROM node:14\r\nWORKDIR /usr/src/app\r\nCOPY package*.json ./\r\nRUN npm install\r\nCOPY . .\r\nEXPOSE 8081\r\nCMD [ \"node\", \"index.js\" ]\r\n\r\nCOPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:latest /opt/bootstrap /opt/bootstrap\r\nENV READINESS_CHECK_PORT=8081 PORT=8081 RUST_LOG=debug\r\nENTRYPOINT [\"/opt/bootstrap\"]\r\nEOF\r\n\r\n```\r\n\r\n这个 Dockerfile 包括两个部分，中间用空行隔开。\r\n\r\n第一部分是普通的镜像构建，用户可以使用任意命令来构建镜像，基础镜像也可以随意选择。\r\n\r\n第二部分是一个 Lambda 运行时客户端（Lambda Runtime Client）。Lambda 在调用容器的时候，会激活容器，然后期待容器自己去某个地址去获取调用信息，自己执行，执行完了再把结果发到某个地址。\r\n\r\n- 获取调用信息 `http://{AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next`\r\n- 返回结果 `/runtime/invocation/<request-id>/response`\r\n\r\n而我们这个 Lambda 运行时客户端的作用，就是帮用户解决这个转发问题。它把 Lambda 调用转换成 HTTP 请求，然后把返回的结果再转换成 Lambda 的响应。对于应用来说，这个过程是透明的。\r\n\r\n如果应用没有运行在 Lambda 环境中，那么 `AWS_LAMBDA_RUNTIME_API` 环境变量就不会被设置，此时运行时客户端则会直接执行用户在 `CMD` 中指定的命令，不做任何变动。这也意味着我们的传统版应用和服务器版应用，可以使用同一个镜像，更方便。\r\n\r\n接下来，我们添加一个 `.dockerignore` 避免把已经存在的包复制进镜像。这些包会在镜像构建时再下载，而不会被纳入镜像构建的版本追踪。\r\n\r\n```shell\r\n\r\ncat <<\"EOF\" > .dockerignore\r\nnode_modules\r\nnpm-debug.log\r\nEOF\r\n\r\n```\r\n\r\n#### 2-2. 构建镜像\r\n\r\n接下来我们测试下这个镜像。先进行构建。\r\n\r\n```shell\r\n\r\ndocker build . -t serverless-express\r\n\r\ndocker images\r\n\r\n```\r\n\r\n#### 2-3. 运行容器\r\n\r\n构建完成后，我们直接使用这个镜像来启动容器。这个容器将运行在后台。\r\n\r\n```shell\r\n\r\ndocker run -d -p 8081:8081 serverless-express\r\n\r\n```\r\n\r\n同样，使用一个命令来测试效果。\r\n\r\n```shell\r\n\r\ncurl localhost:8081\r\n\r\n```\r\n\r\n应该是和之前一样的效果。此时我们也可以使用之前同样的预览方式来进行预览。\r\n\r\n预览完成之后，我们可以用 `docker ps` 来查看在后台运行的容器，找到第一列的容器 ID，然后用 `docker kill` 命令把这个容器停止掉。\r\n\r\n```shell\r\n\r\ndocker ps\r\n\r\ndocker kill <container-id>\r\n\r\n```\r\n\r\n### 部署到无服务器服务\r\n\r\n接下来我们用 AWS Lambda 来运行容器，并使用 Amazon API Gateway 来作为入口。\r\n\r\n#### 创建 ECR 镜像仓库\r\n\r\n首先，Lambda 只能使用 Amazon ECR 上的镜像来启动容器，所以我们先要创建一个 ECR 仓库。\r\n\r\n```shell\r\n\r\naws ecr create-repository --repository-name serverless-express --query repository.repositoryUri\r\n\r\n```\r\n\r\n上面这条命令会输出一个地址，将它复制下来备用（不包含引号）。然后，我们需要登录到这个仓库。ECR 提供了一条命令来帮助我们登录仓库，把下面的 `<repo-uri>` 换成实际的仓库地址。\r\n\r\n\r\n```shell\r\n\r\naws ecr get-login-password | docker login --username AWS --password-stdin <repo-uri>\r\n\r\n```\r\n\r\n接下来，我们使用 AWS SAM 来快速创建一个 Lambda 函数，以及对应的 API Gateway 入口。SAM 用模板的方式来描述需要创建的资源。\r\n\r\n点击菜单 `File → New File`，将下面的模板粘贴进去，然后保存为 `template.yaml`。注意这个文件置于 `~/environment` 目录，即 `serverless-express/` 的上层目录。\r\n\r\n```yaml\r\nAWSTemplateFormatVersion: '2010-09-09'\r\nTransform: AWS::Serverless-2016-10-31\r\nDescription: >\r\n  sam-app\r\n\r\nGlobals:\r\n  Function:\r\n    Timeout: 10\r\n\r\nResources:\r\n  ExpressFunction:\r\n    Type: AWS::Serverless::Function\r\n    Properties:\r\n      PackageType: Image\r\n      MemorySize: 128\r\n      Policies:\r\n        - CloudWatchLambdaInsightsExecutionRolePolicy # Add IAM Permission for Lambda Insight Extension\r\n      Environment:\r\n        Variables:\r\n          RUST_LOG: debug\r\n      Events:\r\n        Root:\r\n          Type: HttpApi\r\n          Properties:\r\n            Path: /\r\n            Method: ANY\r\n        Petstore:\r\n          Type: HttpApi\r\n          Properties:\r\n            Path: /{proxy+}\r\n            Method: ANY\r\n    Metadata:\r\n      DockerTag: v1\r\n      DockerContext: ./serverless-express\r\n      Dockerfile: Dockerfile\r\n\r\nOutputs:\r\n  ExpressApi:\r\n    Description: \"API Gateway endpoint URL for Prod stage for Express function\"\r\n    Value: !Sub \"https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/\"\r\n```\r\n\r\n接下来我们可以直接用下面的命令构建容器，并且创建 API Gateway 等资源，并部署容器到 Lambda 服务。注意把下面的 `<repo-uri>` 替换成你上面保存的 ECR 仓库地址。\r\n\r\n\r\n```shell\r\n\r\ncd ~/environment\r\n\r\nsam build\r\nsam deploy --stack-name serverless-express --image-repository <repo-uri> --capabilities CAPABILITY_IAM\r\n\r\n```\r\n\r\n运行完成后，我们可以看到类似下面的一个输出：\r\n\r\n- `https://xxxxxx.execute-api.us-west-2.amazonaws.com/`\r\n\r\n打开这个地址，我们就能看到 Express 应用了。这个应用和我们在本地运行的效果是一样的。\r\n\r\n### 自由探索\r\n\r\n我们可以打开 AWS CloudFormation 来查看刚刚通过 SAM 创建的模板和对应的资源。\r\n\r\n在 Amazon API Gateway 下我们可以看到 API 网关和对应的 API 模型。\r\n\r\n在 Lambda 中我们可以看到创建的函数、对应的镜像地址、触发器、权限等。\r\n\r\n在 CloudWatch 中可以看到 Lambda 函数的日志以及实际运行时间，每个请求与通常在十数到数十毫秒。\r\n\r\n### 注意\r\n\r\n为了方便演示，我们没有使用数据库，数据临时存在了进程内。当容器被回收时，数据也就消失了，所以在使用过程中用户可能会发现数据归零。\r\n\r\n在实际应用中，容器通常都是不保存状态的，数据的持久化会置于容器外，所以不存在这个问题。\r\n\r\n\r\n\r\n\r\n\r\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤1-设置默认region, 安装eksctl, kubectl工具.md",
    "content": "# 步骤2: 设置默认region, 安装eksctl, kubectl工具\n\n我们将在步骤1创建的AWS Cloud9 环境里面安装eksctl,kubectl。进入Cloud9编辑器环境后，在终端中输入以下命令,进行安装。\n\n```bash\n#设置默认region\n#export AWS_DEFAULT_REGION=us-east-1\n#echo \"export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}\" >> ~/.bashrc\nexport KUBECTL_VERSION=v1.25.0 #推荐使用v1.25.0或者1.26\n\n#eksctl 版本 > v0.164.0\ncurl -L \"https://github.com/weaveworks/eksctl/releases/download/v0.164.0/eksctl_$(uname -s)_amd64.tar.gz\"    | tar xz -C .\nsudo mv ./eksctl /usr/local/bin\n\n#kubectl v1.25.0\n#curl -LO --silent https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl\ncurl -LO --silent https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl\nchmod 775 ./kubectl\nsudo mv ./kubectl /usr/local/bin\n\n#安装jq\nsudo yum install -y jq\n\n```\n\n>检查工具的版本 eksctl (版本>=0.160.0), kubectl(version <=1.24)\n\n```bash\neksctl version\nkubectl version\n```\n\n> 下载所需要的配置文件到本地\n\n```bash\ncurl -OL https://github.com/aws-samples/eks-workshop-greater-china/raw/master/global/2020_GCR_SZ_ContainerDay/resources.tgz\ntar -zxf resources.tgz\n```\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤2-创建EKS集群.md",
    "content": "# 步骤2: 创建EKS集群\n\n2.1 eksctl 自动创建VPC和EKS集群\n\n打开Cloud9终端管理控制台， 使用eksctl 创建EKS集群(操作需要10-15分钟),该命令同时会创建名字为eksworkshop,版本为v1.20的EKS 集群，同时创建一个包含2个m5.large 实例的受管节点组。\n\n ```bash\n export CLUSTER_NAME=eksworkshop\n echo \"export CLUSTER_NAME=${CLUSTER_NAME}\" >> ~/.bashrc\n eksctl create cluster \\\n       --name $CLUSTER_NAME \\\n       --version 1.25 \\\n       --managed\n ```\n\n2.2 eksctl 使用已经存在的VPC 创建EKS集群(可选),\n\n需要正确创建VPC和subnet子网，还需要有公有子网和NAT网关,并且，要把公有子网的Enable auto-assign public IPv4 address 选项打开 , 另外公有子网需要打上Tag : kubernetes.io/role/elb, 私有子网需要打上Tag: kubernetes.io/role/internal-elb , [Tag文档说明](https://repost.aws/knowledge-center/eks-load-balancer-controller-subnets)\n\n```bash\n#创建集群配置文件cluster-config.yaml\n#替换子网id, \napiVersion: eksctl.io/v1alpha5\nkind: ClusterConfig\nmetadata:\n  name: eksworksop\n  region: us-east-1\n  version: \"1.25\"\n\nvpc:\n  subnets:\n    private:\n      us-east-2a: { id: <子网id> }\n      us-east-2b: { id: <子网id> }\n    public:\n      us-east-2a: { id: <子网id> }\n      us-east-2b: { id: <子网id> }\n\nmanagedNodeGroups:\n  - name: nodegroup-ng-01\n    minSize: 1\n    maxSize: 3\n    desiredCapacity: 2\n    instanceType: m5.xlarge\n    labels: {role: worker}\n    ssh:\n      publicKeyName: <ssh keypair 名字>\n    tags:\n      nodegroup-role: worker\n    iam:\n      withAddonPolicies:\n        externalDNS: true\n        autoScaler: true\n        certManager: true\n        albIngress: true\n        ebs: true\n        cloudWatch: true\n```\n\n```bash\neksctl create cluster -f cluster_config.yaml\n```\n\n\n\n\n\n ![](../media/15764759782724/15764761011094.jpg)\n\n  查看EKS集群工作节点\n  ```bash\n   kubectl cluster-info\n   kubectl get node\n  ```\n  ![](../media/15764759782724/15764762619982.jpg)\n\n2.2 (可选)部署一个测试应用\n在Cloud9创建一个nginx.yaml,内容如下\n\n```yaml\ncat << EOF >> nginx.yaml\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: \"service-nginx\"\n  annotations:\n        service.beta.kubernetes.io/aws-load-balancer-type: nlb\nspec:\n  selector:\n    app: nginx\n  type: LoadBalancer\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\nEOF\n\n```\n\n > 部署nginx\n\n ```bash\n#部署\nkubectl apply -f nginx.yaml\nkubectl get deploy\nkubectl get svc\n\n#测试\nELB=$(kubectl get svc service-nginx -o json |  jq -r '.status.loadBalancer.ingress[].hostname')\necho $ELB\ncurl $ELB\n  \n ```\n\n>清除\n>\n\n```bash\nkubectl delete -f nginx.yaml\n```\n\n\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤3-部署配置aws-load-balancer-controller&2048游戏.md",
    "content": "# 步骤4  部署、配置AWS Loadbalacner Controller &2048游戏\n\n4.1 准备权限\n\n> 4.1.1 创建IAM OIDC provider\n\n```bash\nexport CLUSTER_NAME=eksworkshop\nexport AWS_DEFAULT_REGION=us-east-1\neksctl utils associate-iam-oidc-provider \\\n    --cluster=$CLUSTER_NAME \\\n    --approve\n```\n\n> 4.1.2 下载yaml文件\n\n```bash\ncurl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.6.0/docs/install/iam_policy.json\n\n#这里有一个bug https://github.com/aws-ia/terraform-aws-eks-blueprints-addons/issues/200\n#需要手动移除iam_policy.json中间的\"aws:RequestTag/elbv2.k8s.aws/cluster\": \"true\"\n#把\"Condition\": {\n#                \"Null\": {\n#                    \"aws:RequestTag/elbv2.k8s.aws/cluster\": \"true\",\n#                    \"aws:ResourceTag/elbv2.k8s.aws/cluster\": \"false\"\n#                }\n#            }\n#替换为\n\"Condition\": {\n                \"Null\": {\n                    \"aws:ResourceTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n```\n\n> 4.1.3 创建对应的policy\n\n```bash\naws iam create-policy \\\n    --policy-name AWSLoadBalancerControllerIAMPolicy \\\n    --policy-document file://iam-policy.json\n    \n#参考输出\n{\n    \"Policy\": {\n        \"PolicyName\": \"AWSLoadBalancerControllerIAMPolicy\", \n        \"PermissionsBoundaryUsageCount\": 0, \n        \"CreateDate\": \"2021-08-28T15:03:32Z\", \n        \"AttachmentCount\": 0, \n        \"IsAttachable\": true, \n        \"PolicyId\": \"ANPAYVRRQ4TUEMTZVTZYW\", \n        \"DefaultVersionId\": \"v1\", \n        \"Path\": \"/\", \n        \"Arn\": \"arn:aws:iam::59********44:policy/AWSLoadBalancerControllerIAMPolicy\", \n        \"UpdateDate\": \"2021-08-28T15:03:32Z\"\n    }\n}\n```\n\n> 4.1.4 为AWS Load Balancer controller,创建一个IAM role 和 ServiceAccount \n\n```bash\n#参考上面输出，替换<更换为你的AWSID>\neksctl create iamserviceaccount \\\n       --cluster=$CLUSTER_NAME \\\n       --namespace=kube-system \\\n       --name=aws-load-balancer-controller \\\n       --attach-policy-arn=arn:aws:iam::<更换为你的AWSID>:policy/AWSLoadBalancerControllerIAMPolicy \\\n       --override-existing-serviceaccounts \\\n       --approve\n```\n\n\n\n4.2 配置、安装aws-load-balancer-controller\n\n> 4.2.1 安装cert-manager\n\n```bash\n\nkubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml\n\n```\n\n> 4.2.2 下载aws-loadbalancer-controller\n\n```bash\ncurl -OL  https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.6.0/v2_6_0_full.yaml\n\n```\n\n> 4.2.3 在cloud9中编辑v2_6_0_full.yaml,将--cluster-name=your-cluster-name 修改为--cluster-name=eksworshop\n\n![image-20210828231201954](../media/image-20210828231201954.png)\n\n> 4.2.3 请删除v2_6_0_full.yaml中的Servcie Account,因为我们已经通过eksctl创建了该Servcie Account\n\n```bash\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    app.kubernetes.io/component: controller\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-controller\n  namespace: kube-system\n```\n\n> 4.2.4 安装 aws-load-balancer-controller\n>\n> 在新的版本里面 [kubernetes.io/ingress.class](http://kubernetes.io/ingress.class) annotation 会被遗弃掉, 1.18开始增加了ingressClassName ,然后在spec里面使用ingressClassName即可\n\n```bash\nkubectl apply -f v2_6_0_full.yaml\n\n#创建IngressClass\ncat << EOF >> ingress_alb.yaml\n---\napiVersion: networking.k8s.io/v1\nkind: IngressClass\nmetadata:\n  name: alb\nspec:\n  controller: ingress.k8s.aws/alb\nEOF\n\nkubectl apply -f ingress_alb.yaml\n```\n\n\n\n4.3 使用 aws-load-balancer-controller\n\n> 4.3.1 部署2048游戏\n\n```bash\n#生成2048配置文件\n\n\ncurl -s https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/examples/2048/2048_full.yaml \\\n    | sed 's=alb.ingress.kubernetes.io/target-type: ip=alb.ingress.kubernetes.io/target-type: instance=g' > 2048_full.yaml\n    \nkubectl apply -f 2048_full.yaml\n\n#查看ingress信息\nkubectl get ingress/ingress-2048 -n game-2048\n\nexport GAME_2048=$(kubectl get ingress/ingress-2048 -n game-2048 -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')\necho http://${GAME_2048}\n\n\n```\n\n\n\n> 4.3.2 在浏览器中访问2048游戏\n\n<img src=\"../media/image-20210828232526818.png\" alt=\"image-20210828232526818\" style=\"zoom:50%;\" />\n\n> 4.3.3 清除2048 游戏\n\n```bash\nkubectl delete -f  2048_full_latest.yaml\n```\n\n\n\n参考文档 \n\nhttps://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/deploy/installation/\n\nhttps://www.eksworkshop.com/beginner/130_exposing-service/ingress_controller_alb/\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤4-可观测性-日志收集.md",
    "content": "\n\n### 可观察性1 - 日志收集\n\n1. 配置elasticsearch\n\n   为了简化实验，我们使用了一个单节点ElasticSearch来接受fluent-bit的数据,生产环境请正确配置集群版本\n\n   ```bash\n   cd observeration\n   kubectl apply -f elastisearch.yaml\n   \n   #测试elasticsearch 是否正常工作\n   kubectl port-forward service/elasticsearch 9200:9200\n   \n   #新开一个终端,使用curl 测试\n   curl localhost:9200\n   \n   #参考返回\n   {\n     \"name\" : \"wdpc0YA\",\n     \"cluster_name\" : \"docker-cluster\",\n     \"cluster_uuid\" : \"XAFghJJLRYmBWpg85oPBsA\",\n     \"version\" : {\n       \"number\" : \"6.6.1\",\n       \"build_flavor\" : \"default\",\n       \"build_type\" : \"tar\",\n       \"build_hash\" : \"1fd8f69\",\n       \"build_date\" : \"2019-02-13T17:10:04.160291Z\",\n       \"build_snapshot\" : false,\n       \"lucene_version\" : \"7.6.0\",\n       \"minimum_wire_compatibility_version\" : \"5.6.0\",\n       \"minimum_index_compatibility_version\" : \"5.0.0\"\n     },\n     \"tagline\" : \"You Know, for Search\"\n   }\n   \n   ```\n\n   \n\n2. 配置fluent-bit\n\n   > 部署fluent-bit\n\n    ```bash\n    kubectl apply -f fluent-bit.yaml\n    \n    kubectl get pod | grep fluent | awk '{print $1}' | xargs -n1 kubectl logs \n    \n    #参考输出\n    AWS for Fluent Bit Container Image Version 2.5.0\n    Fluent Bit v1.5.0\n    * Copyright (C) 2019-2020 The Fluent Bit Authors\n    * Copyright (C) 2015-2018 Treasure Data\n    * Fluent Bit is a CNCF sub-project under the umbrella of Fluentd\n    * https://fluentbit.io\n    \n    [2021/09/01 02:22:47] [ info] [engine] started (pid=1)\n    [2021/09/01 02:22:47] [ info] [storage] version=1.0.4, initializing...\n    [2021/09/01 02:22:47] [ info] [storage] in-memory\n    [2021/09/01 02:22:47] [ info] [storage] normal synchronization mode, checksum disabled, max_chunks_up=128\n    [2021/09/01 02:22:47] [ info] [filter:kubernetes:kubernetes.0] https=1 host=kubernetes.default.svc port=443\n    [2021/09/01 02:22:47] [ info] [filter:kubernetes:kubernetes.0] local POD info OK\n    [2021/09/01 02:22:47] [ info] [filter:kubernetes:kubernetes.0] testing connectivity with API server...\n    [2021/09/01 02:22:47] [ warn] [filter:kubernetes:kubernetes.0] could not get meta for POD fluent-bit-nlk8x\n    [2021/09/01 02:22:47] [ info] [http_server] listen iface=0.0.0.0 tcp_port=2020\n    [2021/09/01 02:22:47] [ info] [sp] stream processor started\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=102760595 watch_fd=1 name=/var/log/containers/aws-node-jjj8r_kube-system_aws-node-4287db63a2859ed2fd3813d0dc04983fc7e1ef80949ed742d4594952c8b7a144.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=5248234 watch_fd=2 name=/var/log/containers/aws-node-jjj8r_kube-system_aws-node-5aebf7b7a041e11ecb128e7794533866caf9a08652c532b7ad07e48bb9677aef.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=140510387 watch_fd=3 name=/var/log/containers/aws-node-jjj8r_kube-system_aws-vpc-cni-init-ad363a5b086f318f3423eb19c625540ecc3bee355ce4b8824ca30cf175645b17.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=47212466 watch_fd=4 name=/var/log/containers/cert-manager-db4ccd57b-n6j6h_cert-manager_cert-manager-e71e1ebbebf005fd1dc40eebc938dcbc5f2f41681343e06ee0500c67f6591ab9.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=4390551 watch_fd=5 name=/var/log/containers/cert-manager-webhook-79c5595878-jnhnn_cert-manager_cert-manager-14d77f8b037e51dc10b4c00c360631aaf404123bf18ae363bd039875aa3625be.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=34620536 watch_fd=6 name=/var/log/containers/elasticsearch-67f4cf7798-cv8s6_default_elasticsearch-4cbc0cff0db79b01471775b5cb1ae596706a505d06595099cbef377c2255ddf4.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=28383507 watch_fd=7 name=/var/log/containers/elasticsearch-67f4cf7798-cv8s6_default_set-vm-sync-limit-5dbed0e26e0950d9e354401881b29f96c411f9715c68429229f048c7e9861e13.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=45090899 watch_fd=8 name=/var/log/containers/kube-proxy-bncf9_kube-system_kube-proxy-9691935255cbab98a944de05b72274e6288aadb0f8997729f29be52695619a12.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=109053826 watch_fd=9 name=/var/log/containers/kube-proxy-bncf9_kube-system_kube-proxy-ba3264b1d693a8a845419ca6099077520468594760f92ee2756bd1435cd41503.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=148908484 watch_fd=10 name=/var/log/containers/cert-manager-cainjector-68b467c55f-cg7pm_cert-manager_cert-manager-73b8e807e007fc16a1624f6e670333e53c09927f263a7ecb828dea66fb066315.log\n    [2021/09/01 02:22:47] [ info] inotify_fs_add(): inode=46145117 watch_fd=11 name=/var/log/containers/fluent-bit-nlk8x_default_fluent-bit-b19c2816d74c9b3e565be28359d1660fd6e739d8efa2ecb88d1bc6ce7832bd5f.log\n\n\n3. 配置kibana\n\n   > 安装kibana\n\n   ```bash\n   kubectl apply -f kibana.yaml\n   \n   #获取kibana地址\n   kubectl get svc --field-selector=metadata.name=kibana | tail -1 | awk '{print $4}'\n   \n   ```\n\n   \n\n> 在浏览器输入kibana地址, 点击左侧菜单Discover , 创建index pattern ,输入\\*fluent-bit\\*\n\n![image-20210830162024952](../media/image-20210830162024952.png)\n\n\n\n> 选择时间字段\n\n![image-20210830162200255](../media/image-20210830162200255.png)\n\n\n\n> 选择discover\n\n![image-20210830162245778](../media/image-20210830162245778.png)\n\n\n\n4. 清除\n\n   ```bash\n   kubectl delete -f kibana.yaml\n   kubectl delete -f fluent-bit.yaml\n   kubectl delete -f elasticsearch.yaml\n   ```\n\n   "
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤5-可观测性-prometheus-grafana.md",
    "content": "### 可观察性2 - Prometheus&Grafana\n\n\n\n1. 安装helm\n\n   ```bash\n   curl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash\n   \n   helm version --short\n   \n   # 增加 prometheus Helm repo\n   helm repo add prometheus-community https://prometheus-community.github.io/helm-charts\n   \n   # 增加 grafana Helm repo\n   helm repo add grafana https://grafana.github.io/helm-charts\n   \n   \n   ```\n\n2. 部署Prometheus\n\n   ```ba\n   kubectl create namespace prometheus\n   \n   helm install prometheus prometheus-community/prometheus \\\n       --namespace prometheus \\\n       --set alertmanager.persistentVolume.storageClass=\"gp2\" \\\n       --set server.persistentVolume.storageClass=\"gp2\"\n   \n   kubectl get all -n prometheus\n   ```\n\n   输出:\n\n   ![image-20210901113050222](../media/image-20210901113050222.png)\n\n\n\n3. 部署Grafana\n\n   ```bash\n   kubectl create namespace grafana\n   \n   helm install grafana grafana/grafana \\\n       --namespace grafana \\\n       --set persistence.storageClassName=\"gp2\" \\\n       --set persistence.enabled=true \\\n       --set adminPassword='EKS!sAWSome' \\\n       --values grafana.yaml \\\n       --set service.type=LoadBalancer\n   ```\n\n   ![image-20210901130654916](../media/image-20210901130654916.png)\n\n   \n\n   获取grafana访问地址\n\n   ```bash\n   export ELB=$(kubectl get svc -n grafana grafana -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')\n   echo \"http://$ELB\"\n   kubectl get secret --namespace grafana grafana -o jsonpath=\"{.data.admin-password}\" | base64 --decode ; echo\n   \n   ```\n\n   \n\n   ![image-20210901131016616](../media/image-20210901131016616.png)\n\n   > 输入3119,点击load\n\n   ![image-20210901131211866](../media/image-20210901131211866.png)\n\n   > 选择promethus 数据源, 点击导入\n\n   ![image-20210901131429935](../media/image-20210901131429935.png)\n\n   ![grafana-all-nodes](../media/grafana-all-nodes.png)\n\n   \n\n   \n\n   > Pod Monitoring Dashboard 重复上述操作，将3119更换为6417\n\n   ![grafana-all-pods](../media/grafana-all-pods.png)\n\n   \n\n4. 清除资源\n\n   ```bash\n   helm uninstall prometheus --namespace prometheus\n   kubectl delete ns prometheus\n   \n   helm uninstall grafana --namespace grafana\n   kubectl delete ns grafana\n   \n   ```\n\n   \n\n\n\n\n\n\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤6-使用CodePipeline 实现EKS环境CICD.md",
    "content": "\n\n\n\n# 步骤7 使用CodePipeline实现EKS的CI/CD\n\n持续集成 (CI) 和持续交付 (CD) 对于灵活的组织至关重要。 当团队可以频繁地进行离散更改、以编程方式发布这些更改并在不中断的情况下交付更新时，他们的工作效率会更高。在下面的模块中我们将使用AWS CodePipeline构建CI/CD管道，并利用 CI/CD 管道部署一个示例 Kubernetes 服务，我们将对 GitHub 存储库进行更改并观察此更改对集群的自动交付。\n\n## 创建IAM角色\n\n在 AWS CodePipeline 中，我们将使用 AWS CodeBuild 部署示例 Kubernetes 服务。 这需要一个能够与 EKS 集群交互的 AWS Identity and Access Management (IAM) 角色。\n\n在这一步中，我们将创建一个 IAM 角色并添加一个内联策略，我们将在 CodeBuild 阶段使用该策略通过 kubectl 与 EKS 集群交互。\n\n```bash\ncd codepipeline\n\nACCOUNT_ID=$(aws sts get-caller-identity | jq -r .Account)\nTRUST=\"{ \\\"Version\\\": \\\"2012-10-17\\\", \\\"Statement\\\": [ { \\\"Effect\\\": \\\"Allow\\\", \\\"Principal\\\": { \\\"AWS\\\": \\\"${ACCOUNT_ID}\\\" }, \\\"Action\\\": \\\"sts:AssumeRole\\\" } ] }\"\n\necho '{ \"Version\": \"2012-10-17\", \"Statement\": [ { \"Effect\": \"Allow\", \"Action\": \"eks:Describe*\", \"Resource\": \"*\" } ] }' > iam-role-policy\n\naws iam create-role --role-name EksWorkshopCodeBuildKubectlRole --assume-role-policy-document \"$TRUST\" --output text --query 'Role.Arn'\n\naws iam put-role-policy --role-name EksWorkshopCodeBuildKubectlRole --policy-name eks-describe --policy-document file://./iam-role-policy\n\n```\n\n## 修改AWS Auth Config Map\n\n现在我们已经创建了 IAM 角色，我们将将该角色添加到 EKS 集群的 aws-auth ConfigMap。\n\n一旦 ConfigMap 包含这个新角色，管道 CodeBuild 阶段中的 kubectl 将能够通过 IAM 角色与 EKS 集群交互。\n\n```bash\nROLE=\"    - rolearn: arn:aws:iam::${ACCOUNT_ID}:role/EksWorkshopCodeBuildKubectlRole\\n      username: build\\n      groups:\\n        - system:masters\"\n\nkubectl get -n kube-system configmap/aws-auth -o yaml | awk \"/mapRoles: \\|/{print;print \\\"$ROLE\\\";next}1\" > ./aws-auth-patch.yml\n\nkubectl patch configmap/aws-auth -n kube-system --patch \"$(cat ./aws-auth-patch.yml)\"\n```\n\n⚠️ 注意：如果您想手动编辑 aws-auth ConfigMap   您可以执行: $ kubectl edit -n kube-system configmap/aws-auth\n\n## 从 GitHub FORK 演示用的代码仓库\n\n我们现在将 Fork 示例 Kubernetes 服务，以便我们能够修改存储库并触发构建。\n登录 GitHub 并将示例服务 fork 到您自己的帐户：\nhttps://github.com/rnzsgh/eks-workshop-sample-api-service-go\n\n![](../media/2021-08-09-12-00-02.png)\n\n一旦仓库被Fork成功，您可以在个人账号的代码仓库中看到它，类似于下面这样\n\n请修改Dockerfile 使用AWS public registry ,避免dockerhub 免费账号pull limit 限制错误\n\n```bash\n#FROM golang:1.11.1 as builder\nFROM public.ecr.aws/o7x6j3x6/golang:1.11.1 as builder\n```\n\n\n\n![](../media/2021-08-09-12-01-35.png)\n## 配置GitHub访问token\n\n为了让 CodePipeline 从 GitHub 接收回调，我们需要生成个人访问令牌。\n\n创建后，访问令牌可以存储在安全的 enclave 中并重复使用，因此仅在第一次运行或需要生成新密钥时才需要执行此步骤。\n\n在 GitHub 中访问以下页面创建新的token https://github.com/settings/tokens/new\n![](../media/github_token_name.png)\n![](../media/github_copy_access.png)\n\n## Codepipeline 设置\n\n现在我们将使用 AWS CloudFormation 创建 AWS CodePipeline。\n\nCloudFormation 是一种基础设施即代码 (IaC) 工具，它为您提供一种通用语言来描述和供应云环境中的所有基础设施资源。 CloudFormation 允许您使用一个简单的文本文件，以自动化和安全的方式为您的所有区域和账户的应用程序所需的所有资源建模和配置。\n\n每个 EKS 部署/服务都应该有自己的 CodePipeline 并位于隔离的源存储库中。\n\n您可以修改随本研讨会提供的 CloudFormation 模板以满足您的系统要求，从而轻松地将新服务载入您的 EKS 集群。 对于每个新服务，可以重复以下步骤。\n\n单击链接以在 AWS 管理控制台中创建 CloudFormation 堆栈。\nhttps://console.aws.amazon.com/cloudformation/home?#/stacks/create/review?stackName=eksws-codepipeline&templateURL=https://s3.amazonaws.com/eksworkshop.com/templates/main/ci-cd-codepipeline.cfn.yml \n\n(可以在此处下载模板：https://s3.amazonaws.com/eksworkshop.com/templates/main/ci-cd-codepipeline.cfn.yml)\n\n打开Console后，输入github的用户名和上一步中创建的token, 以及最下面的EKS集群名字将默认的eksworkshop-eksctl修改为 *eksworkshop*，勾选 Capabilites , 然后在右下角点击【创建堆栈】\n![](../media/2021-08-09-5-43-05.png)\n\n\n\n![image-20210901220412957](../media/image-20210901220412957.png)\n\n等待状态从“CREATE_IN_PROGRESS”变成“CREATE_COMPLETE”后进行下一步\n\n![](../media/2021-08-09-5-57-28.png)\n\n点击链接https://console.aws.amazon.com/codesuite/codepipeline/pipelines 在控制台上打开CodePipeline，会看到一个以eks-workshop-codepipeline 开头的pipeline，点击进去查看详情\n\n![](../media/2021-08-10-10-31-55.png)\n\n\n\n通过kubectl get svc 查看部署的服务\n\n![](../media/2021-08-10-10-46-27.png)\n\n可以看到hello-k8s 的服务已经部署好了，并且对外提供一个ELB的访问域名，我们复制这个域名到浏览器中访问一下:\n\n![](../media/2021-08-10-10-48-58.png)\n\n可以看到Message中返回 Hello Word 信息，表示服务部署成功，可正常对外访问\n\n## 触发新的发布\n\n到目前为止，我们已经使用AWS CodePipeline 设置好了EKS的CI/CD，现在我们对GitHub仓库中的代码进行修改，看是否能够自动构建和发布到EKS集群\n打开GitHub 选择刚刚fork的仓库 eks-workshop-sample-api-service-go，点击 main.go 文件，然后点击右上角的【编辑】按钮，将Hello Word,改成其他的字符串，如下改成 Hello Word, CICD on EKS，然后点击【commit changes】按钮，提交修改\n\n![](../media/2021-08-10-10-59-10.png)\n![](../media/2021-08-10-11-00-12.png)\n\n在AWS控制台中查看CodePipeline，[https://console.aws.amazon.com/codesuite/codepipeline/pipelines](https://console.aws.amazon.com/codesuite/codepipeline/pipelines/eksws-codepipeline-CodePipelineGitHub-DXUZ8NB2O1FM/view?region=us-east-1)，看到更新正在被自动构建\n\n![](../media/2021-08-10-11-01-21.png)\n\n等待构建完成，再次从浏览器中访问服务\n\n![image-20210901222034285](../media/image-20210901222034285.png)\n\nmessage 信息变成我们在GitHub中提交的更改信息，说明我们的提交已经成功部署到EKS集群中。\n\n至此，基于CodePipeline的EKS CICD搭建并测试完成。\n\n## 环境清理\n\n清理我们在EKS中部署的服务\n\n```\n$ kubectl delete deployments hello-k8s\n$ kubectl delete services hello-k8s\n```\n\n打开CloudFormation控制台，删除创建CodePipeline的堆栈 https://console.aws.amazon.com/cloudformation\n\n![](../media/2021-08-10-11-31-58.png)\n\n删除S3存储桶中的内容\n\n![](../media/2021-08-10-11-47-44.png)\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤7-使用Karpenter实现EKS工作节点弹性伸缩.md",
    "content": "## 使用Karpenter实现EKS工作节点弹性伸缩 \n\n [Karpenter](https://github.com/aws/karpenter) 是AWS开源的kubernetes 工作节点弹性管理工具，它的目标是提高Kubernetes工作节点的灵活性、伸缩性以及降低成本.  \n\nKarpenter 可以:\n\n* 监控所有被Kubernetes scheduler标记为unschedulable的pods\n* 评估Pod请求的调度请求: 资源请求(GPU/GPU),节点选择器, 亲和性, 容忍度, 拓扑\n* 配置满足 Pod 要求的节点\n* 调度Pods到新节点运行\n* 移除空闲或者不在需要的节点\n\n​      以AWS EKS服务为例，Karpenter 和Cluster AutoScaler 工作原理最大的区别: Cluster AutoScaler 是按照AutoScaling Group(弹性伸缩组)进行管理，通过调整Desired参数来实现节点的伸缩功能,CA并不会去计算、评估Pods的需求进行不同实例的扩展.\n\n   Cluster AutoScaler 工作原理：\n\n![image-20211217165913880](../media/image-20211217165913880.png)\n\n\n\nKarpenter 不使用AutoScaling Group,而是通过对Pods请求的评估直接调用EC2.*CreateFleet()*  API 就可以扩展出所需的实例\n\nKarpenter 工作原理:     \n\n![image-20211217170000431](../media/image-20211217170000431.png)\n\n![img](../media/2021-karpenter-diagram.png)\n\n用例: 如果当前CA管理的都是x86 AutoScaling Group ,当有一个deployment 申请arm资源后, CA不能创建出ARM节点. 而Karpenter 对Pods请求的评估后调用EC2.*CreateFleet()*  API 就可以扩展出所需的ARM实例类型.\n\n\n\n### 创建集群\n\n创建AWS EKS集群,初始化2个m5.large工作节点. 如果已经创建了集群可以忽略本小节\n\n```bash\nexport CLUSTER_NAME=eksworkshop\nexport AWS_DEFAULT_REGION=us-west-2\nAWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)\n\ncat <<EOF > cluster.yaml\n---\napiVersion: eksctl.io/v1alpha5\nkind: ClusterConfig\nmetadata:\n  name: ${CLUSTER_NAME}\n  region: ${AWS_DEFAULT_REGION}\n  version: \"1.21\"\nmanagedNodeGroups:\n  - instanceType: m5.large\n    amiFamily: AmazonLinux2\n    name: ${CLUSTER_NAME}-ng\n    desiredCapacity: 2\n    minSize: 1\n    maxSize: 10\niam:\n  withOIDC: true\nEOF\neksctl create cluster -f cluster.yaml\n```\n\n\n\n ### 1 . 准备工作\n\n 1.1 给VPC子网打Tag\n\nKarpenter 会自动发现含有 `kubernetes.io/cluster/$CLUSTER_NAME`标记的VPC 子网.  下面将使用AWS CLI工具对EKS集群使用的VPC子网打上对应的Tag.\n\n  ```bash\n  SUBNET_IDS=$(aws cloudformation describe-stacks \\\n      --stack-name eksctl-${CLUSTER_NAME}-cluster \\\n      --query 'Stacks[].Outputs[?OutputKey==`SubnetsPrivate`].OutputValue' \\\n      --output text)\n  aws ec2 create-tags \\\n      --resources $(echo $SUBNET_IDS | tr ',' '\\n') \\\n      --tags Key=\"kubernetes.io/cluster/${CLUSTER_NAME}\",Value=\n  ```\n\n  1.2 创建KarpenterNode IAM 角色\n\n   Karpenter 启动的实例必须使用 InstanceProfile 运行，该Profile授予运行容器和配置网络所需的权限。 Karpenter 会自动发现并使用`KarpenterNodeRole-${ClusterName}`的 InstanceProfile. \n\n  首先使用CloudFormation创建IAM资源.\n\n   ```bash\n   TEMPOUT=$(mktemp)\n   curl -fsSL https://karpenter.sh/docs/getting-started/cloudformation.yaml > $TEMPOUT \\\n   && aws cloudformation deploy \\\n     --stack-name Karpenter-${CLUSTER_NAME} \\\n     --template-file ${TEMPOUT} \\\n     --capabilities CAPABILITY_NAMED_IAM \\\n     --parameter-overrides ClusterName=${CLUSTER_NAME}\n   ```\n\n​    其次使用以下命令将Karpenter节点role 添加到kubernetes configmap: aws-auth ,授予Profile连接EKS集群的权限.\n\n```bash\neksctl create iamidentitymapping \\\n  --username system:node:{{EC2PrivateDNSName}} \\\n  --cluster  ${CLUSTER_NAME} \\\n  --arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME} \\\n  --group system:bootstrappers \\\n  --group system:nodes\n```\n\n1.3 为karpenterController创建serviceaccount并关联对应的IAM Role\n\nKarpenter需要特定的权限，比如EC2创建权限. 以下命令会创建对应的 AWS IAM Role, Kubernetes service account, 并且通过AWS [IRSA](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html) 功能将role和IAM Role关联在一起.\n\n```\neksctl create iamserviceaccount \\\n  --cluster $CLUSTER_NAME --name karpenter --namespace karpenter \\\n  --attach-policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/KarpenterControllerPolicy-$CLUSTER_NAME \\\n  --approve\n```\n\n\n\n### 2  使用Helm 安装Karpenter charts\n\n2.1  使用helm 部署Karpentercharts\n\n​    首先添加并更新karpenter的helm仓库,  使用正确的参数安装Karpenter，这里请注意我们使用eksctl创建的service account.\n\n```bash\nhelm repo add karpenter https://charts.karpenter.sh\nhelm repo update\nhelm upgrade --install karpenter karpenter/karpenter --namespace karpenter \\\n  --create-namespace --set serviceAccount.create=false --version 0.5.2 \\\n  --set controller.clusterName=${CLUSTER_NAME} \\\n  --set controller.clusterEndpoint=$(aws eks describe-cluster --name ${CLUSTER_NAME} --query \"cluster.endpoint\" --output json) \\\n  --wait # for the defaulting webhook to install before creating a Provisioner\n```\n\n启用调试日志 (可选)\n\n```sh\nkubectl patch configmap config-logging -n karpenter --patch '{\"data\":{\"loglevel.controller\":\"debug\"}}'\n```\n\n2.2 设置Provisioner\n\n单个 Karpenter provisioner 可以处理许多不同的pod 资源请求. Karpenter 根据标签和关联性等pod属性做出调度和配置. Karpenter 消除了管理许多不同节点组的需求.\n\n使用以下命令创建默认的provisioner. 使用`ttlSecondsAfterEmpty` 参数可以配置节点空闲时间,TTL达到之后Karpenter会终止该工作节点. 可以将该参数设置为-1或者undefined来禁止终止行为.\n\n可以访问[provisioner CRD](https://karpenter.sh/docs/provisioner/) 得到更多的provisioner 配置信息. 例如, `ttlSecondsUntilExpired` 可以设置Karpenter 在过期时间到达后终止该节点.\n\n```bash\ncat <<EOF | kubectl apply -f -\napiVersion: karpenter.sh/v1alpha5\nkind: Provisioner\nmetadata:\n  name: default\nspec:\n  requirements:\n    - key: karpenter.sh/capacity-type\n      operator: In\n      values: [\"spot\"]\n    - key: node.kubernetes.io/instance-type\n      operator: In\n      values: [\"m5.xlarge\", \"m5.2xlarge\",\"m5.4xlarge\",\"m5.12xlarge\",\"c5.xlarge\",\"c5.2xlarge\",\"c5.4xlarge\",\"c5.12xlarge\"]\n  limits:\n    resources:\n      cpu: 1000\n  provider:\n    instanceProfile: KarpenterNodeInstanceProfile-${CLUSTER_NAME}\n  ttlSecondsAfterEmpty: 30\nEOF\n```\n\n\n\n## 3 测试\n\n3.1 部署测试应用,默认副本数为0\n\n```bash\ncat <<EOF | kubectl apply -f -\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: inflate\nspec:\n  replicas: 0\n  selector:\n    matchLabels:\n      app: inflate\n  template:\n    metadata:\n      labels:\n        app: inflate\n      annotations:\n        appmesh.k8s.aws/sidecarInjectorWebhook: disabled\n    spec:\n      terminationGracePeriodSeconds: 0\n      containers:\n        - name: inflate\n          image: public.ecr.aws/eks-distro/kubernetes/pause:3.2\n          resources:\n            requests:\n              cpu: 1\nEOF\n```\n\n3.2 开启多个终端窗口使用watch进行观察节点和pod\n\n```bash\nwatch -t -n 1 kubectl get node -Lnode.kubernetes.io/instance-type -Ltopology.kubernetes.io/zone -Lkubernetes.io/arch\n\n```\n\n```bash\n\nwatch -t -n 1 kubectl get pod\n```\n\n\n\n3.3 伸缩测试\n\n> 通过kubectl scale 增加inflate副本数量,触发karpenter,并观察karpenter controller日志和kubectl node\n\n```bash\nkubectl scale deployment inflate --replicas 1\n```\n\n![image-20211217153045284](../media/image-20211217153045284.png)\n\n![image-20211217153123001](../media/image-20211217153123001.png)\n\n> 将副本增加到10\n\n ```bash\n kubectl scale deployment inflate --replicas 10\n ```\n\n![image-20211217153606747](../media/image-20211217153606747.png)\n\nKarpenter 会计算unschedulable的Pods然后扩展EC2，这里看见拉起的就是c5.2xlarge\n\n![image-20211217153812098](../media/image-20211217153812098.png)\n\n> 收缩测试，当节点空闲时Karpenter controller向该节点发出TTL标志（ controller.node  Added TTL to empty node）时间到了就会终止该EC2节点\n\n```bash\n kubectl scale deployment inflate --replicas 0\n```\n\n![image-20211217154353774](../media/image-20211217154353774.png)\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/lab2-eks/步骤8-EBS使用.md",
    "content": "# 步骤8 配置使用EBS CSI\n\n8. 创建所需要的IAM policy , EKS OIDC provider, service account\n\n\n\n\n> 8.1.3 部署EBS CSI 驱动到eks 集群\n\n```bash\nkubectl apply -k  \"github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.10\"\n\n#验证部署是否正确 \nkubectl get pods -n kube-system | grep csi\n#参考输出,每个节点会各自部署ebs-csi-controller和ebs-csi-node \nNAME                                      READY   STATUS              RESTARTS   AGE\nebs-csi-controller-78bc69cb98-cddl6       4/4     Running   0          4m5s\nebs-csi-controller-78bc69cb98-ng6nx       4/4     Running   0          4m5s\nebs-csi-node-l4m88                        3/3     Running   0          4m5s\nebs-csi-node-z86xc                        3/3     Running   0          4m5s\n```\n\n8.2 部署EBS动态卷实例应用\n\n```bash\n git clone https://github.com/kubernetes-sigs/aws-ebs-csi-driver.git\n cd aws-ebs-csi-driver\n git checkout v1.10.0\n\nkubectl apply -f examples/kubernetes/dynamic-provisioning/manifests\n\n#查看storageclass\nkubectl describe storageclass ebs-sc\n\n#查看示例app状态\nkubectl get pods\n\n#查看是否有失败事件(可选)\n#kubectl get events\n\nkubectl get pv\nPV_NAME=$(kubectl get pv -o json | jq -r '.items[0].metadata.name')\nkubectl describe persistentvolumes ${PV_NAME}\n\nkubectl exec -it app --  tail -f  /data/out.txt\n# Thu Mar 5 14:19:43 UTC 2020\n# Thu Mar 5 14:19:48 UTC 2020\n\n#删除示例程序\nkubectl delete -f examples/kubernetes/dynamic-provisioning/manifests\n```\n\n\n\n8.2 部署EBS静态卷实例应用\n\n```bash\nkubectl apply -f examples/kubernetes/static-provisioning/manifests\n\n... 中间验证步骤同8.1\n\nkubectl delete -f examples/kubernetes/static-provisioning/manifests\n```\n\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/aws-load-balancer-controller/2048_full_latest.yaml",
    "content": "---\napiVersion: v1\nkind: Namespace\nmetadata:\n  name: game-2048\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  namespace: game-2048\n  name: deployment-2048\nspec:\n  selector:\n    matchLabels:\n      app.kubernetes.io/name: app-2048\n  replicas: 5\n  template:\n    metadata:\n      labels:\n        app.kubernetes.io/name: app-2048\n    spec:\n      containers:\n      - image: alexwhen/docker-2048\n        imagePullPolicy: Always\n        name: app-2048\n        ports:\n        - containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n  namespace: game-2048\n  name: service-2048\nspec:\n  ports:\n    - port: 80\n      targetPort: 80\n      protocol: TCP\n  type: NodePort\n  selector:\n    app.kubernetes.io/name: app-2048\n---\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  namespace: game-2048\n  name: ingress-2048\n  annotations:\n    kubernetes.io/ingress.class: alb\n    alb.ingress.kubernetes.io/scheme: internet-facing\n    alb.ingress.kubernetes.io/target-type: instance\nspec:\n  rules:\n    - http:\n        paths:\n        - path: /\n          pathType: Prefix\n          backend:\n            service:\n              name: service-2048\n              port:\n                number: 80\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/aws-load-balancer-controller/iam-policy.json",
    "content": "{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"iam:CreateServiceLinkedRole\",\n                \"ec2:DescribeAccountAttributes\",\n                \"ec2:DescribeAddresses\",\n                \"ec2:DescribeAvailabilityZones\",\n                \"ec2:DescribeInternetGateways\",\n                \"ec2:DescribeVpcs\",\n                \"ec2:DescribeSubnets\",\n                \"ec2:DescribeSecurityGroups\",\n                \"ec2:DescribeInstances\",\n                \"ec2:DescribeNetworkInterfaces\",\n                \"ec2:DescribeTags\",\n                \"ec2:GetCoipPoolUsage\",\n                \"ec2:DescribeCoipPools\",\n                \"elasticloadbalancing:DescribeLoadBalancers\",\n                \"elasticloadbalancing:DescribeLoadBalancerAttributes\",\n                \"elasticloadbalancing:DescribeListeners\",\n                \"elasticloadbalancing:DescribeListenerCertificates\",\n                \"elasticloadbalancing:DescribeSSLPolicies\",\n                \"elasticloadbalancing:DescribeRules\",\n                \"elasticloadbalancing:DescribeTargetGroups\",\n                \"elasticloadbalancing:DescribeTargetGroupAttributes\",\n                \"elasticloadbalancing:DescribeTargetHealth\",\n                \"elasticloadbalancing:DescribeTags\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"cognito-idp:DescribeUserPoolClient\",\n                \"acm:ListCertificates\",\n                \"acm:DescribeCertificate\",\n                \"iam:ListServerCertificates\",\n                \"iam:GetServerCertificate\",\n                \"waf-regional:GetWebACL\",\n                \"waf-regional:GetWebACLForResource\",\n                \"waf-regional:AssociateWebACL\",\n                \"waf-regional:DisassociateWebACL\",\n                \"wafv2:GetWebACL\",\n                \"wafv2:GetWebACLForResource\",\n                \"wafv2:AssociateWebACL\",\n                \"wafv2:DisassociateWebACL\",\n                \"shield:GetSubscriptionState\",\n                \"shield:DescribeProtection\",\n                \"shield:CreateProtection\",\n                \"shield:DeleteProtection\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ec2:AuthorizeSecurityGroupIngress\",\n                \"ec2:RevokeSecurityGroupIngress\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ec2:CreateSecurityGroup\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ec2:CreateTags\"\n            ],\n            \"Resource\": \"arn:aws:ec2:*:*:security-group/*\",\n            \"Condition\": {\n                \"StringEquals\": {\n                    \"ec2:CreateAction\": \"CreateSecurityGroup\"\n                },\n                \"Null\": {\n                    \"aws:RequestTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ec2:CreateTags\",\n                \"ec2:DeleteTags\"\n            ],\n            \"Resource\": \"arn:aws:ec2:*:*:security-group/*\",\n            \"Condition\": {\n                \"Null\": {\n                    \"aws:RequestTag/elbv2.k8s.aws/cluster\": \"true\",\n                    \"aws:ResourceTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"ec2:AuthorizeSecurityGroupIngress\",\n                \"ec2:RevokeSecurityGroupIngress\",\n                \"ec2:DeleteSecurityGroup\"\n            ],\n            \"Resource\": \"*\",\n            \"Condition\": {\n                \"Null\": {\n                    \"aws:ResourceTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:CreateLoadBalancer\",\n                \"elasticloadbalancing:CreateTargetGroup\"\n            ],\n            \"Resource\": \"*\",\n            \"Condition\": {\n                \"Null\": {\n                    \"aws:RequestTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:CreateListener\",\n                \"elasticloadbalancing:DeleteListener\",\n                \"elasticloadbalancing:CreateRule\",\n                \"elasticloadbalancing:DeleteRule\"\n            ],\n            \"Resource\": \"*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:AddTags\",\n                \"elasticloadbalancing:RemoveTags\"\n            ],\n            \"Resource\": [\n                \"arn:aws:elasticloadbalancing:*:*:targetgroup/*/*\",\n                \"arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*\",\n                \"arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*\"\n            ],\n            \"Condition\": {\n                \"Null\": {\n                    \"aws:RequestTag/elbv2.k8s.aws/cluster\": \"true\",\n                    \"aws:ResourceTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:AddTags\",\n                \"elasticloadbalancing:RemoveTags\"\n            ],\n            \"Resource\": [\n                \"arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*\",\n                \"arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*\",\n                \"arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*\",\n                \"arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*\"\n            ]\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:ModifyLoadBalancerAttributes\",\n                \"elasticloadbalancing:SetIpAddressType\",\n                \"elasticloadbalancing:SetSecurityGroups\",\n                \"elasticloadbalancing:SetSubnets\",\n                \"elasticloadbalancing:DeleteLoadBalancer\",\n                \"elasticloadbalancing:ModifyTargetGroup\",\n                \"elasticloadbalancing:ModifyTargetGroupAttributes\",\n                \"elasticloadbalancing:DeleteTargetGroup\"\n            ],\n            \"Resource\": \"*\",\n            \"Condition\": {\n                \"Null\": {\n                    \"aws:ResourceTag/elbv2.k8s.aws/cluster\": \"false\"\n                }\n            }\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:RegisterTargets\",\n                \"elasticloadbalancing:DeregisterTargets\"\n            ],\n            \"Resource\": \"arn:aws:elasticloadbalancing:*:*:targetgroup/*/*\"\n        },\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"elasticloadbalancing:SetWebAcl\",\n                \"elasticloadbalancing:ModifyListener\",\n                \"elasticloadbalancing:AddListenerCertificates\",\n                \"elasticloadbalancing:RemoveListenerCertificates\",\n                \"elasticloadbalancing:ModifyRule\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/aws-load-balancer-controller/v2_2_1_full.yaml",
    "content": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: v0.5.0\n  creationTimestamp: null\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: ingressclassparams.elbv2.k8s.aws\nspec:\n  group: elbv2.k8s.aws\n  names:\n    kind: IngressClassParams\n    listKind: IngressClassParamsList\n    plural: ingressclassparams\n    singular: ingressclassparams\n  scope: Cluster\n  versions:\n  - additionalPrinterColumns:\n    - description: The Ingress Group name\n      jsonPath: .spec.group.name\n      name: GROUP-NAME\n      type: string\n    - description: The AWS Load Balancer scheme\n      jsonPath: .spec.scheme\n      name: SCHEME\n      type: string\n    - description: The AWS Load Balancer ipAddressType\n      jsonPath: .spec.ipAddressType\n      name: IP-ADDRESS-TYPE\n      type: string\n    - jsonPath: .metadata.creationTimestamp\n      name: AGE\n      type: date\n    name: v1beta1\n    schema:\n      openAPIV3Schema:\n        description: IngressClassParams is the Schema for the IngressClassParams API\n        properties:\n          apiVersion:\n            description: 'APIVersion defines the versioned schema of this representation\n              of an object. Servers should convert recognized schemas to the latest\n              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n            type: string\n          kind:\n            description: 'Kind is a string value representing the REST resource this\n              object represents. Servers may infer this from the endpoint the client\n              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n            type: string\n          metadata:\n            type: object\n          spec:\n            description: IngressClassParamsSpec defines the desired state of IngressClassParams\n            properties:\n              group:\n                description: Group defines the IngressGroup for all Ingresses that\n                  belong to IngressClass with this IngressClassParams.\n                properties:\n                  name:\n                    description: Name is the name of IngressGroup.\n                    type: string\n                required:\n                - name\n                type: object\n              ipAddressType:\n                description: IPAddressType defines the ip address type for all Ingresses\n                  that belong to IngressClass with this IngressClassParams.\n                enum:\n                - ipv4\n                - dualstack\n                type: string\n              namespaceSelector:\n                description: NamespaceSelector restrict the namespaces of Ingresses\n                  that are allowed to specify the IngressClass with this IngressClassParams.\n                  * if absent or present but empty, it selects all namespaces.\n                properties:\n                  matchExpressions:\n                    description: matchExpressions is a list of label selector requirements.\n                      The requirements are ANDed.\n                    items:\n                      description: A label selector requirement is a selector that\n                        contains values, a key, and an operator that relates the key\n                        and values.\n                      properties:\n                        key:\n                          description: key is the label key that the selector applies\n                            to.\n                          type: string\n                        operator:\n                          description: operator represents a key's relationship to\n                            a set of values. Valid operators are In, NotIn, Exists\n                            and DoesNotExist.\n                          type: string\n                        values:\n                          description: values is an array of string values. If the\n                            operator is In or NotIn, the values array must be non-empty.\n                            If the operator is Exists or DoesNotExist, the values\n                            array must be empty. This array is replaced during a strategic\n                            merge patch.\n                          items:\n                            type: string\n                          type: array\n                      required:\n                      - key\n                      - operator\n                      type: object\n                    type: array\n                  matchLabels:\n                    additionalProperties:\n                      type: string\n                    description: matchLabels is a map of {key,value} pairs. A single\n                      {key,value} in the matchLabels map is equivalent to an element\n                      of matchExpressions, whose key field is \"key\", the operator\n                      is \"In\", and the values array contains only \"value\". The requirements\n                      are ANDed.\n                    type: object\n                type: object\n              scheme:\n                description: Scheme defines the scheme for all Ingresses that belong\n                  to IngressClass with this IngressClassParams.\n                enum:\n                - internal\n                - internet-facing\n                type: string\n              tags:\n                description: Tags defines list of Tags on AWS resources provisioned\n                  for Ingresses that belong to IngressClass with this IngressClassParams.\n                items:\n                  description: Tag defines a AWS Tag on resources.\n                  properties:\n                    key:\n                      description: The key of the tag.\n                      type: string\n                    value:\n                      description: The value of the tag.\n                      type: string\n                  required:\n                  - key\n                  - value\n                  type: object\n                type: array\n            type: object\n        type: object\n    served: true\n    storage: true\n    subresources: {}\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n---\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  annotations:\n    controller-gen.kubebuilder.io/version: v0.5.0\n  creationTimestamp: null\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: targetgroupbindings.elbv2.k8s.aws\nspec:\n  group: elbv2.k8s.aws\n  names:\n    kind: TargetGroupBinding\n    listKind: TargetGroupBindingList\n    plural: targetgroupbindings\n    singular: targetgroupbinding\n  scope: Namespaced\n  versions:\n  - additionalPrinterColumns:\n    - description: The Kubernetes Service's name\n      jsonPath: .spec.serviceRef.name\n      name: SERVICE-NAME\n      type: string\n    - description: The Kubernetes Service's port\n      jsonPath: .spec.serviceRef.port\n      name: SERVICE-PORT\n      type: string\n    - description: The AWS TargetGroup's TargetType\n      jsonPath: .spec.targetType\n      name: TARGET-TYPE\n      type: string\n    - description: The AWS TargetGroup's Amazon Resource Name\n      jsonPath: .spec.targetGroupARN\n      name: ARN\n      priority: 1\n      type: string\n    - jsonPath: .metadata.creationTimestamp\n      name: AGE\n      type: date\n    name: v1alpha1\n    schema:\n      openAPIV3Schema:\n        description: TargetGroupBinding is the Schema for the TargetGroupBinding API\n        properties:\n          apiVersion:\n            description: 'APIVersion defines the versioned schema of this representation\n              of an object. Servers should convert recognized schemas to the latest\n              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n            type: string\n          kind:\n            description: 'Kind is a string value representing the REST resource this\n              object represents. Servers may infer this from the endpoint the client\n              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n            type: string\n          metadata:\n            type: object\n          spec:\n            description: TargetGroupBindingSpec defines the desired state of TargetGroupBinding\n            properties:\n              networking:\n                description: networking provides the networking setup for ELBV2 LoadBalancer\n                  to access targets in TargetGroup.\n                properties:\n                  ingress:\n                    description: List of ingress rules to allow ELBV2 LoadBalancer\n                      to access targets in TargetGroup.\n                    items:\n                      properties:\n                        from:\n                          description: List of peers which should be able to access\n                            the targets in TargetGroup. At least one NetworkingPeer\n                            should be specified.\n                          items:\n                            description: NetworkingPeer defines the source/destination\n                              peer for networking rules.\n                            properties:\n                              ipBlock:\n                                description: IPBlock defines an IPBlock peer. If specified,\n                                  none of the other fields can be set.\n                                properties:\n                                  cidr:\n                                    description: CIDR is the network CIDR. Both IPV4\n                                      or IPV6 CIDR are accepted.\n                                    type: string\n                                required:\n                                - cidr\n                                type: object\n                              securityGroup:\n                                description: SecurityGroup defines a SecurityGroup\n                                  peer. If specified, none of the other fields can\n                                  be set.\n                                properties:\n                                  groupID:\n                                    description: GroupID is the EC2 SecurityGroupID.\n                                    type: string\n                                required:\n                                - groupID\n                                type: object\n                            type: object\n                          type: array\n                        ports:\n                          description: List of ports which should be made accessible\n                            on the targets in TargetGroup. If ports is empty or unspecified,\n                            it defaults to all ports with TCP.\n                          items:\n                            properties:\n                              port:\n                                anyOf:\n                                - type: integer\n                                - type: string\n                                description: The port which traffic must match. When\n                                  NodePort endpoints(instance TargetType) is used,\n                                  this must be a numerical port. When Port endpoints(ip\n                                  TargetType) is used, this can be either numerical\n                                  or named port on pods. if port is unspecified, it\n                                  defaults to all ports.\n                                x-kubernetes-int-or-string: true\n                              protocol:\n                                description: The protocol which traffic must match.\n                                  If protocol is unspecified, it defaults to TCP.\n                                enum:\n                                - TCP\n                                - UDP\n                                type: string\n                            type: object\n                          type: array\n                      required:\n                      - from\n                      - ports\n                      type: object\n                    type: array\n                type: object\n              serviceRef:\n                description: serviceRef is a reference to a Kubernetes Service and\n                  ServicePort.\n                properties:\n                  name:\n                    description: Name is the name of the Service.\n                    type: string\n                  port:\n                    anyOf:\n                    - type: integer\n                    - type: string\n                    description: Port is the port of the ServicePort.\n                    x-kubernetes-int-or-string: true\n                required:\n                - name\n                - port\n                type: object\n              targetGroupARN:\n                description: targetGroupARN is the Amazon Resource Name (ARN) for\n                  the TargetGroup.\n                type: string\n              targetType:\n                description: targetType is the TargetType of TargetGroup. If unspecified,\n                  it will be automatically inferred.\n                enum:\n                - instance\n                - ip\n                type: string\n            required:\n            - serviceRef\n            - targetGroupARN\n            type: object\n          status:\n            description: TargetGroupBindingStatus defines the observed state of TargetGroupBinding\n            properties:\n              observedGeneration:\n                description: The generation observed by the TargetGroupBinding controller.\n                format: int64\n                type: integer\n            type: object\n        type: object\n    served: true\n    storage: false\n    subresources:\n      status: {}\n  - additionalPrinterColumns:\n    - description: The Kubernetes Service's name\n      jsonPath: .spec.serviceRef.name\n      name: SERVICE-NAME\n      type: string\n    - description: The Kubernetes Service's port\n      jsonPath: .spec.serviceRef.port\n      name: SERVICE-PORT\n      type: string\n    - description: The AWS TargetGroup's TargetType\n      jsonPath: .spec.targetType\n      name: TARGET-TYPE\n      type: string\n    - description: The AWS TargetGroup's Amazon Resource Name\n      jsonPath: .spec.targetGroupARN\n      name: ARN\n      priority: 1\n      type: string\n    - jsonPath: .metadata.creationTimestamp\n      name: AGE\n      type: date\n    name: v1beta1\n    schema:\n      openAPIV3Schema:\n        description: TargetGroupBinding is the Schema for the TargetGroupBinding API\n        properties:\n          apiVersion:\n            description: 'APIVersion defines the versioned schema of this representation\n              of an object. Servers should convert recognized schemas to the latest\n              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'\n            type: string\n          kind:\n            description: 'Kind is a string value representing the REST resource this\n              object represents. Servers may infer this from the endpoint the client\n              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'\n            type: string\n          metadata:\n            type: object\n          spec:\n            description: TargetGroupBindingSpec defines the desired state of TargetGroupBinding\n            properties:\n              networking:\n                description: networking defines the networking rules to allow ELBV2\n                  LoadBalancer to access targets in TargetGroup.\n                properties:\n                  ingress:\n                    description: List of ingress rules to allow ELBV2 LoadBalancer\n                      to access targets in TargetGroup.\n                    items:\n                      description: NetworkingIngressRule defines a particular set\n                        of traffic that is allowed to access TargetGroup's targets.\n                      properties:\n                        from:\n                          description: List of peers which should be able to access\n                            the targets in TargetGroup. At least one NetworkingPeer\n                            should be specified.\n                          items:\n                            description: NetworkingPeer defines the source/destination\n                              peer for networking rules.\n                            properties:\n                              ipBlock:\n                                description: IPBlock defines an IPBlock peer. If specified,\n                                  none of the other fields can be set.\n                                properties:\n                                  cidr:\n                                    description: CIDR is the network CIDR. Both IPV4\n                                      or IPV6 CIDR are accepted.\n                                    type: string\n                                required:\n                                - cidr\n                                type: object\n                              securityGroup:\n                                description: SecurityGroup defines a SecurityGroup\n                                  peer. If specified, none of the other fields can\n                                  be set.\n                                properties:\n                                  groupID:\n                                    description: GroupID is the EC2 SecurityGroupID.\n                                    type: string\n                                required:\n                                - groupID\n                                type: object\n                            type: object\n                          type: array\n                        ports:\n                          description: List of ports which should be made accessible\n                            on the targets in TargetGroup. If ports is empty or unspecified,\n                            it defaults to all ports with TCP.\n                          items:\n                            description: NetworkingPort defines the port and protocol\n                              for networking rules.\n                            properties:\n                              port:\n                                anyOf:\n                                - type: integer\n                                - type: string\n                                description: The port which traffic must match. When\n                                  NodePort endpoints(instance TargetType) is used,\n                                  this must be a numerical port. When Port endpoints(ip\n                                  TargetType) is used, this can be either numerical\n                                  or named port on pods. if port is unspecified, it\n                                  defaults to all ports.\n                                x-kubernetes-int-or-string: true\n                              protocol:\n                                description: The protocol which traffic must match.\n                                  If protocol is unspecified, it defaults to TCP.\n                                enum:\n                                - TCP\n                                - UDP\n                                type: string\n                            type: object\n                          type: array\n                      required:\n                      - from\n                      - ports\n                      type: object\n                    type: array\n                type: object\n              nodeSelector:\n                description: node selector for instance type target groups to only\n                  register certain nodes\n                properties:\n                  matchExpressions:\n                    description: matchExpressions is a list of label selector requirements.\n                      The requirements are ANDed.\n                    items:\n                      description: A label selector requirement is a selector that\n                        contains values, a key, and an operator that relates the key\n                        and values.\n                      properties:\n                        key:\n                          description: key is the label key that the selector applies\n                            to.\n                          type: string\n                        operator:\n                          description: operator represents a key's relationship to\n                            a set of values. Valid operators are In, NotIn, Exists\n                            and DoesNotExist.\n                          type: string\n                        values:\n                          description: values is an array of string values. If the\n                            operator is In or NotIn, the values array must be non-empty.\n                            If the operator is Exists or DoesNotExist, the values\n                            array must be empty. This array is replaced during a strategic\n                            merge patch.\n                          items:\n                            type: string\n                          type: array\n                      required:\n                      - key\n                      - operator\n                      type: object\n                    type: array\n                  matchLabels:\n                    additionalProperties:\n                      type: string\n                    description: matchLabels is a map of {key,value} pairs. A single\n                      {key,value} in the matchLabels map is equivalent to an element\n                      of matchExpressions, whose key field is \"key\", the operator\n                      is \"In\", and the values array contains only \"value\". The requirements\n                      are ANDed.\n                    type: object\n                type: object\n              serviceRef:\n                description: serviceRef is a reference to a Kubernetes Service and\n                  ServicePort.\n                properties:\n                  name:\n                    description: Name is the name of the Service.\n                    type: string\n                  port:\n                    anyOf:\n                    - type: integer\n                    - type: string\n                    description: Port is the port of the ServicePort.\n                    x-kubernetes-int-or-string: true\n                required:\n                - name\n                - port\n                type: object\n              targetGroupARN:\n                description: targetGroupARN is the Amazon Resource Name (ARN) for\n                  the TargetGroup.\n                minLength: 1\n                type: string\n              targetType:\n                description: targetType is the TargetType of TargetGroup. If unspecified,\n                  it will be automatically inferred.\n                enum:\n                - instance\n                - ip\n                type: string\n            required:\n            - serviceRef\n            - targetGroupARN\n            type: object\n          status:\n            description: TargetGroupBindingStatus defines the observed state of TargetGroupBinding\n            properties:\n              observedGeneration:\n                description: The generation observed by the TargetGroupBinding controller.\n                format: int64\n                type: integer\n            type: object\n        type: object\n    served: true\n    storage: true\n    subresources:\n      status: {}\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: []\n  storedVersions: []\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-controller-leader-election-role\n  namespace: kube-system\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - configmaps\n  verbs:\n  - create\n- apiGroups:\n  - \"\"\n  resourceNames:\n  - aws-load-balancer-controller-leader\n  resources:\n  - configmaps\n  verbs:\n  - get\n  - update\n  - patch\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  creationTimestamp: null\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-controller-role\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - endpoints\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - events\n  verbs:\n  - create\n  - patch\n- apiGroups:\n  - \"\"\n  resources:\n  - namespaces\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - nodes\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - pods\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - pods/status\n  verbs:\n  - patch\n  - update\n- apiGroups:\n  - \"\"\n  resources:\n  - secrets\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - services\n  verbs:\n  - get\n  - list\n  - patch\n  - update\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - services/status\n  verbs:\n  - patch\n  - update\n- apiGroups:\n  - elbv2.k8s.aws\n  resources:\n  - ingressclassparams\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - elbv2.k8s.aws\n  resources:\n  - targetgroupbindings\n  verbs:\n  - create\n  - delete\n  - get\n  - list\n  - patch\n  - update\n  - watch\n- apiGroups:\n  - elbv2.k8s.aws\n  resources:\n  - targetgroupbindings/status\n  verbs:\n  - patch\n  - update\n- apiGroups:\n  - extensions\n  resources:\n  - ingresses\n  verbs:\n  - get\n  - list\n  - patch\n  - update\n  - watch\n- apiGroups:\n  - extensions\n  resources:\n  - ingresses/status\n  verbs:\n  - patch\n  - update\n- apiGroups:\n  - networking.k8s.io\n  resources:\n  - ingressclasses\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - networking.k8s.io\n  resources:\n  - ingresses\n  verbs:\n  - get\n  - list\n  - patch\n  - update\n  - watch\n- apiGroups:\n  - networking.k8s.io\n  resources:\n  - ingresses/status\n  verbs:\n  - patch\n  - update\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-controller-leader-election-rolebinding\n  namespace: kube-system\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: aws-load-balancer-controller-leader-election-role\nsubjects:\n- kind: ServiceAccount\n  name: aws-load-balancer-controller\n  namespace: kube-system\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-controller-rolebinding\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: aws-load-balancer-controller-role\nsubjects:\n- kind: ServiceAccount\n  name: aws-load-balancer-controller\n  namespace: kube-system\n---\napiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-webhook-service\n  namespace: kube-system\nspec:\n  ports:\n  - port: 443\n    targetPort: 9443\n  selector:\n    app.kubernetes.io/component: controller\n    app.kubernetes.io/name: aws-load-balancer-controller\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    app.kubernetes.io/component: controller\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-controller\n  namespace: kube-system\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app.kubernetes.io/component: controller\n      app.kubernetes.io/name: aws-load-balancer-controller\n  template:\n    metadata:\n      labels:\n        app.kubernetes.io/component: controller\n        app.kubernetes.io/name: aws-load-balancer-controller\n    spec:\n      containers:\n      - args:\n        - --cluster-name=eksworkshop\n        - --ingress-class=alb\n        image: amazon/aws-alb-ingress-controller:v2.2.1\n        livenessProbe:\n          failureThreshold: 2\n          httpGet:\n            path: /healthz\n            port: 61779\n            scheme: HTTP\n          initialDelaySeconds: 30\n          timeoutSeconds: 10\n        name: controller\n        ports:\n        - containerPort: 9443\n          name: webhook-server\n          protocol: TCP\n        resources:\n          limits:\n            cpu: 200m\n            memory: 500Mi\n          requests:\n            cpu: 100m\n            memory: 200Mi\n        securityContext:\n          allowPrivilegeEscalation: false\n          readOnlyRootFilesystem: true\n          runAsNonRoot: true\n        volumeMounts:\n        - mountPath: /tmp/k8s-webhook-server/serving-certs\n          name: cert\n          readOnly: true\n      priorityClassName: system-cluster-critical\n      securityContext:\n        fsGroup: 1337\n      serviceAccountName: aws-load-balancer-controller\n      terminationGracePeriodSeconds: 10\n      volumes:\n      - name: cert\n        secret:\n          defaultMode: 420\n          secretName: aws-load-balancer-webhook-tls\n---\napiVersion: cert-manager.io/v1alpha2\nkind: Certificate\nmetadata:\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-serving-cert\n  namespace: kube-system\nspec:\n  dnsNames:\n  - aws-load-balancer-webhook-service.kube-system.svc\n  - aws-load-balancer-webhook-service.kube-system.svc.cluster.local\n  issuerRef:\n    kind: Issuer\n    name: aws-load-balancer-selfsigned-issuer\n  secretName: aws-load-balancer-webhook-tls\n---\napiVersion: cert-manager.io/v1alpha2\nkind: Issuer\nmetadata:\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-selfsigned-issuer\n  namespace: kube-system\nspec:\n  selfSigned: {}\n---\napiVersion: admissionregistration.k8s.io/v1\nkind: MutatingWebhookConfiguration\nmetadata:\n  annotations:\n    cert-manager.io/inject-ca-from: kube-system/aws-load-balancer-serving-cert\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-webhook\nwebhooks:\n- admissionReviewVersions:\n  - v1beta1\n  clientConfig:\n    service:\n      name: aws-load-balancer-webhook-service\n      namespace: kube-system\n      path: /mutate-v1-pod\n  failurePolicy: Fail\n  name: mpod.elbv2.k8s.aws\n  namespaceSelector:\n    matchExpressions:\n    - key: elbv2.k8s.aws/pod-readiness-gate-inject\n      operator: In\n      values:\n      - enabled\n  objectSelector:\n    matchExpressions:\n    - key: app.kubernetes.io/name\n      operator: NotIn\n      values:\n      - aws-load-balancer-controller\n  rules:\n  - apiGroups:\n    - \"\"\n    apiVersions:\n    - v1\n    operations:\n    - CREATE\n    resources:\n    - pods\n  sideEffects: None\n- admissionReviewVersions:\n  - v1beta1\n  clientConfig:\n    service:\n      name: aws-load-balancer-webhook-service\n      namespace: kube-system\n      path: /mutate-elbv2-k8s-aws-v1beta1-targetgroupbinding\n  failurePolicy: Fail\n  name: mtargetgroupbinding.elbv2.k8s.aws\n  rules:\n  - apiGroups:\n    - elbv2.k8s.aws\n    apiVersions:\n    - v1beta1\n    operations:\n    - CREATE\n    - UPDATE\n    resources:\n    - targetgroupbindings\n  sideEffects: None\n---\napiVersion: admissionregistration.k8s.io/v1\nkind: ValidatingWebhookConfiguration\nmetadata:\n  annotations:\n    cert-manager.io/inject-ca-from: kube-system/aws-load-balancer-serving-cert\n  labels:\n    app.kubernetes.io/name: aws-load-balancer-controller\n  name: aws-load-balancer-webhook\nwebhooks:\n- admissionReviewVersions:\n  - v1beta1\n  clientConfig:\n    service:\n      name: aws-load-balancer-webhook-service\n      namespace: kube-system\n      path: /validate-elbv2-k8s-aws-v1beta1-targetgroupbinding\n  failurePolicy: Fail\n  name: vtargetgroupbinding.elbv2.k8s.aws\n  rules:\n  - apiGroups:\n    - elbv2.k8s.aws\n    apiVersions:\n    - v1beta1\n    operations:\n    - CREATE\n    - UPDATE\n    resources:\n    - targetgroupbindings\n  sideEffects: None\n- admissionReviewVersions:\n  - v1beta1\n  clientConfig:\n    service:\n      name: aws-load-balancer-webhook-service\n      namespace: kube-system\n      path: /validate-networking-v1beta1-ingress\n  failurePolicy: Fail\n  matchPolicy: Equivalent\n  name: vingress.elbv2.k8s.aws\n  rules:\n  - apiGroups:\n    - networking.k8s.io\n    apiVersions:\n    - v1beta1\n    operations:\n    - CREATE\n    - UPDATE\n    resources:\n    - ingresses\n  sideEffects: None\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/codepipeline/aws-auth-patch.yml",
    "content": "apiVersion: v1\ndata:\n  mapRoles: |\n    - rolearn: arn:aws:iam::596030579944:role/EksWorkshopCodeBuildKubectlRole\n      username: build\n      groups:\n        - system:masters\n    - groups:\n      - system:bootstrappers\n      - system:nodes\n      rolearn: arn:aws:iam::596030579944:role/eksctl-eksworkshop-nodegroup-ng-d-NodeInstanceRole-1751CIO1JW5MD\n      username: system:node:{{EC2PrivateDNSName}}\nkind: ConfigMap\nmetadata:\n  creationTimestamp: \"2021-08-27T11:38:47Z\"\n  name: aws-auth\n  namespace: kube-system\n  resourceVersion: \"1417\"\n  uid: b88a5d87-2be5-450d-9a0a-130280275f66\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/codepipeline/iam-role-policy",
    "content": "{ \"Version\": \"2012-10-17\", \"Statement\": [ { \"Effect\": \"Allow\", \"Action\": \"eks:Describe*\", \"Resource\": \"*\" } ] }\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/nginx.yaml",
    "content": "---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - containerPort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: \"service-nginx\"\n  annotations:\n        service.beta.kubernetes.io/aws-load-balancer-type: nlb\nspec:\n  selector:\n    app: nginx\n  type: LoadBalancer\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/observeration/elastisearch.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  labels:\n    product: k8s-elastic\n  name: elastic-config\ndata:\n  elasticsearch.yaml: |\n    discovery.type: single-node\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: elasticsearch\nspec:\n  selector:\n    matchLabels:\n      run: elasticsearch\n  template:\n    metadata:\n      labels:\n        name: elasticsearch\n        run: elasticsearch\n    spec:\n      initContainers:\n      - name: set-vm-sync-limit\n        image: busybox\n        imagePullPolicy: IfNotPresent\n        command: [\"sysctl\", \"-w\", \"vm.max_map_count=262144\"]\n        securityContext:\n          privileged: true\n      containers:\n      - image: docker.elastic.co/elasticsearch/elasticsearch:6.6.1\n        name: elasticsearch\n        imagePullPolicy: IfNotPresent\n        ports:\n        - containerPort: 9200\n          protocol: TCP\n        volumeMounts:\n          - name: elastic-config\n            mountPath: /etc/elasticsearch/elasticsearch.yaml\n            subPath: elasticsearch.yaml\n      volumes:\n      - name: elastic-config\n        configMap:\n          name: elastic-config\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: elasticsearch\n  labels:\n    run: elasticsearch\nspec:\n  ports:\n    - port: 9200\n      targetPort: 9200\n      protocol: TCP\n  selector:\n    run: elasticsearch\n  type: ClusterIP"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/observeration/fluent-bit.yaml",
    "content": "---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: fluent-bit\n  namespace: default\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: fluent-bit-read\nrules:\n- apiGroups: [\"\"]\n  resources:\n  - namespaces\n  - pods\n  verbs: [\"get\", \"list\", \"watch\"]\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: fluent-bit-read\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: fluent-bit-read\nsubjects:\n- kind: ServiceAccount\n  name: fluent-bitg\n  namespace: default\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: fluent-bit-config\n  labels:\n    k8s-app: fluent-bit\ndata:\n  # Configuration files: server, input, filters and output\n  # ======================================================\n  fluent-bit.conf: |\n    [SERVICE]\n        Flush         1\n        Log_Level     info\n        Daemon        off\n        Parsers_File  parsers.conf\n        HTTP_Server   On\n        HTTP_Listen   0.0.0.0\n        HTTP_Port     2020\n\n    @INCLUDE input-kubernetes.conf\n    @INCLUDE filter-kubernetes.conf\n    @INCLUDE output-elasticsearch.conf\n\n  input-kubernetes.conf: |\n    [INPUT]\n        Name              tail\n        Tag               kube.*\n        Path              /var/log/containers/*.log\n        Parser            docker\n        DB                /var/log/flb_kube.db\n        Mem_Buf_Limit     50MB\n        Skip_Long_Lines   On\n        Refresh_Interval  10\n\n  filter-kubernetes.conf: |\n    [FILTER]\n        Name                kubernetes\n        Match               kube.*\n        Kube_URL            https://kubernetes.default.svc:443\n        Kube_CA_File        /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n        Kube_Token_File     /var/run/secrets/kubernetes.io/serviceaccount/token\n        Kube_Tag_Prefix     kube.var.log.containers.\n        Merge_Log           On\n        Merge_Log_Key       log_processed\n        K8S-Logging.Parser  On\n        K8S-Logging.Exclude Off\n\n  output-elasticsearch.conf: |\n    [OUTPUT]\n        Name            es\n        Match           *\n        Host            elasticsearch.default.svc.cluster.local\n        Port            9200\n        Retry_Limit     6\n\n  parsers.conf: |\n    [PARSER]\n        Name   apache\n        Format regex\n        Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \\[(?<time>[^\\]]*)\\] \"(?<method>\\S+)(?: +(?<path>[^\\\"]*?)(?: +\\S*)?)?\" (?<code>[^ ]*) (?<size>[^ ]*)(?: \"(?<referer>[^\\\"]*)\" \"(?<agent>[^\\\"]*)\")?$\n        Time_Key time\n        Time_Format %d/%b/%Y:%H:%M:%S %z\n\n    [PARSER]\n        Name   apache2\n        Format regex\n        Regex  ^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \\[(?<time>[^\\]]*)\\] \"(?<method>\\S+)(?: +(?<path>[^ ]*) +\\S*)?\" (?<code>[^ ]*) (?<size>[^ ]*)(?: \"(?<referer>[^\\\"]*)\" \"(?<agent>[^\\\"]*)\")?$\n        Time_Key time\n        Time_Format %d/%b/%Y:%H:%M:%S %z\n\n    [PARSER]\n        Name   apache_error\n        Format regex\n        Regex  ^\\[[^ ]* (?<time>[^\\]]*)\\] \\[(?<level>[^\\]]*)\\](?: \\[pid (?<pid>[^\\]]*)\\])?( \\[client (?<client>[^\\]]*)\\])? (?<message>.*)$\n\n    [PARSER]\n        Name   nginx\n        Format regex\n        Regex ^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \\[(?<time>[^\\]]*)\\] \"(?<method>\\S+)(?: +(?<path>[^\\\"]*?)(?: +\\S*)?)?\" (?<code>[^ ]*) (?<size>[^ ]*)(?: \"(?<referer>[^\\\"]*)\" \"(?<agent>[^\\\"]*)\")?$\n        Time_Key time\n        Time_Format %d/%b/%Y:%H:%M:%S %z\n\n    [PARSER]\n        Name   json\n        Format json\n        Time_Key time\n        Time_Format %d/%b/%Y:%H:%M:%S %z\n\n    [PARSER]\n        Name        docker\n        Format      json\n        Time_Key    time\n        Time_Format %Y-%m-%dT%H:%M:%S.%L\n        Time_Keep   On\n\n    [PARSER]\n        Name        syslog\n        Format      regex\n        Regex       ^\\<(?<pri>[0-9]+)\\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\\/\\.\\-]*)(?:\\[(?<pid>[0-9]+)\\])?(?:[^\\:]*\\:)? *(?<message>.*)$\n        Time_Key    time\n        Time_Format %b %d %H:%M:%S\n---\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: fluent-bit\n  labels:\n    k8s-app: fluent-bit-logging\n    version: v1\n    kubernetes.io/cluster-service: \"true\"\n\nspec:\n  selector:\n    matchLabels:\n      k8s-app: fluent-bit-logging\n  template:\n    metadata:\n      labels:\n        k8s-app: fluent-bit-logging\n        version: v1\n        kubernetes.io/cluster-service: \"true\"\n      annotations:\n        prometheus.io/scrape: \"true\"\n        prometheus.io/port: \"2020\"\n        prometheus.io/path: /api/v1/metrics/prometheus\n    spec:\n      containers:\n      - name: fluent-bit\n        image: amazon/aws-for-fluent-bit:2.5.0\n        imagePullPolicy: Always\n        ports:\n          - containerPort: 2020\n        volumeMounts:\n        - name: varlog\n          mountPath: /var/log\n        - name: varlibdockercontainers\n          mountPath: /var/lib/docker/containers\n          readOnly: true\n        - name: fluent-bit-config\n          mountPath: /fluent-bit/etc/\n      terminationGracePeriodSeconds: 10\n      volumes:\n      - name: varlog\n        hostPath:\n          path: /var/log\n      - name: varlibdockercontainers\n        hostPath:\n          path: /var/lib/docker/containers\n      - name: fluent-bit-config\n        configMap:\n          name: fluent-bit-config\n      serviceAccountName: fluent-bit\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/observeration/grafana.yaml",
    "content": "datasources:\n  datasources.yaml:\n    apiVersion: 1\n    datasources:\n    - name: Prometheus\n      type: prometheus\n      url: http://prometheus-server.prometheus.svc.cluster.local\n      access: proxy\n      isDefault: true\n"
  },
  {
    "path": "global/2021_GCR_MAD_Day/resources/observeration/kibana.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: kibana-deployment\n  labels:\n    app: kibana\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: kibana\n  template:\n    metadata:\n      labels:\n        app: kibana\n    spec:\n      containers:\n      - name: kibana\n        image: docker.elastic.co/kibana/kibana:6.6.1\n        ports:\n        - containerPort: 5601\n          name: webinterface\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: kibana\n  labels:\n    service: kibana\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 5601\n    targetPort: 5601\n    protocol: TCP\n    name: webinterface\n  selector:\n    app: kibana"
  },
  {
    "path": "global/2021_GCR_MAD_Day/通过AWS Cloud9搭建实验环境.md",
    "content": "# 进入实验环境\n\n\n## 步骤1: 通过AWS Cloud9搭建服务器环境\nAWS Cloud9 为您提供了EC2基础设施资源并且一个可视化的编辑器。在本次实验中，您将通过Cloud9去创建一台具有公网访问权限的EC2 实例，运行后续的实验。\n\n1.1 通过浏览器进入 https://dashboard.eventengine.run/ ,填入12位hash code,然后选择 Email One-Time Password 输入邮件接收临时密码\n\n\n\n<img src=\"media/image-20210903140529220.png\" alt=\"image-20210903140529220\" style=\"zoom:50%;\" />\n\n<img src=\"media/image-20210903140615953.png\" alt=\"image-20210903140615953\" style=\"zoom:50%;\" />\n\n<img src=\"media/image-20200729204214972.png\" alt=\"image-20200729204214972\" style=\"zoom:33%;\" />\n\n\n\n输入邮箱接收一次性登陆验证码\n\n通过点击AWS Console , Open AWS Console 进入aws 控制台\n\n![image-20200729204258710](media/image-20200729204258710.png)\n\n1.2 打开AWS管理控制台，在Service菜单栏中输入关键字Cloud9，进入Cloud9 管理页面\n![](media/15764751257913/15764752078709.jpg?raw=true\")\n\n\n\n1.3 点击Create environment,在Environment name and Description内输入 环境的名称 [username]_cloud9，点击 Next Step。\n![image-20210826095552848](media/image-20210826095552848.png)\n\n1.4 修改实例为t3.small , 其它使用的默认配置，本次实验不需要改动任何实例环境和网路环境， 点击 Next step\n\n\n   ![image-20210826095650485](media/image-20210826095650485.png)\n\n\n\n1.5 进入Review界面后，确认无误，点击Create Environment完成创建。\n\n![image-20210826095955572](media/image-20210826095955572.png)\n\n此后界面会跳转到 Cloud9 的编辑器页面\n\n![image-20210826100148221](media/image-20210826100148221.png)\n\n\n\n**(可选)样式设置**: 默认是深色,可以修改为白色\n\n![image-20200729211802528](media/image-20200729211802528.png)\n\n1.6\tCloud9 通常使用动态生成 IAM 的认证授权信息，但目前和 EKS IAM Authentication 不兼容，因此我们直接给 Cloud 9 EC2 实例附加一个管理员权限的 IAM 角色，并禁止掉 Cloud9 默认的动态 IAM认证授权信息：\n\n* 1）\t创建 IAM 角色\n\n> (1)请新开一个页面,进入[https://console.aws.amazon.com/iam/home#/roles](https://console.aws.amazon.com/iam/home#/roles),选择创建角色 第一步选择 AWS service 并选择 EC2,点击下一步\n\n![](media/15764751257913/15764753509904.png)\n\n> (2)权限中选择 AdministratorAccess,点击下一步\n\n![](media/15764751257913/15764753504307.png)\n\n> (3)输入角色名字 eksworkshop-admin,点击创建角色\n\n![](media/15764751257913/15764753507358.png)\n\n* 2）\t在EC2 Instances界面选择cloud9的EC2实例(名字为aws-cloud9-xxxxx),点击Actions/Instance Settings/Attach/Replace IAM Role,为该实例设置正确的角色\n\n  ![](media/15764751257913/1576503061.png)\n  \n>   选择eksworkshop-admin 角色,点击Apply完成\n\n![](media/15764751257913/15764754031465.png)\n\n* 3）\t关闭cloud9临时权限，并验证角色是否生效\n\n>点击AWS Cloud9图标 -> Preferences - >AWS Settings ->关闭临时权限\n\n* ![](media/15764751257913/15765030614319.png)\n\n输入:\n\n```bash\n#设置默认region\nexport AWS_DEFAULT_REGION=us-east-1\necho \"export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}\" >> ~/.bashrc\n\n\n#测试角色是否生效\naws sts get-caller-identity\n```\n如果可以正常返回以下内容(包含eksworkshop-admin),则表示已经正确设置角色权限\n```json\n#例子:\n{\n    \"Account\": \"012345678911\", \n    \"UserId\": \"AROAYVRRQ4TUEIX4VRZLN:i-0e011f5bb16f38173\", \n    \"Arn\": \"arn:aws:sts::012345678911:assumed-role/eksworkshop-admin/i-0e011f5bb16f38173\"\n}\n```\n\n\n\n"
  },
  {
    "path": "global/karpenter_handson/使用Karpenter实现EKS工作节点弹性伸缩.md",
    "content": "## AWS EKS集群使用Karpenter实现EC2工作节点弹性伸缩 \n\n [Karpenter](https://github.com/aws/karpenter) 是AWS开源的kubernetes 工作节点弹性管理工具，它的目标是提高Kubernetes工作节点的灵活性、伸缩性以及降低成本.  \n\nKarpenter 可以:\n\n* 监控所有被Kubernetes scheduler标记为unschedulable的pods\n* 评估Pod请求的调度请求: 资源请求(GPU/GPU),节点选择器, 亲和性, 容忍度, 拓扑\n* 配置满足 Pod 要求的节点\n* 调度Pods到新节点运行\n* 移除空闲或者不在需要的节点\n\n​      以AWS EKS服务为例，Karpenter 和Cluster AutoScaler 工作原理最大的区别: Cluster AutoScaler 是按照AutoScaling Group(弹性伸缩组)进行管理，通过调整Desired参数来实现节点的伸缩功能,CA并不会去计算、评估Pods的需求进行不同实例的扩展.\n\n   Cluster AutoScaler 工作原理：\n\n![image-20211217165913880](./media/image-20211217165913880.png)\n\n\n\nKarpenter 不使用AutoScaling Group,而是通过对Pods请求的评估直接调用EC2.*CreateFleet()*  API 就可以扩展出所需的实例\n\nKarpenter 工作原理:     \n\n![image-20211217170000431](./media/image-20211217170000431.png)\n\n![img](./media/2021-karpenter-diagram.png)\n\n用例: 如果当前CA管理的都是x86 AutoScaling Group ,当有一个deployment 申请arm资源后, CA不能创建出ARM节点. 而Karpenter 对Pods请求的评估后调用EC2.*CreateFleet()*  API 就可以扩展出所需的ARM实例类型.\n\n\n\n### 创建集群\n\n创建AWS EKS集群,初始化2个m5.large工作节点. 如果已经创建了集群可以忽略本小节\n\n```bash\nexport CLUSTER_NAME=eksworkshop\nexport AWS_DEFAULT_REGION=us-west-2\nAWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)\n\ncat <<EOF > cluster.yaml\n---\napiVersion: eksctl.io/v1alpha5\nkind: ClusterConfig\nmetadata:\n  name: ${CLUSTER_NAME}\n  region: ${AWS_DEFAULT_REGION}\n  version: \"1.21\"\nmanagedNodeGroups:\n  - instanceType: m5.large\n    amiFamily: AmazonLinux2\n    name: ${CLUSTER_NAME}-ng\n    desiredCapacity: 2\n    minSize: 1\n    maxSize: 10\niam:\n  withOIDC: true\nEOF\neksctl create cluster -f cluster.yaml\n```\n\n\n\n ### 1 . 准备工作\n\n 1.1 给VPC子网打Tag\n\nKarpenter 会自动发现含有 `kubernetes.io/cluster/$CLUSTER_NAME`标记的VPC 子网.  下面将使用AWS CLI工具对EKS集群使用的VPC子网打上对应的Tag.\n\n  ```bash\n  SUBNET_IDS=$(aws cloudformation describe-stacks \\\n      --stack-name eksctl-${CLUSTER_NAME}-cluster \\\n      --query 'Stacks[].Outputs[?OutputKey==`SubnetsPrivate`].OutputValue' \\\n      --output text)\n  aws ec2 create-tags \\\n      --resources $(echo $SUBNET_IDS | tr ',' '\\n') \\\n      --tags Key=\"kubernetes.io/cluster/${CLUSTER_NAME}\",Value=\n  ```\n\n  1.2 创建KarpenterNode IAM 角色\n\n   Karpenter 启动的实例必须使用 InstanceProfile 运行，该Profile授予运行容器和配置网络所需的权限。 Karpenter 会自动发现并使用`KarpenterNodeRole-${ClusterName}`的 InstanceProfile. \n\n  首先使用CloudFormation创建IAM资源.\n\n   ```bash\n   TEMPOUT=$(mktemp)\n   curl -fsSL https://karpenter.sh/docs/getting-started/cloudformation.yaml > $TEMPOUT \\\n   && aws cloudformation deploy \\\n     --stack-name Karpenter-${CLUSTER_NAME} \\\n     --template-file ${TEMPOUT} \\\n     --capabilities CAPABILITY_NAMED_IAM \\\n     --parameter-overrides ClusterName=${CLUSTER_NAME}\n   ```\n\n​    其次使用以下命令将Karpenter节点role 添加到kubernetes configmap: aws-auth ,授予Profile连接EKS集群的权限.\n\n```bash\neksctl create iamidentitymapping \\\n  --username system:node:{{EC2PrivateDNSName}} \\\n  --cluster  ${CLUSTER_NAME} \\\n  --arn arn:aws:iam::${AWS_ACCOUNT_ID}:role/KarpenterNodeRole-${CLUSTER_NAME} \\\n  --group system:bootstrappers \\\n  --group system:nodes\n```\n\n1.3 为karpenterController创建serviceaccount并关联对应的IAM Role\n\nKarpenter需要特定的权限，比如EC2创建权限. 以下命令会创建对应的 AWS IAM Role, Kubernetes service account, 并且通过AWS [IRSA](https://docs.aws.amazon.com/emr/latest/EMR-on-EKS-DevelopmentGuide/setting-up-enable-IAM.html) 功能将role和IAM Role关联在一起.\n\n```\neksctl create iamserviceaccount \\\n  --cluster $CLUSTER_NAME --name karpenter --namespace karpenter \\\n  --attach-policy-arn arn:aws:iam::$AWS_ACCOUNT_ID:policy/KarpenterControllerPolicy-$CLUSTER_NAME \\\n  --approve\n```\n\n\n\n### 2  使用Helm 安装Karpenter charts\n\n2.1  使用helm 部署Karpentercharts\n\n​    首先添加并更新karpenter的helm仓库,  使用正确的参数安装Karpenter，这里请注意我们使用eksctl创建的service account.\n\n```bash\nhelm repo add karpenter https://charts.karpenter.sh\nhelm repo update\nhelm upgrade --install karpenter karpenter/karpenter --namespace karpenter \\\n  --create-namespace --set serviceAccount.create=false --version 0.5.2 \\\n  --set controller.clusterName=${CLUSTER_NAME} \\\n  --set controller.clusterEndpoint=$(aws eks describe-cluster --name ${CLUSTER_NAME} --query \"cluster.endpoint\" --output json) \\\n  --wait # for the defaulting webhook to install before creating a Provisioner\n```\n\n启用调试日志 (可选)\n\n```sh\nkubectl patch configmap config-logging -n karpenter --patch '{\"data\":{\"loglevel.controller\":\"debug\"}}'\n```\n\n2.2 设置Provisioner\n\n单个 Karpenter provisioner 可以处理许多不同的pod 资源请求. Karpenter 根据标签和关联性等pod属性做出调度和配置. Karpenter 消除了管理许多不同节点组的需求.\n\n使用以下命令创建默认的provisioner. 使用`ttlSecondsAfterEmpty` 参数可以配置节点空闲时间,TTL达到之后Karpenter会终止该工作节点. 可以将该参数设置为-1或者undefined来禁止终止行为.\n\n可以访问[provisioner CRD](https://karpenter.sh/docs/provisioner/) 得到更多的provisioner 配置信息. 例如, `ttlSecondsUntilExpired` 可以设置Karpenter 在过期时间到达后终止该节点.\n\n```bash\ncat <<EOF | kubectl apply -f -\napiVersion: karpenter.sh/v1alpha5\nkind: Provisioner\nmetadata:\n  name: default\nspec:\n  requirements:\n    - key: karpenter.sh/capacity-type\n      operator: In\n      values: [\"spot\"]\n    - key: node.kubernetes.io/instance-type\n      operator: In\n      values: [\"m5.xlarge\", \"m5.2xlarge\",\"m5.4xlarge\",\"m5.12xlarge\",\"c5.xlarge\",\"c5.2xlarge\",\"c5.4xlarge\",\"c5.12xlarge\"]\n  limits:\n    resources:\n      cpu: 1000\n  provider:\n    instanceProfile: KarpenterNodeInstanceProfile-${CLUSTER_NAME}\n  ttlSecondsAfterEmpty: 30\nEOF\n```\n\n\n\n## 3 测试\n\n3.1 部署测试应用,默认副本数为0\n\n```bash\ncat <<EOF | kubectl apply -f -\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: inflate\nspec:\n  replicas: 0\n  selector:\n    matchLabels:\n      app: inflate\n  template:\n    metadata:\n      labels:\n        app: inflate\n      annotations:\n        appmesh.k8s.aws/sidecarInjectorWebhook: disabled\n    spec:\n      terminationGracePeriodSeconds: 0\n      containers:\n        - name: inflate\n          image: public.ecr.aws/eks-distro/kubernetes/pause:3.2\n          resources:\n            requests:\n              cpu: 1\nEOF\n```\n\n3.2 开启多个终端窗口使用watch进行观察节点和pod\n\n```bash\nwatch -t -n 1 kubectl get node -Lnode.kubernetes.io/instance-type -Ltopology.kubernetes.io/zone -Lkubernetes.io/arch\n\n```\n\n```bash\n\nwatch -t -n 1 kubectl get pod\n```\n\n\n\n3.3 伸缩测试\n\n> 通过kubectl scale 增加inflate副本数量,触发karpenter,并观察karpenter controller日志和kubectl node\n\n```bash\nkubectl scale deployment inflate --replicas 1\n```\n\n![image-20211217153045284](./media/image-20211217153045284.png)\n\n![image-20211217153123001](./media/image-20211217153123001.png)\n\n> 将副本增加到10\n\n ```bash\n kubectl scale deployment inflate --replicas 10\n ```\n\n![image-20211217153606747](./media/image-20211217153606747.png)\n\nKarpenter 会计算unschedulable的Pods然后扩展EC2，这里看见拉起的就是c5.2xlarge\n\n![image-20211217153812098](./media/image-20211217153812098.png)\n\n> 收缩测试，当节点空闲时Karpenter controller向该节点发出TTL标志（ controller.node  Added TTL to empty node）时间到了就会终止该EC2节点\n\n```bash\n kubectl scale deployment inflate --replicas 0\n```\n\n![image-20211217154353774](./media/image-20211217154353774.png)\n"
  }
]