├── README.md
├── .DS_Store
├── docs
├── .DS_Store
├── cloud
│ ├── .DS_Store
│ ├── aws
│ │ ├── .DS_Store
│ │ ├── assets
│ │ │ ├── task-web.png
│ │ │ ├── 3tier-result.png
│ │ │ ├── access-emr-ssh.png
│ │ │ ├── asg-network-vpc.png
│ │ │ ├── ecs-fargate-td.png
│ │ │ ├── emr-spark-setup.png
│ │ │ ├── asg-activity-log.png
│ │ │ ├── ecs-fargate-check.png
│ │ │ ├── ecs-service-spec.png
│ │ │ ├── emr-spark-zepplin.png
│ │ │ ├── vpc-architecture.png
│ │ │ ├── 3tier-architecture.png
│ │ │ ├── access-emr-zepplin.png
│ │ │ ├── asg-launch-template.png
│ │ │ ├── asg-load-monitoring.png
│ │ │ ├── aws-eks-flask-db-app.png
│ │ │ ├── create-zepplin-note.png
│ │ │ ├── ecs-container-spec.png
│ │ │ ├── ecs-fargate-service.png
│ │ │ ├── emr-security-group.png
│ │ │ ├── emr-spot-instances.png
│ │ │ ├── import-data-zepplin.png
│ │ │ ├── xshell-private-key.png
│ │ │ ├── access-emr-ssh-console.png
│ │ │ ├── add-xshell-private-key.png
│ │ │ ├── ecs-fargate-task-check.png
│ │ │ ├── ecs-fargate-td-config.png
│ │ │ ├── emr-spark-architecture.png
│ │ │ ├── emr-spark-description.png
│ │ │ ├── zepplin-register-data.png
│ │ │ ├── asg-activity-log-success.png
│ │ │ ├── asg-activity-log-waiting.png
│ │ │ ├── asg-launch-template-image.png
│ │ │ ├── asg-lb-endpoint-response.png
│ │ │ ├── asg-network-loadbalancer.png
│ │ │ ├── eb-flask-todo-demo-output.png
│ │ │ ├── ecs-fargate-architecture.png
│ │ │ ├── ecs-fargate-service-check.png
│ │ │ ├── ecs-fargate-td-container.png
│ │ │ ├── lightsail-todo-service-ui.png
│ │ │ ├── spark-query-total-delays.png
│ │ │ ├── spark-query-total-flights.png
│ │ │ ├── access-ec2-instance-xshell.png
│ │ │ ├── access-emr-zepplin-console.png
│ │ │ ├── asg-launch-template-created.png
│ │ │ ├── eb-flask-todo-architecture.jpg
│ │ │ ├── eb-flask-todo-demo-webpage.png
│ │ │ ├── lightsail-container-service.png
│ │ │ ├── asg-group-size-scaling-policy.png
│ │ │ ├── asg-launch-template-networking.png
│ │ │ ├── asg-launch-template-userdata.png
│ │ │ ├── lightsail-container-deployment.png
│ │ │ ├── spark-query-total-departures.png
│ │ │ ├── asg-tutorial-architecture-diagram.png
│ │ │ ├── eb-flask-todo-demo-webpage-updated.png
│ │ │ ├── testsession.jsp
│ │ │ ├── eks-cluster-config.yml
│ │ │ └── testdb.jsp
│ │ ├── cloud9-python-docker.md
│ │ ├── ec2-setup.md
│ │ ├── aws-ecs-container.md
│ │ ├── aws-lightsail-container.md
│ │ ├── aws-elasticbeanstalk.md
│ │ ├── aws-autoscaling-group.md
│ │ ├── aws-emr-spark-bigdata.md
│ │ ├── amazon-eks-setup.md
│ │ └── apache-tomcat-redis.md
│ ├── gcp
│ │ ├── assets
│ │ │ ├── gcp-vpc-firewall.png
│ │ │ └── gce-connect-via-ssh.png
│ │ └── gcp-ce-setup.md
│ └── openstack
│ │ ├── assets
│ │ ├── manage-instance.png
│ │ ├── openstack-on-ec2.png
│ │ ├── inc-python-line198.png
│ │ └── openstack-horizon-dashboard.png
│ │ └── install-openstack.md
├── assets
│ ├── channel_add_small.png
│ └── cloudacode-intro.png
├── kubernetes
│ ├── assets
│ │ ├── task-web.png
│ │ ├── argo-web-console.png
│ │ ├── argo-architecture.png
│ │ ├── grafana-dashboard.png
│ │ ├── grafana-datasource.png
│ │ ├── minikube-todo-app.jpg
│ │ ├── grafana-k8s-dashboard.png
│ │ ├── argo-prometheus-synced.png
│ │ ├── grafana-helm-servicetype.png
│ │ └── kubernetes-cluster-prometheus_rev1.json
│ ├── argocd-deployment.md
│ └── minikube-todo-app.md
├── devops
│ └── cicd
│ │ ├── assets
│ │ ├── codebuild-env.png
│ │ ├── code-connection.png
│ │ ├── codepipline-result.png
│ │ ├── github-action-pr.png
│ │ ├── code-connection-list.png
│ │ ├── ci-system-architecture.png
│ │ ├── secretmanager-keyvalue.png
│ │ ├── codbuildpolicy-secretarn.png
│ │ ├── codepipline-architecture.jpg
│ │ ├── secretsmanager-dockerhub-arn.png
│ │ ├── build_process_by_github_webhook.png
│ │ ├── continuous-delivery-codepipeline.png
│ │ └── github-action-dockerhub-architecture.png
│ │ ├── github-action-dockerhub.md
│ │ ├── aws-codepipeline-delivery-eb.md
│ │ ├── aws-codepipeline-delivery-ecs.md
│ │ └── github-aws-codebuild-dockerhub.md
├── python
│ ├── assets
│ │ └── docker-flask-mariadb.jpeg
│ └── flask
│ │ └── simple-flask-app-mariadb.md
└── index.md
├── .gitignore
├── .github
└── workflows
│ └── ci.yml
├── overrides
└── main.html
└── mkdocs.yml
/README.md:
--------------------------------------------------------------------------------
1 | # tutorials
2 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/.DS_Store
--------------------------------------------------------------------------------
/docs/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio code directorie(s)
2 | .vscode/
3 |
4 | .DS_Store
5 | .log
--------------------------------------------------------------------------------
/docs/cloud/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/.DS_Store
--------------------------------------------------------------------------------
/docs/cloud/aws/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/.DS_Store
--------------------------------------------------------------------------------
/docs/assets/channel_add_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/assets/channel_add_small.png
--------------------------------------------------------------------------------
/docs/assets/cloudacode-intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/assets/cloudacode-intro.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/task-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/task-web.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/task-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/task-web.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/3tier-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/3tier-result.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/access-emr-ssh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/access-emr-ssh.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-network-vpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-network-vpc.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-td.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-td.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/emr-spark-setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/emr-spark-setup.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/codebuild-env.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/codebuild-env.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-activity-log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-activity-log.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-check.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-service-spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-service-spec.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/emr-spark-zepplin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/emr-spark-zepplin.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/vpc-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/vpc-architecture.png
--------------------------------------------------------------------------------
/docs/cloud/gcp/assets/gcp-vpc-firewall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/gcp/assets/gcp-vpc-firewall.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/code-connection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/code-connection.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/argo-web-console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/argo-web-console.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/3tier-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/3tier-architecture.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/access-emr-zepplin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/access-emr-zepplin.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-launch-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-launch-template.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-load-monitoring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-load-monitoring.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/aws-eks-flask-db-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/aws-eks-flask-db-app.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/create-zepplin-note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/create-zepplin-note.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-container-spec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-container-spec.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-service.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/emr-security-group.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/emr-security-group.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/emr-spot-instances.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/emr-spot-instances.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/import-data-zepplin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/import-data-zepplin.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/xshell-private-key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/xshell-private-key.png
--------------------------------------------------------------------------------
/docs/cloud/gcp/assets/gce-connect-via-ssh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/gcp/assets/gce-connect-via-ssh.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/codepipline-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/codepipline-result.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/github-action-pr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/github-action-pr.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/argo-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/argo-architecture.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/grafana-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/grafana-dashboard.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/grafana-datasource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/grafana-datasource.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/minikube-todo-app.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/minikube-todo-app.jpg
--------------------------------------------------------------------------------
/docs/python/assets/docker-flask-mariadb.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/python/assets/docker-flask-mariadb.jpeg
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/access-emr-ssh-console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/access-emr-ssh-console.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/add-xshell-private-key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/add-xshell-private-key.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-task-check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-task-check.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-td-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-td-config.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/emr-spark-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/emr-spark-architecture.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/emr-spark-description.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/emr-spark-description.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/zepplin-register-data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/zepplin-register-data.png
--------------------------------------------------------------------------------
/docs/cloud/openstack/assets/manage-instance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/openstack/assets/manage-instance.png
--------------------------------------------------------------------------------
/docs/cloud/openstack/assets/openstack-on-ec2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/openstack/assets/openstack-on-ec2.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/code-connection-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/code-connection-list.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/grafana-k8s-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/grafana-k8s-dashboard.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-activity-log-success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-activity-log-success.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-activity-log-waiting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-activity-log-waiting.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-launch-template-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-launch-template-image.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-lb-endpoint-response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-lb-endpoint-response.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-network-loadbalancer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-network-loadbalancer.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/eb-flask-todo-demo-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/eb-flask-todo-demo-output.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-architecture.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-service-check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-service-check.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/ecs-fargate-td-container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/ecs-fargate-td-container.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/lightsail-todo-service-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/lightsail-todo-service-ui.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/spark-query-total-delays.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/spark-query-total-delays.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/spark-query-total-flights.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/spark-query-total-flights.png
--------------------------------------------------------------------------------
/docs/cloud/openstack/assets/inc-python-line198.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/openstack/assets/inc-python-line198.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/ci-system-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/ci-system-architecture.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/secretmanager-keyvalue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/secretmanager-keyvalue.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/argo-prometheus-synced.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/argo-prometheus-synced.png
--------------------------------------------------------------------------------
/docs/kubernetes/assets/grafana-helm-servicetype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/kubernetes/assets/grafana-helm-servicetype.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/access-ec2-instance-xshell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/access-ec2-instance-xshell.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/access-emr-zepplin-console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/access-emr-zepplin-console.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-launch-template-created.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-launch-template-created.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/eb-flask-todo-architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/eb-flask-todo-architecture.jpg
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/eb-flask-todo-demo-webpage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/eb-flask-todo-demo-webpage.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/lightsail-container-service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/lightsail-container-service.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/codbuildpolicy-secretarn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/codbuildpolicy-secretarn.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/codepipline-architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/codepipline-architecture.jpg
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-group-size-scaling-policy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-group-size-scaling-policy.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-launch-template-networking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-launch-template-networking.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-launch-template-userdata.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-launch-template-userdata.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/lightsail-container-deployment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/lightsail-container-deployment.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/spark-query-total-departures.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/spark-query-total-departures.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/secretsmanager-dockerhub-arn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/secretsmanager-dockerhub-arn.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/asg-tutorial-architecture-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/asg-tutorial-architecture-diagram.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/eb-flask-todo-demo-webpage-updated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/aws/assets/eb-flask-todo-demo-webpage-updated.png
--------------------------------------------------------------------------------
/docs/cloud/openstack/assets/openstack-horizon-dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/cloud/openstack/assets/openstack-horizon-dashboard.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/build_process_by_github_webhook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/build_process_by_github_webhook.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/continuous-delivery-codepipeline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/continuous-delivery-codepipeline.png
--------------------------------------------------------------------------------
/docs/devops/cicd/assets/github-action-dockerhub-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudacode/tutorials/HEAD/docs/devops/cicd/assets/github-action-dockerhub-architecture.png
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/testsession.jsp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Session ID
6 | <%=session.getId()%>
7 |
8 |
9 | Server IP
10 | <%=request.getLocalAddr()%>
11 |
12 |
13 | Server Name: <%=request.getLocalName()%>
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: cloudacode-tutorials-ci
2 | on:
3 | push:
4 | branches:
5 | - master
6 | - main
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - uses: actions/setup-python@v2
13 | with:
14 | python-version: 3.x
15 | - run: pip install mkdocs-material
16 | - run: mkdocs gh-deploy --force
17 |
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/eks-cluster-config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: eksctl.io/v1alpha5
3 | kind: ClusterConfig
4 |
5 | metadata:
6 | name: cloud-eks-cluster
7 | region: ap-northeast-2
8 |
9 | availabilityZones: ["ap-northeast-2a", "ap-northeast-2c"]
10 |
11 | iam:
12 | withOIDC: true
13 |
14 | managedNodeGroups:
15 | - name: cloud-eks-workers
16 | desiredCapacity: 1
17 | iam:
18 | withAddonPolicies:
19 | albIngress: true
20 | instanceTypes: ["c4.large","c5.large"]
21 | spot: true
22 | # instanceType: t3.small
23 | # ssh:
24 | # publicKeyName: ""
25 | # https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2#KeyPairs:
26 |
27 | cloudWatch:
28 | clusterLogging:
29 | enableTypes: ["audit", "authenticator", "controllerManager"]
30 |
--------------------------------------------------------------------------------
/docs/cloud/aws/cloud9-python-docker.md:
--------------------------------------------------------------------------------
1 | # Develop Python and Docker on Cloud9
2 |
3 | **Cloud9을 통해서 Python 과 Docker 개발 환경 구성**
4 |
5 | 이번 실습은 AWS의 Cloud9를 통해 Python과 Docker를 개발하는 환경을 만드는 것을 목표로 합니다. 또한 Cloud9로 접근을 위한 Security Group 설정과 Disk volume 추가하는 방법도 포함되어 있습니다.
6 |
7 | **Time to Complete: 0.5 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
12 |
13 | ## 1. What is the Cloud9
14 | A cloud IDE for writing, running, and debugging code.
15 | [AWS Official Document](https://aws.amazon.com/cloud9/)
16 |
17 | ## 2. How to use Cloud9
18 |
19 | VIDEO
20 |
21 | 🎉 Congratulations, you have completed Cloud9 tutorial
--------------------------------------------------------------------------------
/overrides/main.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block extrahead %}
4 | {% set title = config.site_name %}
5 | {% set description = config.site_description %}
6 | {% set image = "https://raw.githubusercontent.com/cloudacode/tutorials/main/docs/assets/cloudacode-intro.png" %}
7 | {% if page and page.meta and page.meta.title %}
8 | {% set title = page.meta.title ~ " - " ~ title %}
9 | {% set description = page.meta.description %}
10 | {% set image = page.meta.image %}
11 | {% elif page and page.title and not page.is_homepage %}
12 | {% set title = page.title ~ " - " ~ title %}
13 | {% endif %}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {% endblock %}
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Welcome to Cloudacode
2 |
3 | ## Cloudacode Project 🚀
4 |
5 | Get started with step-by-step tutorials for `cloud, devops, kubernetes, and cncf technology`.
6 |
7 | ## Project layout 📚
8 |
9 | cloud/
10 | ... # Cloud 101
11 | devops(CICD)/
12 | ... # Continuous Integration / Deployment
13 | devops(Terraform)/
14 | ... # Terraform
15 | kubernetes/
16 | ... # Kubernetes
17 | cncf/
18 | ... # Cncf project
19 | etc/
20 | ... # Etc
21 |
22 | ## Me 🧑🚀
23 |
24 | A seasoned cloud and site reliability engineer with 12 years of experience in the web-scale tech industry.
25 |
26 | Areas of professional expertise:
27 |
28 | * On and off-prem cloud environment engineering
29 | * Deliver scalable and reliable infra with K8S
30 | * Improve operation efficiency and modernize legacy environment
31 | * Problem Solving / Strategic Thinking
32 | * Cross-functional communications
33 | * Project planning and management
34 |
35 | For full profile visit [kyungcheol's Linkedin](https://www.linkedin.com/in/kyungcheol/).
--------------------------------------------------------------------------------
/docs/cloud/aws/assets/testdb.jsp:
--------------------------------------------------------------------------------
1 | <%@page import="java.sql.DriverManager"%>
2 | <%@page import="java.sql.ResultSet"%>
3 | <%@page import="java.sql.Statement"%>
4 | <%@page import="java.sql.Connection"%>
5 | <%
6 | String id = request.getParameter("userid"); String driver =
7 | "com.mysql.jdbc.Driver"; String connectionUrl =
8 | "jdbc:mysql://database-1.cxm6fgejlg3y.ap-northeast-2.rds.amazonaws.com:3306/";
9 | String database = "javatest"; String userid = "admin"; String password =
10 | "qazWSX123"; try { Class.forName(driver); } catch (ClassNotFoundException e) {
11 | e.printStackTrace(); } Connection connection = null; Statement statement = null;
12 | ResultSet resultSet = null; %>
13 |
14 |
15 |
16 |
17 |
18 | session id
19 | <%=session.getId()%>
20 |
21 |
22 | foo
23 | bar
24 |
25 | <% try{ connection = DriverManager.getConnection(connectionUrl+database,
26 | userid, password); statement=connection.createStatement(); String sql
27 | ="select id, foo, bar from testdata"; resultSet =
28 | statement.executeQuery(sql); while(resultSet.next()){ %>
29 |
30 | <%=resultSet.getString("foo") %>
31 | <%=resultSet.getString("bar") %>
32 |
33 | <% } connection.close(); } catch (Exception e) { e.printStackTrace(); } %>
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | # Project information
2 | site_name: CLOUDACODE
3 | site_url: https://cloudacode.com/tutorials/
4 | site_author: KC Chang
5 | site_description: >-
6 | Introduces the process of building various applications in the cloud environment
7 | and improving development procedures with DevOps culture.
8 |
9 | # Repository
10 | repo_name: cloudacode/tutorials
11 | repo_url: https://github.com/cloudacode/tutorials
12 | edit_uri: ""
13 |
14 | # Google Analytics
15 | extra:
16 | analytics:
17 | provider: google
18 | property: G-L86XX3YR79
19 |
20 | # Configuration
21 | theme:
22 | name: material
23 | custom_dir: overrides
24 | palette:
25 | - scheme: default
26 | toggle:
27 | icon: material/weather-sunny
28 | name: Switch to dark mode
29 | - scheme: slate
30 | toggle:
31 | icon: material/weather-night
32 | name: Switch to light mode
33 |
34 | markdown_extensions:
35 | - admonition
36 | - pymdownx.highlight
37 | - meta
38 |
39 | # Page tree
40 | nav:
41 | - Home: index.md
42 | - Tutorial:
43 | - Cloud:
44 | - AWS:
45 | - cloud/aws/ec2-setup.md
46 | - cloud/aws/aws-autoscaling-group.md
47 | - cloud/aws/aws-elasticbeanstalk.md
48 | - cloud/aws/apache-tomcat-redis.md
49 | - cloud/aws/cloud9-python-docker.md
50 | - cloud/aws/aws-lightsail-container.md
51 | - cloud/aws/aws-ecs-container.md
52 | - cloud/aws/amazon-eks-setup.md
53 | - cloud/aws/aws-emr-spark-bigdata.md
54 | - GCP:
55 | - cloud/gcp/gcp-ce-setup.md
56 | - Openstack:
57 | - cloud/openstack/install-openstack.md
58 | - Python:
59 | - python/flask/simple-flask-app-mariadb.md
60 | - Kubernetes:
61 | - kubernetes/minikube-todo-app.md
62 | - kubernetes/argocd-deployment.md
63 | - DevOps:
64 | - CICD:
65 | - devops/cicd/github-aws-codebuild-dockerhub.md
66 | - devops/cicd/github-action-dockerhub.md
67 | - devops/cicd/aws-codepipeline-delivery-eb.md
68 | - devops/cicd/aws-codepipeline-delivery-ecs.md
69 | # - DevOps(Terraform):
70 | # - Kubernetes:
71 | # - Monitoring:
72 | # - CNCF:
73 | # - ETC:
74 | - Blog ⧉: https://medium.com/@cloudacode
75 | - Youtube ⧉: https://www.youtube.com/channel/UCw46J_QQ3-HrjPsSsuOSDdQ
76 |
--------------------------------------------------------------------------------
/docs/cloud/gcp/gcp-ce-setup.md:
--------------------------------------------------------------------------------
1 | # Launch a GCE, Deploy Flask app
2 |
3 | **GCP 환경 구성 및 Compute Engine 구축**
4 |
5 | 이번 실습은 GCP를 통해 서비스 구성 시 가장 기본이 되는 Compute Engine 구성 실습을 통해서 GCP의 기본 서비스들을 이해 하고 GCP 콘솔 활용 방법을 익히기 위함입니다. Compute Engine 컴퓨팅 리소스 활용 및 서비스 배포를 위한 기본 작업들을 이해 할 수 있습니다.
6 |
7 | **Time to Complete: 1-2 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | * **GCP Account and Administrator-level or PowerUser-level access to it**
12 |
13 | ## System Architecture
14 |
15 | ## 1. Launch GCE instance
16 |
17 | https://console.cloud.google.com/compute
18 |
19 | ### Create VM instances
20 |
21 | - Name: `gcp-test`
22 | - Region: `asia-northeast3(Seoul)` Zone: `asia-northeast3-a`
23 | - Machine configuration: 인스턴스의 크기(타입)
24 | - Confidential VM service: 데이터 암호화 옵션(`변경 없음`)
25 | - Container: GKE 혹은 GCE에 컨테이너를 활용 옵션(`변경 없음`)
26 | - Boot Disk: OS 이미지(`Debian`)
27 | - Identity and API access
28 | - Service account: 인스턴스, 인스턴스에서 실행되는 앱이 다른 GCP 서비스와 상호작용 할때 필요한 서비스 계정(`변경 없음`)
29 | - Access scopes: 접근 범위(`Allow default access`)
30 | - Firewall: 방화벽
31 | - Allow HTTP traffic (`변경 없음`)
32 |
33 | ### Create a firewall
34 |
35 | Flask 서비스 포트(5000)을 custom하게 firewall에 추가가 필요
36 |
37 |
38 | 로 접속 하여 **Create Firewall Rule** 선택 후 아래와 같이 입력
39 |
40 | - Name: default-flask-app
41 | - Network: default
42 | - Prioity: 1000
43 | - Direction of traffic: ingress
44 | - Action on match: Allow
45 | - Targets: All instances in the network
46 | - Source filter: IP ranges
47 | - Source IP Ranges: `0.0.0.0/0`
48 | - Protocol and ports:
49 | - Specified protocols and ports: `tcp` `5000`
50 |
51 | !!! Note
52 | 만약 node.js 혹은 django 로 실습을 수행할 시에 해당 포트에 맞게 Custom TCP port 설정 변경
53 |
54 | ## 2. Access a GCE instance
55 |
56 | VM Instance 콘솔 화면 Connect 항목에 `SSH` 클릭 후 `View gcloud command` 를 통해 인스턴스 접근
57 | 
58 |
59 | gcloud command line 창에서 오른쪽 아래 `RUN IN CLOUD SHELL` 클릭
60 |
61 | Cloud Shell이 열리고 인스턴스 접근에 대한 커멘드 라인이 자동으로 입력되어 있으므로 추가 변경 없이 진행 하면 정상적으로 인스턴스에 접근이 됨
62 | * SSH Key 생성이 이루어지고 추가 입력값 없이 빈칸으로 진행
63 |
64 |
65 | ## 3. Run Python Flask on GCE server
66 |
67 | GCE 리눅스 서버에 접속 후 python3-pip 패키지 설치
68 | ```bash
69 | sudo apt update
70 | sudo apt install python3-pip
71 | ```
72 |
73 | 접근한 Linux에서 Flask 설치
74 | ```bash
75 | pip3 install Flask
76 | pip3 freeze > requirements.txt
77 | ```
78 |
79 | Flask app 파일 설정 `app.py`
80 | ```bash
81 | cat < app.py
82 | from flask import Flask
83 | app = Flask(__name__)
84 |
85 | @app.route('/')
86 | def hello_world():
87 | return "Hello, GCE!"
88 |
89 | if __name__ == "__main__":
90 | app.run(debug=True, host='0.0.0.0', port=5000)
91 | EOF
92 | ```
93 |
94 | Flask app 실행
95 | ```bash
96 | python3 app.py
97 | ```
98 |
99 | GCE의 External IP를 확인 후 해당 IP에 Flask Port(5000)으로 접속 및 페이지 확인
100 |
101 | (옵션) Flask에 CSS, HTML 페이지를 구성 하고 싶을 경우 아래 코드를 참고
102 |
103 | [simple-flask-web-app](https://github.com/cloudacode/coolstuff/tree/main/simple-flask-web)
104 |
105 | 🎉 Congratulations, you have completed GCE, Flask setup tutorial
--------------------------------------------------------------------------------
/docs/devops/cicd/github-action-dockerhub.md:
--------------------------------------------------------------------------------
1 | # Publishing Docker images - GitHub Action
2 |
3 | **개발 빌드 환경 구성 및 Container 빌드 자동화 실습**
4 |
5 | [GitHub Action](https://docs.github.com/en/actions)을 master 혹은 main branch로 코드가 커밋이 되면 어플리케이션을 도커로 빌드 자동화 및 도커 레지스트리([hub.docker.com](https://hub.docker.com/)) 에 이미지 등록
6 |
7 | **Time to Complete: 1 hour**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | * **An Administrator-level for GitHub Repo**
12 | * **Understand what is the GitHub Actions**
13 |
14 | VIDEO
15 |
16 | ## System Architecture
17 | 
18 |
19 | ## 1. Create encrypted secrets for a GitHub Repo
20 |
21 | [creating-encrypted-secrets-for-a-repository](https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository)
22 |
23 | - Name: `DOCKER_USERNAME`, Vaule: `Your DockerHub Account Name`
24 | - Name: `DOCKER_PASSWORD`, Value: `Your DockerHub Password`
25 |
26 | ## 2. Create a workflow to use actions
27 |
28 | 최상위 디렉토리 `.github/workflows/github-actions-dockerhub.yml`에 workflow 스펙을 아래와 같이 명시
29 |
30 | ```yaml
31 | name: Publish Docker image
32 |
33 | on:
34 | pull_request:
35 | types: [assigned, opened, synchronize, reopened]
36 |
37 | jobs:
38 | push_to_registry:
39 | name: Push Docker image to Docker Hub
40 | runs-on: ubuntu-latest
41 | steps:
42 | - name: Check out the repo
43 | uses: actions/checkout@v3
44 |
45 | - name: Log in to Docker Hub
46 | uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
47 | with:
48 | username: ${{ secrets.DOCKER_USERNAME }}
49 | password: ${{ secrets.DOCKER_PASSWORD }}
50 |
51 | - name: Extract metadata (tags, labels) for Docker
52 | id: meta
53 | uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
54 | with:
55 | images: dockerhub-namespace/dockerhub-repository
56 |
57 | - name: Build and push Docker image
58 | uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
59 | with:
60 | context: .
61 | file: ./Dockerfile
62 | push: true
63 | tags: ${{ steps.meta.outputs.tags }}
64 | labels: ${{ steps.meta.outputs.labels }}
65 | ```
66 |
67 | Line 25 번째 줄에 본인의 `dockerhub-namespace/repo-name` 으로 변경후 code commit & main branch에 merge
68 |
69 | ## 3. Verify GitHub Action
70 |
71 | - Git Branch 생성 후 코드 수정 및 Commit
72 | - GitHub에서 Main Branch로 Pull Request 수행
73 | - Pull Request 진행 화면에서 Github Action이 동작 하는지 확인
74 | 
75 |
76 | ## 4. Verify DockerHub image
77 |
78 | 이미지가 정상적으로 본인 Repo에 업로드 되었는지 확인
79 | https://hub.docker.com
80 |
81 | !!! Note
82 | workflow 스펙 파일에서 별도로 tag를 지정 하지 않았다면 pr 번호가 image tag로 부여됨
83 |
84 | ## Reference
85 | - https://docs.github.com/en/actions/guides/publishing-docker-images
86 |
87 |
88 | 🎉 Congratulations, you have completed Publishing Docker images - GitHub Action tutorial
89 |
--------------------------------------------------------------------------------
/docs/cloud/aws/ec2-setup.md:
--------------------------------------------------------------------------------
1 | # Launch an EC2, Deploy Flask app
2 |
3 | **AWS EC2 구성 및 Python Flask 앱 배포**
4 |
5 | 이번 실습은 AWS를 통해 서비스 구성 시 가장 기본이 되는 EC2 구성 실습을 통해서 AWS의 기본 서비스들을 이해 하고 AWS 콘솔 활용 방법을 익히기 위함입니다. EC2로 컴퓨팅 리소스 활용 및 서비스 배포를 위한 기본 작업들을 이해 할 수 있습니다.
6 |
7 | **Time to Complete: 1-2 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
12 |
13 | ## System Architecture
14 | 
15 |
16 | ## 1. Launch EC2 instance
17 |
18 | https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2
19 |
20 | ### Choose an Amazon Machine Image(AMI)
21 |
22 | Instance 의 OS 이미지를 선택하는 단계 이며 Amazon Linux, CentOS, Ubunt, WindowsOS 등 다양한 OS 이미지를 선택 가능
23 |
24 | `Amazon Linux 2 AMI (HVM), SSD Volume Type`
25 |
26 | ### Chooose an Instance Type
27 |
28 | Instance의 CPU, Memory , Network 용량을 선택 하는 단계이며 일반 인스턴트 타입외에 높은 CPU, Memory, IO 타입도 제공
29 |
30 | `t2.micro`
31 |
32 | ### Instance Details
33 |
34 | Instance가 배포되는 네트워크 환경 VPC, Subnet) 설정
35 |
36 | - Number of instances: 한번에 배포할 인스턴스의 개수이며 1로 유지
37 | - Purchasing option: Spot instances를 활용 할건지의 유무, 선택 하지 않음
38 | - Network: Default VPC 선택
39 | - Subnet: No preference
40 | - Auto-assign Public IP: 자동으로 Public IP 할당 유무를 체크 하는 부분 Enable로 선택
41 | - IAM role: EC2 인스턴스에 IAM 역할을 부여해 추후 API/ Secret key를 사용하지 않고 AWS 소스 자원을 관리 하도록 설정 하는 부분
42 | - Tenancy: 추후에 License이슈 혹은 매우 낮은 네트워크 Latency를 위해 특정 Hardware에 Instance를 몰아서 배치할 수 있는 기능, Default(Shared)로 선택
43 |
44 | ### Instance Storage 설정
45 |
46 | Instance의 Disk 용량과 추가 Disk를 선택, Root 볼륨 size와 Disk 볼륨의 유무, size를 정하는 부분
47 |
48 | 기본 `8GB`로 진행
49 |
50 | ### Add Tags
51 |
52 | AWS콘솔에서 Display 되는 Tag 의 값을 지정 하는 부분 이고 Add Tag 텝 클릭 후 값 입력
53 | (*추후 손쉽게 생성한 서버를 찾기 위함이며 기억할 수 있는 이름으로 서버 이름 변경 가능
54 |
55 | `Key: Name, Value: Web Server`
56 |
57 | ### Configure Security Group
58 |
59 | SG는 Host 레벨의 방화벽이며 Allow 정책만 가능하며 서비스할 Port 만 허용 혹은 원격 접속을 위한 접근 대역 IP 로만 제한을 통해 보안 수준을 높임
60 |
61 | Secuirty Group Name: `test-flask-sg`
62 |
63 | - SSH(22)
64 | - Type: SSH
65 | - Source: My IP or Anywhere
66 | - TCP(5000, Flask)
67 | - Type: Custom TCP
68 | - PORT: 5000
69 | - Source: My IP or Anywhere
70 |
71 | !!! Note
72 | 만약 node.js 혹은 django 로 실습을 수행할 시에 해당 포트에 맞게 Custom TCP port 설정 변경
73 |
74 | ### Review Instance Launch
75 |
76 | Instance 배포를 위해 지정한 설정값들을 리뷰 하는 단계 이며 서버에 접근을 위한 key 발급을 진행, Launch 클릭후 key pair 생성
77 |
78 | **Create a new key pair** 진행 후 Download Key Pair
79 |
80 | !!! Warning
81 | key는 재발급 되지 않으므로 안전한 곳에 key 를 저장
82 |
83 | ## 2. Monitor EC2 instance
84 |
85 | 정상적으로 Instance가 배포 되는지 EC2 Dashboard에서 확인 가능
86 | Status Checks 가 2/2가 되면 정상 배포 완료
87 |
88 | ## 3. Access EC2 instance
89 |
90 | [EC2 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2#Instances:instanceState=running)에서 생성한 인스턴스 선택 후 **connect** 버튼을 클릭하면 터미널로 접속 가이드라인이 아래와 같이 제공
91 |
92 | ```bash
93 | ssh -i ec2-user@
94 | ```
95 |
96 | 만약 Windows를 사용 하고 있다면 Xshell을 활용
97 |
98 | 공식 홈페이지에서 다운로드
99 | URL:
100 | https://www.netsarang.co.kr/download/main.html
101 |
102 | 항목: Xshell5
103 | https://www.netsarang.co.kr/download/down_form.html?code=512
104 |
105 | - 새로운 세션 생성 및 사용자 인증
106 |
107 | 
108 | 
109 | 
110 |
111 | ## 4. Run Python Flask on EC2 server
112 |
113 | 접근한 Linux에서 Flask 설치
114 | ```bash
115 | pip3 install Flask
116 | pip3 freeze > requirements.txt
117 | ```
118 |
119 | Flask app 파일 설정 `app.py`
120 | ```bash
121 | cat < app.py
122 | from flask import Flask
123 | app = Flask(__name__)
124 |
125 | @app.route('/')
126 | def hello_world():
127 | return "Hello, EC2!"
128 |
129 | if __name__ == "__main__":
130 | app.run(debug=True, host='0.0.0.0', port=5000)
131 | EOF
132 | ```
133 |
134 | Flask app 실행
135 | ```bash
136 | python3 app.py
137 | ```
138 |
139 | [EC2 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2#Instances:instanceState=running)
140 | 에서 **Public IPv4 address** 확인 혹은 리눅스 커멘드로 `curl ifconfig.me` 후 해당 IP에 Flask 포트(5000) 으로 접속 및 페이지 확인
141 |
142 | (옵션) Flask에 CSS, HTML 페이지를 구성 하고 싶을 경우 아래 코드를 참고
143 |
144 | [simple-flask-web-app](https://github.com/cloudacode/coolstuff/tree/main/simple-flask-web)
145 |
146 | 🎉 Congratulations, you have completed EC2, Flask setup tutorial
--------------------------------------------------------------------------------
/docs/cloud/aws/aws-ecs-container.md:
--------------------------------------------------------------------------------
1 | # Deploy Container on Elastic Container Service
2 |
3 | **Amazon ECS를 통해 Container 배포**
4 |
5 | 이번 실습은 Amazon ECS 통해 Container를 배포하고 접근을 해보는 실습 입니다. AWS Elastic Container Service의 Cluster, Service의 직접 구성을 통해 프러덕션 어플리케이션을 구성 하고 관리 하는 방법을 이해 할 수 있습니다
6 |
7 | 
8 |
9 | **Time to Complete: 0.5 hours**
10 |
11 |
17 |
18 | **Tutorial Prereqs:**
19 |
20 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
21 | * **본인이 생성한 컨테이너 이미지** [freecode-todo](https://hub.docker.com/repository/docker/cloudacode/freecodetodo), [소스 코드](https://github.com/cloudacode/FlaskIntroduction)
22 |
23 | ## 1. Task Definitions 설정
24 |
25 | 하나 혹은 여러 개의 Container로 구성된 하나의 어플리케이션을 Task정의로 지정 하며 Task 단위로 ECS에 배포
26 | 
27 |
28 | ECS Dashboard 에서 [Task Definitions](https://ap-northeast-2.console.aws.amazon.com/ecs/home/taskDefinitions) 선택 후 **Create new Task Definition**
29 |
30 | - Task Definition Name: 작업 정의 이름, TD이름
31 | - Requires compatibilities: FARGATE
32 | - Task Role: Task에서 AWS 리소스에 API로 호출을 해야 할 경우 사용하는 IAM 역할, 변경없음
33 | - Network Mode: AWS Fargate에서는 awsvpc가 기본이며 그 외는 Linux는 Docker네트워크이며 Windows의 경우 NAT, Bridge모드 선택 가능, 변경없음
34 | - Operating System Family: Linux
35 | - Task memory (MiB): Container에 할당할 최대 메모리(하드 리밋)이며 ECS 인스턴스에 올라가는 Task들의 워크로드에 따라 용량 결정 필요: 0.5GB - 2GB 에서 선택
36 | - Task CPU (unit): Container용으로 예약할 CPU unit: 0.25 vCPU – 16 vCPU 중에 선택
37 |
38 | 
39 |
40 | **Container Definitions** 정의 항목에 아래와 같이 실제 Container의 이름과 이미지 주소 등의 필수 요소 및 저장소, 로깅, 보안에 관련한 선택 요소 들을 지정
41 |
42 | - Container Name: 컨테이너 이름
43 | - Image: 컨테이너 이미지 URL
44 | 예) cloudacode/freecodetodo:latest
45 | - Port Mappings: 외부로 노출할 컨테이너 포트
46 |
47 | 
48 |
49 | ## 2. Cluster 생성
50 |
51 | ECS Cluster [콘솔 화면](https://ap-northeast-2.console.aws.amazon.com/ecs/home/clusters)에서 Cluster 생성
52 |
53 | - Template: Networking only
54 | - Cluster Name: 클러스터 이름
55 |
56 | !!! WARN
57 | 기존에 만들어진 VPC를 활용 할 예정이므로 새롭게 Create VPC 하지 않는다
58 |
59 | ## 3. Service 설정
60 |
61 | 위에서 생성한 이름의 Cluster 클릭 후 상세 화면에서 서비스 설정
62 |
63 | 
64 |
65 | ### Service 구성
66 |
67 | - Task Definition: 작업 정의 이름
68 | - Cluster: Container가 배포될 Cluster, cluster 이름
69 | - Service name: 사용할 서비스 이름 결정, service 이름
70 | - Number of tasks: 서비스에 배포할(수평 확장) Task의 개수, 1개 이상
71 | - Minimum healthy percent: 배포 시 RUNNING 상태를 유지해야 하는 서비스 내 작업 수에 대한 최소 리소스 백분율, 100
72 | - Maximum percent: 배포 시 RUNNING/ PENDING 상태를 유지할 최대 작업 수에 대한 리소스 백분율, 200
73 | - Deployments: 작업 배포 정책(Rolling, Blue/Green), Rolling update
74 |
75 | 
76 |
77 | ### Network 구성
78 | - VPC/Subnets: 원하는 VPC와 Subnets을 지정
79 | - Security Group: Container를 외부로 노출할때 사용하는 Port를 Open(예, Flask 5000포트)
80 | - Load balancer Type: LB 타입 선택, No
81 |
82 | ### AutoScaling 구성
83 | - Service Auto Scaling: AutoScaling 설정 가능, Do not adjust
84 |
85 | 생성 완료 후 ECS Cluster 항목에서 서비스 상태 확인 (Task가 정상적으로 배포 및 Running 확인)
86 |
87 | ## 4. Service 동작 확인
88 |
89 | 
90 |
91 | 서비스가 정상적으로 `ACTIVE` 상태가 확인이 되면 TASK 상세 화면에서 Public IP로 접속
92 |
93 | 
94 |
95 | 해당 `URL`을 브라우저에서 접속하여 컨테이너가 정상적으로 서비스 중인지 확인
96 |
97 | 
98 |
99 | ## 4. 환경 삭제
100 |
101 | ECS Cluster [콘솔 화면](https://ap-northeast-2.console.aws.amazon.com/ecs/home/clusters)에서 Cluster 삭제
102 |
103 | 🎉 Congratulations, you have completed Amazon Elastic Container Service tutorial
104 |
105 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
106 |
107 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/docs/cloud/aws/aws-lightsail-container.md:
--------------------------------------------------------------------------------
1 | # Deploy Container on AWS Lightsail
2 |
3 | **AWS LightSail에 Container 배포**
4 |
5 | 이번 실습은 AWS LightSail 통해 Container를 배포하고 접근을 해보는 실습 입니다. AWS에서 컨테이너를 배포할수 있는 리소스중 하나인 LightSail에 대해 배워 보고 컨테이너 서비스 배포를 위한 기본 작업들을 이해 할 수 있습니다.
6 |
7 | **Time to Complete: 0.5 hours**
8 |
9 |
15 |
16 | **Tutorial Prereqs:**
17 |
18 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
19 | * **본인이 생성한 컨테이너 이미지** [freecode-todo](https://hub.docker.com/repository/docker/cloudacode/freecodetodo)
20 | * **AWS CLI 및 Lightsail Plugin설치**
21 | [설치 페이지](https://lightsail.aws.amazon.com/ls/docs/en_us/articles/amazon-lightsail-install-software#install-software-aws-cli)
22 |
23 | !!! Warning
24 | Cloud9은 CLI 버전이 1이고 IAM 권한이 제한 되기 때문에 local 개발 환경에서 실습 진행
25 |
26 |
27 | ## 1. Create a Container server on lightsail
28 |
29 | ### Lightsail의 기본적인 스펙과 확장 범위를 설정
30 |
31 | [Lightsail 스펙 페이지](https://aws.amazon.com/lightsail/pricing/?nc1=h_ls)
32 |
33 | !!! Info
34 | 실습은 nano 스펙(512 MB RAM, 0.25 vCPUs)으로 진행
35 |
36 | ```bash
37 | aws lightsail create-container-service \
38 | --service-name --power nano --scale 1
39 | ```
40 |
41 | [Lightsail AWS 콘솔](https://lightsail.aws.amazon.com/ls/webapp/home/containers) 에서 확인 가능
42 | 
43 |
44 | ### Continaer 이미지 다운
45 |
46 | ```bash
47 | docker pull cloudacode/freecodetodo:latest
48 | ```
49 |
50 | 참고: `cloudacode/freecodetodo` [소스 코드](https://github.com/cloudacode/FlaskIntroduction)
51 |
52 | ### Container 이미지 업로드
53 |
54 | ```bash
55 | aws lightsail push-container-image --service-name \
56 | --label flask-container --image cloudacode/freecodetodo:latest
57 | ```
58 |
59 | !!! Warning
60 | output 결과로 나오는 ":devops-flask-service.flask-container.[숫자]"가 배포시 사용할 컨테이너 이미지의 정보이므로 결과 값을 저장
61 |
62 | ## 2. Deploy the container
63 |
64 | ### 컨테이너 메타데이터 파일 생성
65 |
66 | containers.json
67 | ```json
68 | {
69 | "": {
70 | "image": ":..X",
71 | "ports": {
72 | "": "HTTP"
73 | }
74 | }
75 | }
76 | ```
77 |
78 | 예시)
79 | ```json
80 | {
81 | "freecodetodo": {
82 | "image": ":todo-service.flask-container.5",
83 | "ports": {
84 | "5000": "HTTP"
85 | }
86 | }
87 | }
88 | ```
89 |
90 | !!! Note
91 | 본인의 서비스의 ports 맞게 변경 필요, ex) nodejs 기본포트는 3000, flask는 5000
92 |
93 | ### 컨테이너의 Endpoint 설정 파일 생성
94 |
95 | public-endpoint.json
96 | ```json
97 | {
98 | "containerName": "",
99 | "containerPort":
100 | }
101 | ```
102 |
103 | 예시)
104 | ```json
105 | {
106 | "containerName": "freecodetodo",
107 | "containerPort": 5000
108 | }
109 | ```
110 |
111 | !!! Note
112 | 본인의 서비스의 포트에 맞게 변경 필요
113 |
114 |
115 | ### 서비스 배포 수행
116 |
117 | ```bash
118 | aws lightsail create-container-service-deployment --service-name \
119 | --containers file://containers.json --public-endpoint file://public-endpoint.json
120 | ```
121 |
122 | ## 3. 서비스 확인
123 |
124 | [Lightsail 콘솔](https://lightsail.aws.amazon.com/ls/webapp/home/containers) 혹은 aws lightsail cli로 확인
125 |
126 | ```bash
127 | aws lightsail get-container-services --service-name
128 | ```
129 | 을 수행하여 `STATE`가 `RUNNING` 으로 상태가 변경 되었으면 `URL`로 서비스 접속
130 |
131 | 
132 |
133 | 해당 `URL`을 브라우저에서 접속하여 컨테이너가 정상적으로 서비스 중인지 확인
134 |
135 | 
136 |
137 | ## 4. 환경 삭제
138 |
139 | [Lightsail 콘솔](https://lightsail.aws.amazon.com/ls/webapp/home/containers) 혹은 aws lightsail cli 로 삭제
140 |
141 | ```bash
142 | aws lightsail delete-container-service --service-name todo-service
143 | ```
144 |
145 | 🎉 Congratulations, you have completed AWS lightsail tutorial
146 |
147 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
148 |
149 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/docs/cloud/openstack/install-openstack.md:
--------------------------------------------------------------------------------
1 | # Deploy openstack(devstack) on EC2
2 |
3 | **EC2 인스턴스에 테스트용 Openstack 설치**
4 |
5 | 이번 실습은 DevStack(테스트용 Openstack)을 EC2에 설치하고 Horizon 대시보드를 통해 Openstack의 기본 리소스(컴퓨팅, 스토리지, 네트워크 등)를 배포하고 이해 할 수 있습니다.
6 |
7 | **Time to Complete: 1-2 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | * **An AWS Account and PowerUser-level access to it**
12 | * **Ubuntu 20.04, t3.xlarge, Spot, 50GB [EC2 Instance](../cloud/aws/../../aws/ec2-setup.md#1-launch-ec2-instance)**
13 |
14 | ## System Architecture
15 | 
16 |
17 |
18 |
24 |
25 | ## 1. Create stack user
26 |
27 | ```bash
28 | sudo useradd -s /bin/bash -d /opt/stack -m stack
29 | echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack
30 | sudo -u stack -i
31 | ```
32 |
33 | ## 2. Download Devstack
34 |
35 | ```bash
36 | sudo apt update
37 | sudo apt install git -y
38 | git clone https://opendev.org/openstack/devstack
39 | cd devstack/
40 | ```
41 |
42 | ## 3. Install Devstack
43 |
44 | ### Update config file
45 | DevStack의 Password 파일 설정 `local.conf`
46 | ```bash
47 | cat < local.conf
48 | [[local|localrc]]
49 | ADMIN_PASSWORD=cloudacode
50 | DATABASE_PASSWORD=cloudacode
51 | RABBIT_PASSWORD=cloudacode
52 | SERVICE_PASSWORD=cloudacode
53 | EOF
54 | ```
55 |
56 | 설치과정 중 python pip module upgrade시에 발생하는 경고 메시지를 무시하기 위해 `inc/python` 파일 일부를 수정, 198번째 라인에 아래 옵션 추가
57 | ```bash
58 | --ignore-installed
59 | ```
60 | 
61 |
62 | ### Install devstack
63 | using `stack.sh` to install devstack.
64 | ```bash
65 | ./stack.sh
66 | ```
67 |
68 | !!! Warning
69 | will take a 15-20 minutes to install a lot of dependencies
70 |
71 | 정상적으로 완료가 되면 다음과 같은 메시지를 확인 할 수 있다.
72 |
73 | ```bash
74 | =================
75 | Async summary
76 | =================
77 | Time spent in the background minus waits: 342 sec
78 | Elapsed time: 1369 sec
79 | Time if we did everything serially: 1711 sec
80 | Speedup: 1.24982
81 |
82 | This is your host IP address: 172.31.2.38
83 | This is your host IPv6 address: ::1
84 | Horizon is now available at http://172.31.2.38/dashboard
85 | Keystone is serving at http://172.31.2.38/identity/
86 | The default users are: admin and demo
87 | The password: cloudacode
88 |
89 | Services are running under systemd unit files.
90 | For more information see:
91 | https://docs.openstack.org/devstack/latest/systemd.html
92 |
93 | DevStack Version: xena
94 | OS Version: Ubuntu 20.04 focal
95 | ```
96 |
97 | ## 4. Access Openstack dashboard
98 |
99 | [EC2 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2#Instances:instanceState=running)
100 | 에서 **Public IPv4 address** 확인 혹은 리눅스 커멘드로 `curl ifconfig.me` 후 해당 IP에 HTTP로 접속 및 페이지 확인
101 |
102 | !!! Note
103 | ID: admin, PW: cloudacode
104 |
105 | 
106 |
107 | ## 5. Create an instance
108 |
109 | VIDEO
110 |
111 | ## 6. Manage the instance
112 |
113 | 
114 |
115 | ```bash
116 | #Enable NAT for the instance network(02:35)
117 | sudo iptables -t nat -A POSTROUTING -o ens5 \
118 | -s 172.24.4.0/24 -j MASQUERADE
119 |
120 | #Config port forward rule to expose network(24:35)
121 | sudo iptables -t nat -A PREROUTING -p tcp -i ens5 \
122 | --dport 8000 -j DNAT --to-destination 172.24.4.185:8000
123 | ```
124 |
125 | VIDEO
126 |
127 | 🎉 Congratulations, you have completed Openstack tutorial
128 |
129 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
130 |
131 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/docs/cloud/aws/aws-elasticbeanstalk.md:
--------------------------------------------------------------------------------
1 | # Deploy a Flask app on Amazon ElasticBeanstalk
2 |
3 | **Amazon ElasticBeanstalk로 Python Flask App 배포 실습**
4 |
5 | 이번 실습은 Amazon Elastic Beanstalk을 통해 웹앱을 구성 해보는 실습입니다. AWS에서 가장 대표적인 PaaS인 ElasticBeanstalk를 운영하는 방법과 코드 배포 방법을 이해할 수 있습니다.
6 |
7 | 
8 |
9 | **Time to Complete: 0.5 hours**
10 |
11 |
17 |
18 | **Tutorial Prereqs:**
19 |
20 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
21 | * **AWS Cloud9**
22 | [생성 가이드](./cloud9-python-docker.md)
23 | * **AWS EB CLI 설치**
24 | [설치 페이지](https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/eb-cli3-install-advanced.html)
25 | ```bash
26 | $ pip install awsebcli --upgrade --user
27 | $ eb --version
28 | EB CLI 3.20.3 (Python 3.7.1)
29 | ```
30 |
31 | ## 1. ElasticBeanstalk 구성
32 |
33 | [Amazon Elastic Beanstalk](https://ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2#/welcome)
34 |
35 | ### Sample Code
36 | 
37 |
38 | Flask [sample](https://github.com/cloudacode/FlaskIntroduction)
39 | ```bash
40 | $ git clone https://github.com/cloudacode/FlaskIntroduction
41 | $ cd FlaskIntroduction
42 | # 이번 실습에서는 build 자동화를 연동을 하지 않으며 Warning 메시지를 피하기 위해 buildspec 파일 삭제
43 | $ rm -rf buildspec.yml
44 | ```
45 |
46 | ### EB Application 및 environment 배포
47 |
48 | ```bash
49 | $ eb init -p python-3.7 flask-todo-demo --region ap-northeast-2
50 | Application flask-todo has been created.
51 | ```
52 |
53 | ### EB Environment 배포
54 |
55 | ```bash
56 | $ eb create flask-todo-demo --vpc.elbpublic
57 | ```
58 | 
59 |
60 | 만약 특정 VPC에 배포를 하고 싶은 경우는 vpc 옵션을 추가적으로 부여
61 |
62 | ```bash
63 | $ eb create flask-todo-demo -r ap-northeast-2 --vpc.id \
64 | --vpc.elbsubnets --vpc.ec2subnets \
65 | --vpc.publicip --vpc.elbpublic
66 | ```
67 |
68 | 만약 Database 까지 함께 배포를 하고 싶은 경우는 `-db` 옵션을 추가
69 |
70 | !!! WARN
71 | ElasticBeanstalk를 생성하면서 DB를 함께 생성하는 경우 추후에 EB 삭제시 DB도 함께 삭제가 되므로 RDS는 별도로 생성 해서 연동 하는 것을 추천
72 |
73 | ### (옵션) EB 환경변수 설정
74 |
75 | 추후 EB에 환경 변수를 함께 전달 하고 싶은 경우
76 |
77 | ```bash
78 | $ mkdir -p .ebextensions
79 | $ cat <<'EOF' > .ebextensions/options.config
80 | option_settings:
81 | - option_name: DB_HOST
82 | value: eb-rds
83 | - option_name: DB_NAME
84 | value: todo
85 | EOF
86 | ```
87 |
88 | ### EB 배포 확인 및 로그
89 |
90 | [Elastic Beanstalk 환경 관리 CLI](https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/eb-cli3-getting-started.html#ebcli3-basics-create)
91 |
92 | ```bash
93 | # 로그 확인
94 | $ eb logs
95 | # EB 상태 확인
96 | $ eb status
97 | Environment details for: flask-todo-demo
98 | Application name: flask-todo-demo
99 | Region: ap-northeast-2
100 | Deployed Version: app-a696-221024_235944023808
101 | Environment ID: e-mdcmmemta3
102 | Platform: arn:aws:elasticbeanstalk:ap-northeast-2::platform/Python 3.7 running on 64bit Amazon Linux 2/3.4.0
103 | Tier: WebServer-Standard-1.0
104 | CNAME: flask-todo-demo.eba-3htsmntp.ap-northeast-2.elasticbeanstalk.com
105 | Updated: 2022-10-25 00:04:06.247000+00:00
106 | Status: Ready
107 | Health: Green
108 | ```
109 |
110 | 해당 `CNAME`을 브라우저에서 접속하여 정상적으로 접근 되는지 확인
111 |
112 |
113 | ## 2. 애플리케이션 수정 및 EB 재배포
114 |
115 | ### 코드 수정
116 |
117 | FlaskIntroduction/static/css/main.css 에 background-color를 lightblue로 변경
118 |
119 | ```
120 | body, html {
121 | margin: 0;
122 | font-family: sans-serif;
123 | background-color: lightblue;
124 | }
125 | ```
126 |
127 | git 에 수정 내역 커밋
128 | ```bash
129 | $ git add static/css/main.css
130 | $ git commit -m "change bg to lightblue"
131 | ```
132 |
133 | ### EB 재배포
134 |
135 | ```bash
136 | $ eb deploy
137 | ```
138 | 
139 |
140 |
141 | ## 3. 환경 삭제
142 |
143 | [Elastic Beanstalk Environments 콘솔](https://ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2#/environments)에서 환경 삭제
144 |
145 | 혹은
146 | ```bash
147 | $ eb terminate
148 | ```
149 |
150 | 🎉 Congratulations, you have completed Deploying a Flask Application to Elastic Beanstalk
151 |
152 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
153 |
154 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/docs/cloud/aws/aws-autoscaling-group.md:
--------------------------------------------------------------------------------
1 | # Amazon EC2 Auto Scaling
2 |
3 | **Amazon EC2 Auto Scaling 구성 실습**
4 |
5 | 이번 실습은 Amazon EC2 Auto Scaling을 통해 리소스 사용량에 맞게 자동 확장 축소를 해보는 실습입니다. AWS에서 가장 기본이 되는 EC2를 탄력적으로 운영하는 방법과 Auto Scaling 설정 구성을 이해할 수 있습니다.
6 |
7 | 
8 |
9 | **Time to Complete: 0.5 hours**
10 |
11 |
17 |
18 | **Tutorial Prereqs:**
19 |
20 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
21 |
22 | ## 1. Launch Template 구성
23 |
24 | ### Launch Template 설정
25 |
26 | [Launch Template 생성 페이지](https://ap-northeast-2.console.aws.amazon.com/ec2/home?region=ap-northeast-2#LaunchTemplates:) 혹은
27 |
28 | [AutoScalingGroup 생성 페이지](https://ap-northeast-2.console.aws.amazon.com/ec2/home?region=ap-northeast-2#CreateAutoScalingGroup:)에서 launch template 생성
29 | 
30 |
31 | - 시작 템플릿의 이름을 입력하고 초기 버전에 대한 설명을 추가
32 | - Autoscaling에서 활용할 Template이므로 Auto Scaling guidance 활성화
33 | - EC2 Image 설정
34 | 
35 | - Instance type: t2.nano (512 MB RAM, 1 vCPUs)
36 | - Key pair: 기존에 EC2 접속때 사용하던 key 선택 (없다면 생성 가능)
37 | - Network Settings
38 | 
39 | - Storage: Default
40 | - Advanced Details > User data
41 | ```bash
42 | #!/bin/bash
43 | yum update -y
44 | yum install -y httpd
45 | echo " Hello World from $(hostname -f) " > /var/www/html/index.html
46 | systemctl start httpd
47 | systemctl enable httpd
48 | ```
49 | 
50 |
51 | 
52 |
53 | [LaunchTemplate AWS 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/home?region=ap-northeast-2#LaunchTemplates:) 에서 확인 가능
54 |
55 | ## 2. Auto Scaling Groups 구성
56 |
57 | ### Auto Scaling Groups 설정
58 |
59 | [Auto Scaling Group 생성 페이지](https://ap-northeast-2.console.aws.amazon.com/ec2/home?region=ap-northeast-2#AutoScalingGroups:)
60 |
61 | - Auto Scaling 그룹 이름 입력 및 Launch template(시작 템플릿) 선택
62 | - Network
63 | 
64 | - Advanced option 에서 LoadBalancer 추가
65 | 
66 | - Min/Max 값 설정 및 CPU Trigger policy를 10으로 조정
67 | 
68 | - Review 및 Create Autoscaling group 진행
69 |
70 | ## 3. 서비스 확인
71 |
72 | [LoadBalancer 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/home#LoadBalancers:sort=loadBalancerName)에서 LB 및 [EC2 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/)에서 1개의 instance가 생성 됬는지 확인
73 |
74 | !!! WARN
75 | 생성된 LB의 Default Security Group의 Rule에 80 port가 열려있지 않다면 수동으로 추가 필요
76 |
77 | LB와 EC2의 상태가 `RUNNING` 으로 변경 되었으면 `Public DNS or IP`로 서비스 접속
78 |
79 | 해당 `URL`을 브라우저에서 접속하여 정상적으로 서비스 중인지 확인
80 |
81 | ```bash
82 | curl my-first-asg-1-190530202.ap-northeast-2.elb.amazonaws.com
83 |
84 | Hello World from ip-10-0-1-132.ap-northeast-2.compute.internal
85 | ```
86 |
87 | ## 4. 부하 생성
88 |
89 | AutoScaling Group이 설정 한 대로 운영이 되는지 확인을 위해 만들어진 EC2 인스턴스에 Stress test 진행
90 |
91 | [EC2 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/)에서 생성된 instance로 SSH 접속
92 |
93 | ```bash
94 | # install stress on Amazon Linux
95 | sudo amazon-linux-extras install epel -y
96 | sudo yum install stress -y
97 |
98 | # run CPU stress
99 | sudo stress -c 70
100 | ```
101 |
102 | ASG 콘솔 Monitoring 탭에서 EC2 instance의 CPU가 올라가는 것을 확인 가능
103 | 
104 |
105 | Activity log에서 자동으로 scaling이 되는 것을 확인
106 | 
107 | 
108 |
109 | LB Endpoint에서 새로운 인스턴스(총 3대)로 트레픽이 벨런싱 되는지 확인
110 | 
111 |
112 | ## 5. 환경 삭제
113 |
114 | [Auto Scaling 그룹](https://console.aws.amazon.com/ec2/v2/home?#AutoScalingGroups)을 삭제
115 |
116 | [LoadBalancer 콘솔](https://ap-northeast-2.console.aws.amazon.com/ec2/home#LoadBalancers:sort=loadBalancerName)에서 LB 삭제
117 |
118 | 🎉 Congratulations, you have completed AWS Autoscaling Tutorial
119 |
120 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
121 |
122 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/docs/devops/cicd/aws-codepipeline-delivery-eb.md:
--------------------------------------------------------------------------------
1 | # Continuous delivery - AWS CodePipeline - ElasticBeanstalk
2 |
3 | **개발 빌드 및 배포 환경 자동화 실습**
4 |
5 | CI/CD Pipeline 도구를 통해 소스 관리, 도커 빌드 자동화, 서비스 배포 까지 자동화
6 |
7 | **Time to Complete: 2-3 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | [CI Integration](./github-aws-codebuild-dockerhub.md)
12 |
13 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
14 |
15 | ## System Architecture
16 | 
17 |
18 |
24 |
25 | ## 1. Setup ElasticBeanstalk
26 |
27 | [ElasticBeanstalk Console](https://ap-northeast-2.console.aws.amazon.com/elasticbeanstalk/home?region=ap-northeast-2#/welcome)
28 |
29 | ### Create Application(Create a Web app)
30 |
31 | 1. Application Name
32 | 2. Platform: Docker, Platform Branch: Docker running...Amazon Linux 2, Platform version: Recommended
33 | 3. Application Code: Sample application
34 |
35 | EB(ElasticBeanstalk) app 생성 확인까지 약 5분 소요
36 |
37 | ## 2. Update the Buildspec file for EB
38 |
39 | CodePipline의 명세서 buildspec.yml 을 작성
40 |
41 | [앞 실습](./github-aws-codebuild-dockerhub.md)에서 만들었던 Buidspec 파일에 Elastic Beanstalk에서 실행할 docker image 정보를 artifact로 넘겨주기 위한 설정을 추가
42 |
43 | ```yaml
44 | - echo Writing image definitions file...
45 | - printf '{"AWSEBDockerrunVersion":"1","Image":{"Name":"%s"},"Ports":[{"ContainerPort":"5000"}]}' $IMAGE_REPO_NAME:$TAG > Dockerrun.aws.json
46 | artifacts:
47 | files: Dockerrun.aws.json
48 | ```
49 |
50 | 예시)
51 | ```bash
52 | version: 0.2
53 |
54 | phases:
55 | pre_build:
56 | commands:
57 | - echo Logging in to Docker Hub...
58 | - docker login -u $DOCKERHUB_USER -p $DOCKERHUB_PW
59 | - TAG="$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | head -c 8)"
60 | build:
61 | commands:
62 | - echo Build started on `date`
63 | - echo Building the Docker image...
64 | - docker build -t $IMAGE_REPO_NAME:$TAG .
65 | - docker tag $IMAGE_REPO_NAME:$TAG $IMAGE_REPO_NAME:$TAG
66 | post_build:
67 | commands:
68 | - echo Build completed on `date`
69 | - echo Pushing the Docker image...
70 | - docker push $IMAGE_REPO_NAME:$TAG
71 | - echo Writing image definitions file...
72 | - printf '{"AWSEBDockerrunVersion":"1","Image":{"Name":"%s"},"Ports":[{"ContainerPort":"5000"}]}' $IMAGE_REPO_NAME:$TAG > Dockerrun.aws.json
73 | artifacts:
74 | files: Dockerrun.aws.json
75 | ```
76 |
77 | !!! note
78 | 만약 본인이 작성한 application의 port가 `8000`이 아니라면 본인 포트에 맞게 변경 필요!
79 | e.g., `{"ContainerPort":"3000"}`
80 |
81 | ## 3. Setup codepipeline
82 |
83 | [CodePipeline console](https://ap-northeast-2.console.aws.amazon.com/codesuite/codepipeline/pipelines)
84 |
85 | ### Step 1: Pipeline settings
86 | 1. Pipeline Name
87 | 2. Service Role: New Service Role
88 | 3. Role Name: `AWSCodePipelineServiceRole-ap-northeast-2-[Pipeline Name]`
89 | - AWS CodePipeline이 이 새 파이프라인에 사용할 서비스 역할을 생성하도록 허용 활성화
90 |
91 | ### Step 2: Source Stage
92 | 1. 소스: Github(Version 1), 내 GitHub 계정의 리포지토리
93 | - Github v2가 권고 사항이나 실습은 v1로 진행: [v2 변경시 참고](https://docs.aws.amazon.com/ko_kr/codepipeline/latest/userguide/update-github-action-connections.html)
94 | 2. Repository, Branch: 본인의 Repo, 원하는 Branch name e.g., main, dev, release
95 | 3. Detection option: GitHub Webhook(recommended)
96 |
97 | ### Step 3: Build Stage
98 |
99 | [앞 실습](./github-aws-codebuild-dockerhub.md)
100 | 에서 설정한 codebuild 프로젝트 활용, 만약 새로운 codebuild project를 생성할 경우 앞 실습 가이드라인에 따라서 프로젝트 생성
101 |
102 | ### Step 4: Deploy Stage
103 | 1. Provider: AWS Elastic Beanstalk
104 | 2. Application Name, Environment Name: 위에서 자동 생성한 [EB 정보](#create-applicationcreate-a-web-app)
105 |
106 | ## 4. Verify CodePipeline
107 |
108 | ### 테스트 Pull Request/Merge
109 |
110 | 별도의 Branch를 만들어 flask-app의 코드 변경(예, style.css 배경 변경) 후 main branch로 PR 수행.
111 |
112 | https://ap-northeast-2.console.aws.amazon.com/codesuite/codepipeline/pipelines
113 |
114 | Pipeline 도구가 변경 사항을 인지하여 자동으로 빌드/배포가 수행 되는지 확인
115 |
116 | ### ElasticBeanstalk 환경 URL 확인
117 |
118 | EB의 애플리케이션 [환경 URL](#create-applicationcreate-a-web-app) 확인 후 정상적으로 웹페이지에 변경이 일어났는지 확인
119 |
120 | 🎉 Congratulations, you have completed Continuous delivery - AWS CodePipeline tutorial
121 |
122 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
123 |
124 |
130 |
131 |
132 |
133 | ## 참고 자료
134 |
135 | - https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/single-container-docker-configuration.html#docker-configuration.no-compose
136 | - https://d1.awsstatic.com/whitepapers/DevOps/practicing-continuous-integration-continuous-delivery-on-AWS.pdf
137 | - https://docs.aws.amazon.com/codebuild/latest/userguide/sample-elastic-beanstalk.html#sample-elastic-beanstalk-codepipeline
138 | - https://docs.aws.amazon.com/ko_kr/codepipeline/latest/userguide/tutorials-four-stage-pipeline.html#tutorials-four-stage-pipeline-prerequisites-jenkins-configure
139 |
--------------------------------------------------------------------------------
/docs/devops/cicd/aws-codepipeline-delivery-ecs.md:
--------------------------------------------------------------------------------
1 | # Continuous delivery - AWS CodePipeline - ECS
2 |
3 | **개발 빌드 및 배포 환경 자동화 실습**
4 |
5 | CI/CD Pipeline 도구를 통해 소스 관리, 도커 빌드 자동화, 서비스 배포 까지 자동화
6 |
7 | **Time to Complete: 2-3 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | [CI Integration](./github-aws-codebuild-dockerhub.md)
12 |
13 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
14 |
15 | ## System Architecture
16 | 
17 |
18 |
24 |
25 | ## 1. Setup Elastic Container Service
26 |
27 | [Setup ECS](../../cloud/aws/aws-ecs-container.md)
28 |
29 | ## 2. Update the Buildspec file for ECS
30 |
31 | CodePipline의 명세서 buildspec.yml 을 작성
32 |
33 | [앞 실습](./github-aws-codebuild-dockerhub.md) 에서 만들었던 Buidspec 파일에 ECS에서 실행할 docker image 정보를 artifact로 넘겨주기 위한 설정을 추가
34 |
35 | ```yaml
36 | - echo Writing image definitions file...
37 | - printf '[{"name":"cloudacode-freecode-todo","imageUri":"%s"}]' $IMAGE_REPO_NAME:$TAG > imagedefinitions.json
38 | artifacts:
39 | files: imagedefinitions.json
40 | ```
41 |
42 | !!! WARN
43 | imagedefinitions.json에 name에 들어가는 값은 ECS TaskDefinition에서 정의한 Container Name과 동일 해야한다
44 |
45 | 예시)
46 | ```bash
47 | version: 0.2
48 |
49 | phases:
50 | pre_build:
51 | commands:
52 | - echo Logging in to Docker Hub...
53 | - docker login -u $DOCKERHUB_USER -p $DOCKERHUB_PW
54 | - TAG=$TAG_VERSION
55 | build:
56 | commands:
57 | - echo Build started on `date`
58 | - echo Building the Docker image...
59 | - docker build -t $IMAGE_REPO_NAME:$TAG .
60 | - docker tag $IMAGE_REPO_NAME:$TAG $IMAGE_REPO_NAME:$TAG
61 | post_build:
62 | commands:
63 | - echo Build completed on `date`
64 | - echo Pushing the Docker image...
65 | - docker push $IMAGE_REPO_NAME:$TAG
66 | - echo Writing image definitions file...
67 | - printf '[{"name":"cloudacode-freecode-todo","imageUri":"%s"}]' $IMAGE_REPO_NAME:$TAG > imagedefinitions.json
68 | artifacts:
69 | files: imagedefinitions.json
70 | ```
71 |
72 | ## 2. Setup Code Connection
73 | [Code Connection console](https://ap-northeast-2.console.aws.amazon.com/codesuite/settings/connections)
74 |
75 | Connections -> Create Connection
76 | - Select a Provider: GitHub
77 | - Connection name: 커넥션 이름
78 |
79 | Install a new app -> 본인 Repo 선택
80 | 
81 |
82 | Github에 app이 연동 되면 다음과 같이 connection을 확인 가능
83 | 
84 |
85 | ## 3. Setup codepipeline
86 |
87 | [CodePipeline console](https://ap-northeast-2.console.aws.amazon.com/codesuite/codepipeline/pipelines)
88 |
89 | ### Step 1: Pipeline settings
90 | 1. Pipeline Name
91 | 2. Service Role: New Service Role
92 | 3. Role Name: `AWSCodePipelineServiceRole-ap-northeast-2-[Pipeline Name]`
93 | - AWS CodePipeline이 이 새 파이프라인에 사용할 서비스 역할을 생성하도록 허용 활성화
94 |
95 | ### Step 2: Source Stage
96 | 1. 소스: Github(Version 2), 내 GitHub 계정의 리포지토리 Connection
97 |
98 | !!! INFO
99 | Connection이 없는 경우 2. Setup Code Connection 작업 다시 수행
100 |
101 | 2. Repository, Branch: 본인의 Repo, 원하는 Branch name e.g., main, dev, release
102 | 3. Detection option: Start the pipeline on source code change
103 | 4. Output artifact format: CodePipeline default
104 |
105 | ### Step 3: Build Stage
106 |
107 | [앞 실습](./github-aws-codebuild-dockerhub.md)
108 | 에서 설정한 codebuild 프로젝트 활용, 만약 새로운 codebuild project를 생성할 경우 앞 실습 가이드라인에 따라서 프로젝트 생성
109 |
110 | ### Step 4: Deploy Stage
111 | 1. Provider: Amazon ECS
112 | 2. Region: Asia Pacific(Seoul)
113 | 3. Cluster Name: [ECS 실습](../../cloud/aws/aws-ecs-container.md)에서 생성한 클러스터 지정
114 | 4. Service Name: [ECS 실습](../../cloud/aws/aws-ecs-container.md)에서 생성한 서비스 지정
115 | 5. Image definitions file, Deployment timeout: 변경 사항 없음
116 |
117 | ## 4. Verify CodePipeline
118 |
119 | ### 테스트 Pull Request/Merge
120 |
121 | 별도의 Branch를 만들어 flask-app의 코드 변경(예, style.css 배경 변경) 후 main branch로 PR 수행.
122 |
123 | https://ap-northeast-2.console.aws.amazon.com/codesuite/codepipeline/pipelines
124 |
125 | Pipeline 도구가 변경 사항을 인지하여 자동으로 빌드/배포가 수행 되는지 확인
126 |
127 | 
128 |
129 | ### DockerHub에 신규 이미지 확인
130 |
131 | [DockerHub](https://hub.docker.com/) 본인 프로젝트 Repo에 신규 Image가 정상적으로 업로드 되었는지 확인
132 |
133 | ### ECS 환경 URL 확인
134 |
135 | ECS [Cluster Console](https://ap-northeast-2.console.aws.amazon.com/ecs/home?region=ap-northeast-2#/clusters) 에서 Task Definition이 업데이트 된 버전으로 배포가 일어났는지 확인
136 |
137 | ### 환경 삭제
138 |
139 | ECS [Cluster Console](https://ap-northeast-2.console.aws.amazon.com/ecs/home?region=ap-northeast-2#/clusters)와 [CodePipeline console](https://ap-northeast-2.console.aws.amazon.com/codesuite/codepipeline/pipelines) 에서 실습 프로젝트 삭제
140 |
141 | 🎉 Congratulations, you have completed Continuous delivery - AWS CodePipeline ECS tutorial
142 |
143 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
144 |
145 |
151 |
152 |
153 |
154 | ## 참고 자료
155 |
156 | - https://d1.awsstatic.com/whitepapers/DevOps/practicing-continuous-integration-continuous-delivery-on-AWS.pdf
157 |
--------------------------------------------------------------------------------
/docs/python/flask/simple-flask-app-mariadb.md:
--------------------------------------------------------------------------------
1 | # A Simple REST Flask APP with MariaDB Container
2 |
3 | In this tutorial, you will learn how to build a Flask web application and implement the app with database(MariaDB). using postman to test basic REST APIs(HTTP methods: GET, POST, DELETE).
4 |
5 | Flask로 Web App을 개발을 하고 데이터베이스와 연동을 하는 방법을 알아본다. CURL을 사용 하여 기본적인 REST API(HTTP methods: GET, POST, DELETE)를 테스트 해본다.
6 |
7 | **Time to Complete: 1-2 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | - Download stable [POSTMAN](https://www.postman.com/downloads/)
12 | - Python 3.x
13 | - Python Library [requirement.txt](https://github.com/cloudacode/coolstuff/blob/main/flask-example/simple-flask-app/requirements.txt)
14 |
15 | flask
16 | pymysql
17 | flask_table
18 | flask-mysql
19 |
20 | - Download stable [Docker](https://docs.docker.com/get-docker/)
21 |
22 | ## Architecture
23 |
24 | 
25 |
26 | ## 1. Create a container test network
27 |
28 | ```bash
29 | docker network create test-net
30 | ```
31 | `test-net` is newly created docker network for this tutorial (other than bridge as the default network)
32 |
33 | ## 2. Provision a DB container
34 |
35 | ### Start predefined mariadb container
36 |
37 | ```bash
38 | docker run -p 3306:3306 --name my-mariadb --net test-net -d cloudacode/simple-mariadb:latest
39 | ```
40 |
41 | dockerfile of the cloudacode/mariadb: [simple-mariadb-container](https://github.com/cloudacode/coolstuff/tree/main/flask-example/simple-mariadb-app)
42 |
43 | !!! Note
44 | If you want to setup the database by yourself, please follow below guideline.
45 |
46 | ### (Optional) Start a mariadb instance from scratch
47 |
48 | #### Deploy new MariaDB container
49 |
50 | ```bash
51 | docker run -p 3306:3306 --name my-mariadb --net test-net \
52 | -e MYSQL_ROOT_PASSWORD=mysecret -e MYSQL_DATABASE=cloud_user \
53 | -d mariadb:latest
54 | ```
55 |
56 | !!! Note
57 | mariadb official repo: https://hub.docker.com/_/mariadb
58 |
59 | #### Initalize the database
60 |
61 | connect to db container and database
62 | ```bash
63 | docker exec -it my-mariadb /bin/bash
64 | ```
65 |
66 | If you can see `root@b51599196adf:/#` in your terminal, it means you are in the container.
67 |
68 | login the database via mysql client and initialize the database
69 |
70 | ```bash
71 | mysql -uroot -pmysecret
72 | ```
73 |
74 | ```bash
75 | MariaDB [(none)]> use cloud_user;
76 | Database changed
77 | MariaDB [cloud_user]>
78 | MariaDB [cloud_user]> CREATE TABLE IF NOT EXISTS `cloud_user` (
79 | `user_id` bigint NOT NULL AUTO_INCREMENT,
80 | `user_name` varchar(45) DEFAULT NULL,
81 | `user_email` varchar(45) DEFAULT NULL,
82 | `user_bio` varchar(255) DEFAULT NULL,
83 | PRIMARY KEY (`user_id`)
84 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ;
85 |
86 | Query OK, 0 rows affected, 1 warning (0.001 sec)
87 |
88 | MariaDB [cloud_user]> select * from cloud_user;
89 | Empty set (0.001 sec)
90 |
91 | MariaDB [cloud_user]> INSERT INTO `cloud_user` (
92 | `user_id`,`user_name`,`user_email`, `user_bio`)
93 | values
94 | (1,'kc chang','cloudacode@gmail.com', 'mento');
95 |
96 | Query OK, 1 row affected (0.001 sec)
97 |
98 | MariaDB [cloud_user]>
99 | MariaDB [cloud_user]> select * from cloud_user;
100 | +---------+-----------+----------------------+----------+
101 | | user_id | user_name | user_email | user_bio |
102 | +---------+-----------+----------------------+----------+
103 | | 1 | kc chang | cloudacode@gmail.com | mento |
104 | +---------+-----------+----------------------+----------+
105 | 1 row in set (0.000 sec)
106 |
107 | ```
108 |
109 | ## 3. Build the Flask app
110 |
111 | to run the flask app in your local environment, you should build the flask app first.
112 |
113 | source code: [cloudacode/coolstuff.git](https://github.com/cloudacode/coolstuff)
114 |
115 | ```bash
116 | git clone https://github.com/cloudacode/coolstuff.git
117 | cd flask-example/simple-flask-app
118 | docker build -t cloudacode/simple-flask-app:latest .
119 | ```
120 |
121 | !!! Note
122 | you can change the `cloudacode` to your dockerhub repo name
123 |
124 | ## 4. Run the Flask app
125 |
126 | Run the flask app on your localhost or dev machine
127 |
128 | ```bash
129 | docker run -p 8888:5000 --net test-net \
130 | -e DB_USER=root -e DB_PASSWORD=mysecret -e DB_NAME=cloud_user -e DB_HOST=simple-mariadb \
131 | cloudacode/simple-flask-app:latest
132 | ```
133 | OR
134 | ```bash
135 | docker run -p 8888:5000 --net test-net \
136 | --env-file ./env.list cloudacode/simple-flask-app:latest
137 | ```
138 |
139 | !!! Note
140 | If you are using your own password or database name, you need to replace the vaule in the `env.list` file
141 |
142 | ## 5. Test API request
143 |
144 | get date from the server. you can also use the web browser to get the date
145 | ```bash
146 | curl localhost:8888/user
147 | ```
148 |
149 | review the output. here is the expected output message
150 | ```json
151 | [
152 | {
153 | "user_bio": "mento",
154 | "user_email": "cloudacode@gmail.com",
155 | "user_id": 1,
156 | "user_name": "kc chang"
157 | }
158 | ]
159 | ```
160 |
161 | post Json data to the server
162 | ```bash
163 | curl --header "Content-Type: application/json" \
164 | --request POST \
165 | --data '{"bio": "test user", "email": "test1@cloudacode.com", "name": "test1"}' \
166 | http://localhost:8888/add
167 | ```
168 |
169 | get the user list again from the server
170 | ```bash
171 | curl localhost:8888/user
172 | ```
173 |
174 | ## 6. Docker Compose
175 |
176 | Install Docker Compose: [link](https://docs.docker.com/compose/install/)
177 |
178 | ```yaml
179 | version: "2"
180 | services:
181 | simple-mariadb:
182 | image: cloudacode/simple-mariadb:latest
183 | ports:
184 | - "3306:3306"
185 | simple-flask-app:
186 | links:
187 | - simple-mariadb
188 | image: cloudacode/simple-flask-app:latest
189 | ports:
190 | - "8888:5000"
191 | environment:
192 | - DB_USER=root
193 | - DB_PASSWORD=mysecret
194 | - DB_NAME=cloud_user
195 | - DB_HOST=simple-mariadb
196 | ```
197 | docker-compose.yaml
198 |
199 | Run docker compose to up all containers
200 | ```
201 | docker-compose up -d
202 | ```
203 |
204 | 🎉 Congratulations, you have completed Flask, MariaDB integration tutorial
205 |
--------------------------------------------------------------------------------
/docs/cloud/aws/aws-emr-spark-bigdata.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Amazon EMR, Apache Spark, Zepplin으로 빅데이터 분석
3 | description: Amazon EMR, Spark, Zepplin을 통해 1억개가 넘는 비행 노선 정보를 가지고 가장 많이 출항 하고 도착하는 도시와 비행정보 그리고 지연된 이력 등을 시각적으로 표현하는 시스템을 구성 하여 원하는 결과를 도출 하여 본다
4 | image: https://raw.githubusercontent.com/cloudacode/tutorials/main/docs/cloud/aws/assets/emr-spark-zepplin.png
5 | ---
6 |
7 | # Analysis BigData through Amazon EMR, Apache Spark, Zepplin
8 |
9 | **Amazon EMR, Apache Spark, Zepplin으로 빅데이터 분석 하기**
10 |
11 | 이번 실습은 Amazon EMR, Spark, Zepplin을 통해 1억개가 넘는 비행 노선 정보를 가지고 가장 많이 출항 하고 도착하는 도시와 비행정보 그리고 지연된 이력 등을 시각적으로 표현하는 시스템을 구성 하여 원하는 결과를 도출 하여 본다.
12 |
13 | **Time to Complete: 0.5 hours**
14 |
15 | ## Architecture
16 | 
17 |
18 |
24 |
25 | ## Objective
26 | - 빅데이터 분석 시스템의 기본적인 구조와 활용 가능 범위를 파악한다.
27 | - 빅데이터 파이프라인(생성, 수집/저장, 분석/가공, 공유/전달)에서 AWS의 활용 요소를 파악한다.
28 | - Zepplin을 통해 Spark 분석엔진을 손쉽게 관리하고 효과적으로 결과를 표현하는 방안을 파악한다.
29 |
30 | ## Concepts
31 | - EMR: 방대한 양의 데이터를 처리 및 분석을 위한 빅데이터 클러스터 플랫폼 이며 Apache Hadoop, Apache Spark을 지원 [What is Amazon EMR?](https://docs.aws.amazon.com/ko_kr/emr/latest/ManagementGuide/emr-what-is-emr.html)
32 | - Spark: Apache Spark는 빅 데이터 워크로드에 주로 사용되는 오픈 소스 분산 처리 시스템. 빠른 성능을 위해 인 메모리 캐싱과 최적화된 실행을 사용하며, 일반 배치 처리, 스트리밍 분석, 기계 학습, 그래프 데이터베이스 및 임시 쿼리를 지원
33 | - Zepplin: 커멘드라인 형태의 Spark 데이터 분석을 Web적으로 표현하는 어플리케이션
34 |
35 | 
36 |
37 | ## 1. EMR Cluster 생성(Spark)
38 |
39 | ### EMR Cluster의 기본적인 스펙과 확장 범위를 설정
40 |
41 | [EMR 스펙 페이지](https://aws.amazon.com/emr/pricing/?nc=sn&loc=4)
42 |
43 | !!! Info
44 | 실습은 r3.xlarge 스펙(30.5 GiB RAM, 4 vCPUs)의 온디맨드 인스턴스 **3대**로 진행, $0.399/hr x 3
45 |
46 |
47 | [EMR 콘솔](https://ap-northeast-2.console.aws.amazon.com/elasticmapreduce/home?region=ap-northeast-2#) 접근 후 다음과 같이 클러스터 생성
48 |
49 | 
50 |
51 | - Cluster Name: 사용할 클러스터 이름
52 | - Software Configuration : 데이터분석 엔진을 선택, 실습에서는 `Spark`
53 | - Hardware Configuration : 데이터분석 엔진 Worker 노드의 사이즈 결정, 비용 절감을 위해 auto-termination 활성화 (idle after 1 hr -> 변경: `30mins`)
54 | - Security and Access: EMR 서버에 접속이 필요하지 않으면 key pair에 대해서 Proceed without an EC2 key pair 선택, SSH 접속을 원할 경우 본인의 EC2 key pair 지정
55 |
56 | 실습에서는 `on-demand`로 진행 하지만 만약 EMR 노드들을 spot instance로 비용을 최적화 진행을 하는 경우 콘솔 위에 Advanced 옵션에서 선택 가능
57 |
58 | 
59 |
60 | ### EMR Cluster의 원격 접근을 위해 Security Group 설정
61 |
62 | 
63 |
64 | 아래와 같이 My IP에 대해 8890, 22 포트를 Add Rule
65 | 
66 |
67 | ## 2. EMR Cluster 접속
68 |
69 | ### EMR Cluster에 SSH 접속(Optional)
70 |
71 | !!! INFO
72 | SSH 접속은 클러스터 생성시 Security and Access에서 key pair를 등록한 경우만 가능
73 |
74 | 지정한 Private key를 통해 Cluster endpoint에 연결
75 | 
76 |
77 | !!! INFO
78 | username: hadoop
79 |
80 | 
81 |
82 | ### Zeppelin을 통해 EMR Cluster 연결
83 |
84 | 
85 |
86 | 포트는 Master public DNS 엔드포인트에 8890 포트로 접속
87 | 
88 |
89 | ## 3. 데이터 분석
90 |
91 | 샘플 데이터: 미국 교통 정보 데이터([항공](https://catalog.data.gov/dataset/airline-on-time-performance-and-causes-of-flight-delays-on-time-data)) 약 80GB
92 | 
93 |
94 | ### 비행정보 데이터 적재 및 카운트 수행
95 |
96 | [Scala](https://spark.apache.org/docs/latest/quick-start.html)를 활용하여 쿼리를 작성
97 |
98 | !!!INFO
99 | 위 미국 교통 정보 cvs 데이터를 본인의 S3 bucket에 직접 올려서 Spark에 import도 가능 하지만 실습에서는 사전에 [Parquet](https://parquet.apache.org/) 포멧으로 압축되어 올라온 파일을 활용
100 |
101 | ```sql
102 | val parquetFile = sqlContext.read.parquet("s3://us-east-1.elasticmapreduce.samples/flightdata/input/")
103 | parquetFile.count()
104 | ```
105 |
106 | 
107 |
108 | 데이터 파일 내용중 3개만 도출
109 | ```sql
110 | parquetFile.take(3).foreach(println)
111 | ```
112 |
113 | 데이터를 Flights 테이블에 적재
114 | ```sql
115 | parquetFile.registerTempTable("flights")
116 | ```
117 |
118 | 
119 |
120 | ### 분석쿼리 - 2000년도부터 가장 출항을 많이 한 공항
121 |
122 | ```sql
123 | %sql
124 | SELECT origin, count(*) AS total_departures
125 | FROM flights
126 | WHERE year >= 2000
127 | GROUP BY origin
128 | ORDER BY total_departures
129 | DESC LIMIT 10
130 | ```
131 |
132 | 
133 |
134 | ### 분석쿼리 - 출발 지연이 가장 많았던 공항
135 |
136 | ```sql
137 | %sql
138 | SELECT origin, count(depdelayminutes) AS total_delays
139 | FROM flights
140 | WHERE depdelayminutes > 15 AND year >= 2000
141 | GROUP BY origin
142 | ORDER BY total_delays
143 | DESC LIMIT 10
144 | ```
145 |
146 | 
147 |
148 | ### Scala 분석쿼리 - 가장 출항을 많이 한 노선
149 |
150 | ```sql
151 | %sql
152 | SELECT origin, dest, count(*) AS total_flights
153 | FROM flights
154 | WHERE year >= 2000
155 | GROUP BY origin, dest
156 | ORDER BY total_flights
157 | DESC LIMIT 10
158 | ```
159 |
160 | 
161 |
162 | ## 4. 환경 삭제
163 |
164 | [EMR 콘솔](https://ap-northeast-2.console.aws.amazon.com/elasticmapreduce/home?region=ap-northeast-2#) 접근 후 클러스터 삭제
165 |
166 |
167 | 🎉 Congratulations, you have completed Amazon EMR, Apache Spark, Zepplin tutorial
168 |
169 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
170 |
171 |
177 |
178 |
--------------------------------------------------------------------------------
/docs/kubernetes/argocd-deployment.md:
--------------------------------------------------------------------------------
1 | # Implement an ArgoCD, Deploy Monitoring Pipeline
2 |
3 | **Kuberentes에 ArgoCD 연동 및 Grafana, Prometheus로 모니터링 파이프라인 구성**
4 |
5 | 이번 실습은 쿠버네틱스에 ArgoCD를 연동하여 어플리케이션을 배포 해보고 모니터링 파이프라인을 구성 해보는 실습 입니다. 쿠버네틱스에 서비스의 배포 관리를 할수 있는 도구인 ArgoCD에 대한 특성과 실제 모니터링 파이프라인을 구성해 보면서 모니터링 방법에 대해 이해 할 수 있습니다.
6 |
7 | ## 사전 준비 사항
8 |
9 | ### AWS EKS 구성
10 |
11 | Amazon EKS 구성: [관련 링크](../cloud/aws/amazon-eks-setup.md)
12 |
13 | ## Architecture
14 | 
15 |
16 |
22 |
23 | ## ArgoCD 연동
24 |
25 | ### ArgoCD 설치
26 | https://argoproj.github.io/argo-cd/getting_started/
27 |
28 | ```
29 | kubectl create namespace argocd
30 | kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
31 | ```
32 | This will create a new namespace, `argocd`, where Argo CD services and application resources will live.
33 |
34 | ### (옵션) ArgoCD CLI 설치
35 |
36 | Download the latest Argo CD version from [https://github.com/argoproj/argo-cd/releases/latest](https://github.com/argoproj/argo-cd/releases/latest).
37 |
38 | More detailed installation instructions can be found via the [CLI installation documentation](https://github.com/argoproj/argo-cd/blob/master/docs/cli_installation.md).
39 |
40 | ### ArgoCD Server 접속
41 | In order to access server via URL, need to expose the Argo CD API server. Change the argocd-server service type to `LoadBalancer`:
42 |
43 | ```bash
44 | kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
45 | ```
46 | LB Endpoint를 노출 하더라도 도메인 등록 시간이 소요 되므로 브라우저를 통한 접근이 가능하기 까지는 약 5분 소요
47 |
48 | Check the LB Endpoint
49 |
50 | ```bash
51 | kubectl get -n argocd svc argocd-server
52 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
53 | argocd-server LoadBalancer 10.100.143.242 a1521dde2ec114a4eb7fb04632cab058-1608723687.ap-northeast-2.elb.amazonaws.com 80:32511/TCP,443:31088/TCP 17m
54 | ```
55 |
56 | Also available to get the external LB endpoint as a raw value:
57 |
58 | ```bash
59 | kubectl get -n argocd svc argocd-server --output jsonpath='{.status.loadBalancer.ingress[0].hostname}'
60 | ```
61 |
62 | 초기 `admin` 패스워드 확인
63 | ```bash
64 | kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
65 | ```
66 | https://argoproj.github.io/argo-cd/getting_started/#4-login-using-the-cli
67 |
68 |
69 | 브라우저를 통해 LB Endpoint 에 접속
70 |
71 | !!! note
72 | SSL인증서 연동을 하지 않아 브라우저에서 사이트가 안전하지 않는다는 메시지가 발생하기 때문에 실습 때는 무시하고 진행한다.
73 |
74 | 
75 |
76 |
77 | ## ArgoCD를 통해 모니터링 App(Prometheus, Grafana) 배포
78 |
79 | 웹 콘솔에 접속후 __+ New App__ 클릭하여 신규 애플리케이션(Prometheus) 생성
80 |
81 | - GENERAL
82 | - Application Name: prometheus
83 | - Project: default
84 | - Sync Policy: Manual
85 | - SOURCE
86 | - Repo URL: https://prometheus-community.github.io/helm-charts `HELM`
87 | - Chart: prometheus `15.1.1`
88 | - DESTINATION
89 | - Cluster URL: https://kubernetes.default.svc
90 | - Namespace: default
91 |
92 | __Create__ 진행 후
93 |
94 | 화면을 새로고침 하면 다음과 같이 앱이 하나 등록 되어 Sync가 아직 되지 않은 OutOfSync 상태로 확인 된다. Sync 정책을 Manual 로 하였기 때문에 초기에 OutOfSync 상태는 정상 이다.
95 |
96 | __SYNC__ 수행 후
97 |
98 | 레포지토리 URL 이 올바르게 되어 있다면 문제 없이 sync가 완료되고 상세 페이지 역시 아래처럼 확인 가능하다
99 | 
100 |
101 | Prometheus의 ClusterIP 확인
102 |
103 | ```bash
104 | kubectl get svc prometheus-server
105 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
106 | prometheus-server ClusterIP 10.100.238.196 80/TCP 5m44s
107 | ```
108 |
109 | 다시 웹 콘솔에서 __+ New App__ 클릭하여 신규 애플리케이션(Grafana) 생성
110 |
111 | - GENERAL
112 | - Application Name: grafana
113 | - Project: default
114 | - Sync Policy: Manual
115 | - SOURCE
116 | - Repo URL: https://grafana.github.io/helm-charts `HELM`
117 | - Chart: prometheus `6.21.1`
118 | - DESTINATION
119 | - Cluster URL: https://kubernetes.default.svc
120 | - Namespace: default
121 |
122 | 아래 HELM 변수값 탭에서 `service.type` 검색 후 값을 `LoadBalancer` 로 변경
123 | 
124 |
125 | __Create__ 와 __SYNC__ 수행 후 정상적으로 애플리케이션이 만들어졌다면 admin password를 조회
126 |
127 | ```bash
128 | kubectl get secret --namespace default grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
129 | ```
130 |
131 | Endpoint 확인을 위해 ArgoCD 화면에서 Grafana 선택 후 상세페이지
132 | __Service__(화면에서는 svc grafana)의 Hostnames 항목에 앱에 접속 가능한 LB URL이 생성 되었는지 확인 후 웹 브라우져를 통해 해당 URL로 접속하여 Grafana에 접근
133 | 
134 |
135 | ### Monitoring Dashboard 구성
136 |
137 | 왼쪽 텝 __Configuration__ 에서 Data Sources 선택 후 위에서 조회한 Prometheus Cluster IP를 HTTP URL로 지정
138 | 
139 | SAVE & TEST 하여 Data Source 등록
140 |
141 |
142 | 왼쪽 텝 __+__ Import -> Upload Json File:
143 | [k8s-metric-dashboard_rev1.json](https://raw.githubusercontent.com/cloudacode/coolstuff/main/grafana-dashboard/k8s-metric-dashboard_rev1.json) 업로드
144 |
145 |
146 | Options
147 | - prometheus: `Promethesus`
148 |
149 | 아래처럼 리소스에 대한 모니터링 대쉬보드 확인
150 | 
151 |
152 |
153 | ## Clean Up
154 | 실습 완료 후 비용 절약을 위해 실습한 EKS 리소스를 정리
155 | ```
156 | eksctl delete cluster --region=ap-northeast-2 --name=
157 | ```
158 |
159 | ## Reference
160 | https://argoproj.github.io/argo-cd/getting_started
161 |
162 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
163 |
164 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/docs/devops/cicd/github-aws-codebuild-dockerhub.md:
--------------------------------------------------------------------------------
1 | # Publishing Docker images - AWS CodeBuild
2 |
3 | **개발 빌드 환경 구성 및 Container 빌드 자동화 실습**
4 |
5 | [CodeBuild](https://aws.amazon.com/codebuild/)를 통해 코드의 Pull Request가 일어나면 도커 빌드 및 [레지스트리](https://hub.docker.com/)에 이미지 등록 자동화 실습
6 |
7 | **Time to Complete: 2-3 hours**
8 |
9 | **Tutorial Prereqs:**
10 |
11 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
12 | * **Fork [cloudacode/FlaskIntroduction](https://github.com/cloudacode/FlaskIntroduction) Repository**
13 |
14 | ## System Architecture
15 | 
16 |
17 |
23 |
24 | ## 1. Create an AWS CodeBuild Project
25 |
26 | ### Make a BuildSpec file for CodeBuild
27 |
28 | 최상위 디렉토리에 CodeBuild의 작업을 정의한 `buildspec.yml`를 생성
29 |
30 | [Build Specification reference 문서](https://docs.aws.amazon.com/ko_kr/codebuild/latest/userguide/build-spec-ref.html)
31 |
32 | 예시)
33 | ```yaml
34 | version: 0.2
35 |
36 | phases:
37 | pre_build:
38 | commands:
39 | - echo Logging in to Docker Hub...
40 | - docker login -u $DOCKERHUB_USER -p $DOCKERHUB_PW
41 | - TAG=$TAG_VERSION
42 | build:
43 | commands:
44 | - echo Build started on `date`
45 | - echo Building the Docker image...
46 | - docker build -t $IMAGE_REPO_NAME:$TAG .
47 | - docker tag $IMAGE_REPO_NAME:$TAG $IMAGE_REPO_NAME:$TAG
48 | post_build:
49 | commands:
50 | - echo Build completed on `date`
51 | - echo Pushing the Docker image...
52 | - docker push $IMAGE_REPO_NAME:$TAG
53 | ```
54 |
55 | 만약 TAG 버전을 unique한 commit hash로 저장 하고 싶다면
56 | ```yaml
57 | - TAG="$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | head -c 8)"
58 | ```
59 |
60 | ### Setup the codebuild
61 |
62 | Go to [CodeBuild](https://ap-northeast-2.console.aws.amazon.com/codesuite/codebuild/projects) console
63 |
64 | 1. **Project configuration**
65 | - Project 이름 입력
66 | - Enable build badge 활성화
67 | 2. **Source**
68 | - Connecting using OAuth 로 GitHub과 연동
69 | - 만약, Personal access token으로 진행시 GitHub Personal access token 생성 필요 [참고](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token) 및 권한은 repo, admin:repo_hook [참고](https://docs.aws.amazon.com/codebuild/latest/userguide/access-tokens.html#access-tokens-github)
70 | 3. **Primary source webhook events**
71 | - Webhook: 코드 변경이 이 리포지토리에 푸시될 때마다 다시 빌드
72 | - Event Type: `PULL_REQUEST_CREATED`, `PULL_REQUEST_UPDATED`, `PULL_REQUEST_REOPENED`
73 | - 만약, 특정 Branch 이름이나 Tag로 이벤트를 감지 하고 싶다면 `Start a build under these condition`에 필터 추가 [참고 문서](https://docs.aws.amazon.com/codebuild/latest/userguide/github-webhook.html)
74 | e.g., feature/ 브랜치 이벤트만 `HEAD_REF: ^refs/heads/feature/*`
75 | 4. **환경(Environment)**
76 | - Environment image: 관리형 이미지, Amazon Linux 2, Standard, aws/codebuild/amazonlinux2-x86_64-standard:4.0
77 | - Privileged: 권한 승격 활성화 (Enable this flag if you want to build Docker images or want your builds to get elevated privileges)
78 | - 서비스 역할: 새 서비스 역할 (Name: default e.g., codebuild-*[project_name]*-service-role)
79 | - Additional configuration 에 환경 변수 설정:
80 | - TAG_VERSION(*일반 텍스트*): `latest` , 위에서 TAG_VERSION을 commit hash로 받는 설정을 하였을 경우는 설정 필요 없음
81 | - IMAGE_REPO_NAME(*일반 텍스트*): `Docker Repo Name` e.g., cloudacode/devops-flask
82 | - DOCKERHUB_USER(*Secrets Manager*): `dockerhub:username`
83 | - DOCKERHUB_PW(*Secrets Manager*): `dockerhub:password`
84 | 
85 | !!! Note
86 | username, password 보안을 위해 Secrets Manager를 활용하여 암호 관리 필요. [참고](https://aws.amazon.com/premiumsupport/knowledge-center/codebuild-docker-pull-image-error/?nc1=h_ls#Store_your_DockerHub_credentials_with_AWS_Secrets_Manager)
87 | 5. **BuildSpec**
88 | - 상위 디렉토리에 buildspec.yml이라는 파일로 이름을 정했으므로 별도의 입력값 필요 없음
89 | 6. **Artifact**: 없음
90 | 7. **CloudWatch**: Default(CloudWatch 로그 선택)
91 |
92 | ## 2. Configure Secrets Manager
93 | Go to [SecretsManager](https://ap-northeast-2.console.aws.amazon.com/secretsmanager/home) console
94 |
95 | Store a new secret
96 |
97 | - Type: Other type of Secrets
98 | - Secret key/vale에 username: `DOCKERHUB 계정이름`, password: `DOCKERHUB 계정패스워드` 입력
99 | - Secret Name: `dockerhub`
100 | 
101 |
102 | 참고: [DockerHub 자격 증명저장](https://aws.amazon.com/premiumsupport/knowledge-center/codebuild-docker-pull-image-error/?nc1=h_ls#Store_your_DockerHub_credentials_with_AWS_Secrets_Manager)
103 |
104 | ## 3. Configure IAM policy
105 | SecretManager에서 정의한 dockerhub secret도 읽는 권한을 부여 하기 위해
106 | `CodeBuildSecretsManagerPolicy--ap-northeast-2`의 Resource에 secretsmanager dockerhub ARN 추가
107 |
108 | ### Confirm the dockerhub secrets ARN
109 |
110 | Go to [Secertmanager dockerhub ARN](https://ap-northeast-2.console.aws.amazon.com/secretsmanager/home?region=ap-northeast-2#/secret?name=dockerhub)
111 |
112 | 
113 |
114 | ### Add the dockerhub secrets resource in IAM Policy
115 |
116 | Go to [IAM Policy](https://console.aws.amazon.com/iam/home?region=ap-northeast-2#/policies) console
117 |
118 | `CodeBuildSecretsManagerPolicy--ap-northeast-2` 에서 수정 진행(JSON에서 Resource의 마지막 줄에 추가)
119 |
120 | 
121 |
122 | ## 4. Verify Codebuild Job manually
123 |
124 | 수동으로 수행 및 [Codebuild](https://ap-northeast-2.console.aws.amazon.com/codesuite/codebuild/projects) 콘솔에서 확인
125 |
126 | ### DockerHub image
127 |
128 | 이미지가 정상적으로 [DockerHub](https://hub.docker.com)에 업로드 되었는지 확인
129 |
130 |
131 | ### Pull Request 테스트
132 |
133 | 별도의 Branch를 만들어 static/css/main.css의 backgroud-color 수정 후 main으로 PR 수행 및 CI 도구가 변경 사항을 인지하여 자동으로 수행 되는지 확인
134 |
135 | 
136 |
137 | 🎉 Congratulations, you have completed Publishing Docker images - AWS CodeBuild tutorial
138 |
139 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
140 |
141 |
147 |
148 |
149 |
150 | ## 참고 자료
151 | - https://docs.aws.amazon.com/ko_kr/whitepapers/latest/introduction-devops-aws/introduction-devops-aws.pdf
152 | - https://docs.aws.amazon.com/ko_kr/whitepapers/latest/practicing-continuous-integration-continuous-delivery/practicing-continuous-integration-continuous-delivery.pdf
153 | - https://docs.aws.amazon.com/ko_kr/codebuild/latest/userguide/sample-docker.html
154 | - https://docs.aws.amazon.com/ko_kr/codebuild/latest/userguide/github-webhook.html
155 |
--------------------------------------------------------------------------------
/docs/kubernetes/minikube-todo-app.md:
--------------------------------------------------------------------------------
1 | # Deploy Todo App locally via Minikube
2 |
3 | **Minikube를 활용하여 로컬환경에 Todo App 배포**
4 |
5 | 이번 실습은 쿠버네티스에 Python flask 어플리케이션과 mariaDB를 배포 해보고 접근 해보는 실습 입니다. 쿠버네티스에 DB용 영구볼륨(PersistentVolume)구성 방법 및 어플리케이션 배포 방법과 서비스 노출 방법에 대해 이해 할 수 있습니다.
6 |
7 | ## 사전 준비 사항
8 |
9 | ### Minikube 구성
10 |
11 | Minikube 구성: [관련 링크](https://minikube.sigs.k8s.io/docs/start/)
12 |
13 | ## Architecture
14 | 
15 |
16 |
22 |
23 | ## Minikube에 Application 배포
24 |
25 | ### Minikube 실행
26 |
27 | Run `minikube start` to start minikube locally
28 |
29 | ### Todo Data Volume 생성
30 |
31 | Run `kubectl apply -f todo-mariadb-pv.yaml` to create persistent data volume for the mariadb.
32 |
33 | todo-mariadb-pv.yaml
34 | ```yaml
35 | apiVersion: v1
36 | kind: PersistentVolume
37 | metadata:
38 | name: task-data-volume
39 | labels:
40 | classname: mini
41 | spec:
42 | storageClassName: mini
43 | accessModes:
44 | - ReadWriteOnce
45 | capacity:
46 | storage: 1Gi
47 | hostPath:
48 | path: /data/task-data/
49 | ---
50 | apiVersion: v1
51 | kind: PersistentVolumeClaim
52 | metadata:
53 | name: task-data-claim
54 | labels:
55 | classname: mini
56 | spec:
57 | storageClassName: mini
58 | accessModes:
59 | - ReadWriteOnce
60 | resources:
61 | requests:
62 | storage: 500Mi
63 | ```
64 |
65 | Run `kubectl get pv,pvc -l classname=mini ` to verify the pv and pvc are created properly
66 |
67 | ```bash
68 | $ kubectl get pv,pvc -l classname=mini
69 | NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
70 | persistentvolume/task-data-volume 1Gi RWO Retain Bound default/task-data-claim mini 11s
71 |
72 | NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
73 | persistentvolumeclaim/task-data-claim Bound task-data-volume 1Gi RWO mini 11s
74 | ```
75 |
76 | ### Todo App용 Mariadb 배포
77 |
78 | Source code: [cloudacode/coolstuff/todo-mariadb](https://github.com/cloudacode/coolstuff/tree/main/todo-app/mariadb-app)
79 |
80 | Run `kubectl apply -f todo-mariadb-app.yaml` to deploy mariadb and service endpoint
81 |
82 | todo-mariadb-app.yaml
83 | ```yaml
84 | ---
85 | apiVersion: apps/v1
86 | kind: Deployment
87 | metadata:
88 | name: mysql
89 | spec:
90 | selector:
91 | matchLabels:
92 | app: mysql
93 | strategy:
94 | type: Recreate
95 | template:
96 | metadata:
97 | labels:
98 | app: mysql
99 | spec:
100 | containers:
101 | - image: cloudacode/mariadb-todo:v1.0.1
102 | name: mysql
103 | ports:
104 | - containerPort: 3306
105 | name: mysql
106 | volumeMounts:
107 | - name: task-data-storage
108 | mountPath: /var/lib/mysql
109 | volumes:
110 | - name: task-data-storage
111 | persistentVolumeClaim:
112 | claimName: task-data-claim
113 | ---
114 | apiVersion: v1
115 | kind: Service
116 | metadata:
117 | name: mysql
118 | spec:
119 | ports:
120 | - port: 3306
121 | selector:
122 | app: mysql
123 | clusterIP: None
124 | ```
125 |
126 | ### Todo App용 Flask 배포
127 |
128 | Source code: [cloudacode/coolstuff/todo-flask-app](https://github.com/cloudacode/coolstuff/tree/main/todo-app/flask-app)
129 |
130 | Run `kubectl apply -f todo-flask-app.yaml` to deploy flask app and service endpoint
131 |
132 | todo-flask-app.yaml
133 | ```yaml
134 | ---
135 | apiVersion: apps/v1
136 | kind: Deployment
137 | metadata:
138 | name: todo-app
139 | labels:
140 | app: todo-app
141 | spec:
142 | replicas: 1
143 | selector:
144 | matchLabels:
145 | app: todo-app
146 | strategy:
147 | rollingUpdate:
148 | maxSurge: 1
149 | maxUnavailable: 0
150 | type: RollingUpdate
151 | template:
152 | metadata:
153 | labels:
154 | app: todo-app
155 | spec:
156 | containers:
157 | - image: cloudacode/python-todo:v1.1.0
158 | imagePullPolicy: Always
159 | name: todo-app
160 | ports:
161 | - containerPort: 5000
162 | protocol: TCP
163 | env:
164 | - name: DB_USER
165 | value: root
166 | - name: DB_PASSWORD
167 | value: mysecret
168 | - name: DB_NAME
169 | value: todo
170 | - name: DB_HOST
171 | value: mysql
172 | ---
173 | apiVersion: v1
174 | kind: Service
175 | metadata:
176 | name: todo-app-svc
177 | spec:
178 | selector:
179 | app: todo-app
180 | ports:
181 | - protocol: TCP
182 | port: 80
183 | targetPort: 5000
184 | type: LoadBalancer
185 | ```
186 |
187 | Run `kubectl get svc` in check the exposed service. you may see the `EXTERNAL-IP` is `pending` status due to minikube doesn't have extra LB.
188 |
189 | ```bash
190 | kubectl get svc todo-app-svc
191 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
192 | todo-app-svc LoadBalancer 10.102.161.248 80:31289/TCP 54s
193 | ```
194 |
195 | You should use the `minikube tunnel` to get the external-ip for the service. [Loadbalancer Access](https://minikube.sigs.k8s.io/docs/handbook/accessing/#loadbalancer-access)
196 |
197 | ### Minikube tunnel 설정
198 |
199 | Run `minikube tunnel` in a *seperate terminal* to enable external-ip
200 |
201 | ```bash
202 | minikube tunnel
203 | ❗ The service todo-app-svc requires privileged ports to be exposed: [80]
204 | 🔑 sudo permission will be asked for it.
205 | 🏃 Starting tunnel for service todo-app-svc.
206 | Password:
207 |
208 | ```
209 |
210 | Run `kubectl get svc todo-app-svc` in check the external-ip and it will be
211 |
212 | ```bash
213 | kubectl get svc todo-app-svc
214 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
215 | todo-app-svc LoadBalancer 10.102.161.248 127.0.0.1 80:31289/TCP 5m41s
216 | ```
217 |
218 | ### Todo App 접근
219 |
220 | Open `http://127.0.0.1` in your favorite web browser and check the flask todo app
221 |
222 | 
223 |
224 | ### Todo MariaDB Pod 삭제 및 재배포
225 |
226 | 위에서 세팅한 Persistent Volume이 Pod의 내부 볼륨이 아닌 외부 스토리지 볼륨을 사용하는 것을 검증 하기 위해 pod를 삭제
227 |
228 | Run `kubectl delete pods -l app=todo-db` to delete the pod resource. Deployment resource will monitor the pod status and will spawn the pod immediately
229 |
230 | ```bash
231 | $ kubectl get pods -l app=todo-db
232 | NAME READY STATUS RESTARTS AGE
233 | todo-db-65848c57db-hwqnp 1/1 Running 0 17s
234 | ```
235 |
236 | A new todo-db pod is up and mounted node's `/data/task-data/` to `/var/lib/mysql/` volume on the pod. This means that DB data volume is managed in an external volume space.
237 |
238 | 확인을 위해 open `http://127.0.0.1` and make sure the todo data exists.
239 |
240 | ### Todo App 리소스 확장
241 |
242 | Run `kubectl scale --replicas=3 deployment/todo-app` to scale out the app
243 |
244 | ```
245 | $ kubectl scale --replicas=3 deployment/todo-app
246 | deployment.apps/todo-app scaled
247 | $ kubectl get pods
248 | NAME READY STATUS RESTARTS AGE
249 | mysql-8bb5f69f8-cs55w 1/1 Running 0 10m
250 | todo-app-576d68cf7f-cf74w 1/1 Running 0 5s
251 | todo-app-576d68cf7f-mskbm 1/1 Running 0 7m16s
252 | todo-app-576d68cf7f-w8x8q 0/1 ContainerCreating 0 5s
253 | ```
254 |
255 | ## Clean Up
256 | 배포한 리소스(deployments, service) 정리
257 |
258 | ```
259 | $ kubectl delete -f todo-flask-app.yaml
260 | $ kubectl delete -f todo-mariadb-app.yaml
261 | ```
262 |
263 |
264 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
265 |
266 |
272 |
273 |
274 |
--------------------------------------------------------------------------------
/docs/cloud/aws/amazon-eks-setup.md:
--------------------------------------------------------------------------------
1 | # Setup an Amazon EKS, Deploy web application
2 |
3 | **EKS로 환경 구성 및 어플리케이션 배포 실습**
4 |
5 | 이번 실습은 Amazon EKS로 대규모 컨테이너 운영 환경을 만들고 서비스(Container)를 배포 배포 해보는 실습 입니다. AWS에서 쿠버네틱스 서비스인 EKS에 대해 배워 보고 컨테이너 서비스 배포를 위한 기본 작업들을 이해 할 수 있습니다.
6 |
7 | ## 사전 준비 사항
8 |
9 | ### AWS CLI 설정
10 |
11 | AWS CLI 설치: [관련 링크](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
12 |
13 | AWS CLI 초기 설정: [관련 링크](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html)
14 |
15 | !!! note
16 | 원활한 실습을 위해 IAM User 권한에 `AdministratorAccess` policy 부여
17 |
18 | ## Architecture
19 | 
20 |
21 |
27 |
28 | ## 1. EKS 구성 하기
29 |
30 | ### IAM user for EKS
31 | EKS는 Root User로 생성/접속하는 것을 보안상 권고하지 않으며 EKS을 관리하기 위한 권한(Kubernetes RBAC authorization)을 EKS를 생성한 IAM 엔터티(user 혹은 role)로 부터 할당을 시키기 때문에 IAM user 혹은 role를 사용중이지 않다면 필수로 IAM 엔터티를 생성하고 EKS 생성 역할을 부여 해야한다.
32 |
33 | https://docs.aws.amazon.com/eks/latest/userguide/create-cluster.html
34 |
35 | 사용중인 IAM 엔터티(유저, Role)가 있다면 eksctl 권한이 있는지 검토. 원활한 실습을 위해 **AdministratorAccess** policy 부여
36 |
37 | Otherwise, create a IAM user with eksctl minimum policies.
38 | https://eksctl.io/usage/minimum-iam-policies/
39 |
40 | 현재 세션의 IAM 엔터티 확인 방법
41 | ```bash
42 | $ aws sts get-caller-identity
43 | ```
44 |
45 | ### Install eksctl and kubectl
46 |
47 | EKS 생성을 위해 eksctl을 설치 하고 추후 kubernetes 관리를 위해 kubectl도 사전에 설치 필요: [kubectl 설치(1.18)](https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/install-kubectl.html)
48 |
49 | [eksctl 설치](https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/eksctl.html)
50 |
51 |
52 | ### Deploy EKS Cluster
53 |
54 | EKS 배포를 위한 구성 정보 파일 (eks-cluster-config.yml) 작성
55 |
56 | *실습 비용 절감을 위해 SPOT 인스턴스 사용
57 |
58 | ```yaml
59 | ---
60 | apiVersion: eksctl.io/v1alpha5
61 | kind: ClusterConfig
62 |
63 | metadata:
64 | name: cloud-eks-cluster
65 | region: ap-northeast-2
66 |
67 | availabilityZones: ["ap-northeast-2a", "ap-northeast-2c"]
68 |
69 | iam:
70 | withOIDC: true
71 |
72 | managedNodeGroups:
73 | - name: cloud-eks-workers
74 | desiredCapacity: 1
75 | iam:
76 | withAddonPolicies:
77 | albIngress: true
78 | instanceTypes: ["c4.large","c5.large"]
79 | spot: true
80 | # instanceType: t3.small
81 | # ssh:
82 | # publicKeyName: ""
83 | # https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home?region=ap-northeast-2#KeyPairs:
84 |
85 | cloudWatch:
86 | clusterLogging:
87 | enableTypes: ["audit", "authenticator", "controllerManager"]
88 | ```
89 |
90 | 정의한 구성 정보 대로 cluster 생성
91 | ```
92 | $ eksctl create cluster -f ./eks-cluster-config.yml
93 | ```
94 |
95 | EKS Cluster 구성 완료 까지 약 15분 소요
96 |
97 | 옵션)만약 CLI로 하고 싶다면 다음과 같이 수행
98 | ```
99 | eksctl create cluster \
100 | --name cloud-eks-01 \
101 | --version 1.18 \
102 | --region ap-northeast-2 \
103 | --zones=ap-northeast-2a,ap-northeast-2c \
104 | --nodegroup-name cloud-eks-workers \
105 | --nodes 1 \
106 | --nodes-min 1 \
107 | --nodes-max 3 \
108 | --with-oidc \
109 | --managed \
110 | --alb-ingress-access \
111 | --spot \
112 | --instance-types=c4.large,c5.large
113 | ```
114 |
115 | ### EKS Cluster 접속 확인
116 |
117 | 정상적인 output
118 | ```
119 | [✔] all EKS cluster resources for "cloud-eks-01" have been created
120 | [ℹ] nodegroup "cloud-eks-workers" has 1 node(s)
121 | [ℹ] node "ip-192-168-27-236.ap-northeast-2.compute.internal" is ready
122 | [ℹ] waiting for at least 1 node(s) to become ready in "cloud-eks-workers"
123 | [ℹ] nodegroup "cloud-eks-workers" has 1 node(s)
124 | [ℹ] node "ip-192-168-27-236.ap-northeast-2.compute.internal" is ready
125 | [ℹ] kubectl command should work with "/Users/kcchang/.kube/config", try 'kubectl get nodes'
126 | [✔] EKS cluster "cloud-eks-01" in "ap-northeast-2" region is ready
127 | ```
128 |
129 | kubectl을 통해 추가된 node 확인
130 | ```
131 | ➜ ✗ kubectl get nodes
132 | NAME STATUS ROLES AGE VERSION
133 | ip-192-168-27-236.ap-northeast-2.compute.internal Ready 19m v1.18.9-eks-d1db3c
134 | ```
135 |
136 | ## 2. Application 배포
137 |
138 | ### Database 배포
139 |
140 | [예제 todo 애플리케이션](https://github.com/cloudacode/coolstuff/tree/main/todo-flask-app)에서 로컬 sqlight DB 대신에 외부 RDBMS(mariadb, mysql등) 리소스를 연동 한 경우에는 쿠버네티스 위에 DB app을 배포 해야하므로 관련해 Deployment manifast 파일 작성
141 |
142 | Deployment 파일 구성 하기 [kuberentes deployment](https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment/)
143 |
144 | mysql-deployment.yaml
145 | ```yaml
146 | apiVersion: apps/v1
147 | kind: Deployment
148 | metadata:
149 | name: mysql
150 | spec:
151 | selector:
152 | matchLabels:
153 | app: mysql
154 | strategy:
155 | type: Recreate
156 | template:
157 | metadata:
158 | labels:
159 | app: mysql
160 | spec:
161 | containers:
162 | - image: cloudacode/mariadb-todo:v1.0.1
163 | name: mysql
164 | ports:
165 | - containerPort: 3306
166 | name: mysql
167 | ```
168 |
169 |
170 | Deploy the contents of the deployment file:
171 | ```bash
172 | kubectl apply -f mysql-deployment.yaml
173 | ```
174 |
175 | Display information about the Deployment:
176 | ```bash
177 | kubectl describe deployment mysql
178 | ```
179 |
180 | 정상적으로 mysql이 Deploy가 되었다면 flask app에서 mysql로 접속을 위해 service를 deployment에 매핑
181 |
182 | mysql-service.yaml
183 | ```yaml
184 | apiVersion: v1
185 | kind: Service
186 | metadata:
187 | name: mysql
188 | spec:
189 | ports:
190 | - port: 3306
191 | selector:
192 | app: mysql
193 | clusterIP: None
194 | ```
195 |
196 | Deploy the contents of the service file:
197 | ```bash
198 | kubectl apply -f mysql-service.yaml
199 | ```
200 |
201 | 배포가 정상적으로 완료가 되면 Pod 정보를 찾을수 있다
202 | ```bash
203 | kubectl get pods -l app=mysql
204 | ```
205 |
206 | Output
207 | ```bash
208 | NAME READY STATUS RESTARTS AGE
209 | mysql-6fd94cc949-d8lj7 1/1 Running 0 23s
210 | ```
211 |
212 | ### Flask APP 배포
213 |
214 | 쿠버네티스에 Flask app을 배포하기 위해 Deployment manifast 파일 작성
215 |
216 | flask-deployment.yaml
217 | ```yaml
218 | apiVersion: apps/v1
219 | kind: Deployment
220 | metadata:
221 | name: cloud-flask
222 | labels:
223 | app: cloud-flask
224 | spec:
225 | replicas: 1
226 | selector:
227 | matchLabels:
228 | app: cloud-flask
229 | strategy:
230 | rollingUpdate:
231 | maxSurge: 20%
232 | maxUnavailable: 20%
233 | type: RollingUpdate
234 | template:
235 | metadata:
236 | labels:
237 | app: cloud-flask
238 | spec:
239 | containers:
240 | - image: cloudacode/python-todo:v1.1.0
241 | imagePullPolicy: Always
242 | name: cloud-flask
243 | ports:
244 | - containerPort: 5000
245 | protocol: TCP
246 | env:
247 | - name: DB_USER
248 | value: root
249 | - name: DB_PASSWORD
250 | value: mysecret
251 | - name: DB_NAME
252 | value: todo
253 | - name: DB_HOST
254 | value: mysql
255 | ```
256 |
257 | Deploy the contents of the deployment file:
258 | ```bash
259 | kubectl apply -f flask-deployment.yaml
260 | ```
261 |
262 | Display information about the Deployment:
263 | ```bash
264 | kubectl describe deployment cloud-flask
265 | ```
266 |
267 |
268 | 정상적으로 Flask app이 배포 되었다면 외부에서 flask app으로 접속을 위해 service를 deployment에 매핑
269 |
270 | flask-service.yaml
271 | ```yaml
272 | apiVersion: v1
273 | kind: Service
274 | metadata:
275 | name: cloud-flask-svc
276 | spec:
277 | selector:
278 | app: cloud-flask
279 | ports:
280 | - protocol: TCP
281 | port: 80
282 | targetPort: 5000
283 | type: LoadBalancer
284 | ```
285 |
286 | Deploy the contents of the service file:
287 | ```bash
288 | kubectl apply -f flask-service.yaml
289 | ```
290 |
291 | 배포가 정상적으로 완료가 되면 Pod 정보를 찾을수 있다
292 | ```bash
293 | kubectl get pods -l app=cloud-flask
294 | ```
295 |
296 | flask app의 경우는 Service 타입을 LB로 외부 노출을 시켰으므로 다음과 같이 LB Endpoint를 확인 가능
297 | ```bash
298 | kubectl get svc cloud-flask-svc
299 | ```
300 |
301 | Output
302 | ```bash
303 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
304 | cloud-flask-svc LoadBalancer 10.100.211.215 acd2f9103b9564eb3ada544282a1dee3-566651492.ap-northeast-2.elb.amazonaws.com 80:31126/TCP 101s
305 | ```
306 |
307 | 해당 LB endpoint로 접근 하여 확인 동작 확인
308 | 
309 |
310 | ## Clean Up
311 | 실습 완료 후 비용 절약을 위해 실습한 EKS 리소스를 정리
312 | ```
313 | eksctl delete cluster --region=ap-northeast-2 --name=
314 | ```
315 |
316 | ## Trobleshooting - EKS
317 | https://aws.amazon.com/premiumsupport/knowledge-center/amazon-eks-cluster-access/
318 |
319 | https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/troubleshooting.html#unauthorized
320 |
321 | 이 글이 유용하였다면 ⭐ Star를, 💬 1:1 질문이나 기술 관련 문의가 필요하신 분들은 클라우드어코드 카카오톡 채널 추가 부탁드립니다.🤗
322 |
323 |
329 |
330 |
331 |
--------------------------------------------------------------------------------
/docs/cloud/aws/apache-tomcat-redis.md:
--------------------------------------------------------------------------------
1 | # Build a 3tier Web App on AWS
2 |
3 | The basic unit of a 3 tier web application which is Apache + Tomcat + Redis + DB and we will use Redis for tomcat session clustering.
4 |
5 | WEB(Apache), WAS(Tomcat) + Session Clustering(Redis), DB 구성을 통해 기본적인 웹서비스의 3 Tier 구성에 대해 알아본다.
6 |
7 | This tutorial uses the AWS and highly recommend using AWS for setting up the infrastructure to test 3 tier web app.
8 |
9 | **Time to Complete: 2-3 hours**
10 |
11 | **Cost to Complete: Many of the services used are included in the AWS Free Tier. For those that are not, the sample application will cost, in total, less than $2/day.**
12 |
13 | **Tutorial Prereqs:**
14 |
15 | * **An AWS Account and Administrator-level or PowerUser-level access to it**
16 |
17 | Please be sure to terminate all of the resources created during this workshop to ensure that you are no longer charged.
18 |
19 | ### System Architecture
20 | 
21 |
22 |
28 |
29 | ## 1. Create a Web Server
30 |
31 | ### Create EC2 instances
32 |
33 | First, create `Ubuntu 18.04` [EC2](https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home) instance(s) for Web Server(s), with public IP and allow 80 for any.
34 |
35 | ### Install Apache on Ubuntu 18.04
36 |
37 | Install via apt package
38 |
39 | ```bash
40 | $ sudo apt update
41 | $ sudo apt install apache2
42 | ```
43 |
44 | ## 2. Create a WAS Server
45 |
46 | ### Create EC2 instances
47 |
48 | First, create `Ubuntu 18.04` [EC2](https://ap-northeast-2.console.aws.amazon.com/ec2/v2/home) instance(s) for Was Server(s), with public IP, allow 8080 for any, and allow 8009 for WEB server SG group.
49 |
50 | ### Set up a Tomcat User
51 | !!! note
52 | Tomcat should be run as an unprivileged user (i.e. not root)
53 |
54 | ```bash
55 | $ sudo groupadd tomcat
56 | $ sudo useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat
57 | ```
58 |
59 | ### Install Tomcat via Source package
60 |
61 | First, Tomcat needs JDK
62 | ```bash
63 | $ sudo apt update
64 | $ sudo apt install default-jdk -y
65 | $ sudo update-java-alternatives -l
66 | ```
67 |
68 | Download Tomcat Source package [Download](https://tomcat.apache.org/download-90.cgi)
69 | ```bash
70 | $ curl -O https://ftpmirror1.infania.net/mirror/apache/tomcat/tomcat-9/v9.0.41/bin/apache-tomcat-9.0.41.tar.gz
71 | ```
72 |
73 | Execute the following command to create tomcat directory and extract source pakcage
74 |
75 | ```bash
76 | $ sudo mkdir /opt/tomcat
77 | $ sudo tar xzvf apache-tomcat-*tar.gz -C /opt/tomcat --strip-components=1
78 | ```
79 |
80 | Set up the permission for tomcat user/group
81 |
82 | ```bash
83 | cd /opt/tomcat
84 | sudo chgrp -R tomcat /opt/tomcat
85 | sudo chmod -R g+r conf
86 | sudo chmod g+x conf
87 | sudo chown -R tomcat webapps/ work/ temp/ logs/
88 | ```
89 |
90 | Now, configure the systemd service file `/etc/systemd/system/tomcat.service`
91 |
92 | ```bash
93 | [Unit]
94 | Description=Apache Tomcat Web Application Container
95 | After=network.target
96 |
97 | [Service]
98 | Type=forking
99 |
100 | Environment=JAVA_HOME=/usr/lib/jvm/java-1.11.0-openjdk-amd64
101 | Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
102 | Environment=CATALINA_HOME=/opt/tomcat
103 | Environment=CATALINA_BASE=/opt/tomcat
104 | Environment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'
105 | Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'
106 |
107 | ExecStart=/opt/tomcat/bin/startup.sh
108 | ExecStop=/opt/tomcat/bin/shutdown.sh
109 |
110 | User=tomcat
111 | Group=tomcat
112 | UMask=0007
113 | RestartSec=10
114 | Restart=always
115 |
116 | [Install]
117 | WantedBy=multi-user.target
118 | ```
119 |
120 | Start tomcat service
121 | ```bash
122 | sudo systemctl daemon-reload
123 | sudo systemctl start tomcat
124 | sudo systemctl status tomcat
125 | ```
126 |
127 | Open your browser to check tomcat server
128 | http://was_server_IP:8080
129 |
130 | Congratulations, you have installed the basic tomcat server
131 |
132 | ### Create sample Webapp in Tomcat
133 |
134 | ```bash
135 | $ cd /opt/tomcat
136 | $ sudo mkdir -p webapps/demo
137 | ```
138 |
139 | `index.jsp`
140 | ```html
141 |
142 |
143 | TOMCAT DEMO
144 |
145 |
146 | ```
147 |
148 | Restart tomcat service
149 |
150 | ```bash
151 | $ sudo systemctl restart tomcat.service
152 | ```
153 |
154 | http://WAS_SERVER_IP:8080/demo
155 |
156 | Now, you have a new demo webapp
157 |
158 |
159 | ## 3. Integrate apache and tomcat via AJP protocol
160 |
161 | !!! note
162 | Tomcat AJP protocol connector
163 | https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html
164 |
165 | ### Enable AJP in Tomcat server
166 |
167 | In order to make connection between apache and tomcat, enable AJP connector in `/opt/tomcat/conf/server.xml`
168 |
169 | ```xml
170 |
171 |
176 |
177 |
178 | ```
179 |
180 | Please keep in mind, the jvmRoute value stands for worker name and each WAS has a unique name.
181 |
182 | Restart tomcat service
183 | ```bash
184 | $ sudo systemctl restart tomcat.service
185 | ```
186 |
187 | ### Setup mod_jk module in Apache server
188 |
189 | Install mod_jk library
190 |
191 | ```bash
192 | $ cd /etc/apache2
193 | $ sudo apt-get install libapache2-mod-jk
194 | $ sudo ln -s /etc/libapache2-mod-jk/workers.properties
195 | ```
196 |
197 | Configure worker infomation as WAS server in `workers.properties`
198 |
199 | Single WAS server,
200 | ```log
201 | workers.tomcat_home=/usr/share/tomcat8
202 | workers.java_home=/usr/lib/jvm/default-java
203 | ps=/
204 |
205 | worker.list=ajp13_worker_lb
206 |
207 | worker.ajp13_worker01.port=8009
208 | worker.ajp13_worker01.host=`WAS Server IP`
209 | worker.ajp13_worker01.type=ajp13
210 | worker.ajp13_worker01.lbfactor=100
211 |
212 | worker.ajp13_worker_lb.type=lb
213 | worker.ajp13_worker_lb.balance_workers=ajp13_worker01
214 | ```
215 |
216 | Multiple WAS servers,
217 |
218 | ```log
219 | workers.tomcat_home=/usr/share/tomcat8
220 | workers.java_home=/usr/lib/jvm/default-java
221 | ps=/
222 |
223 | worker.list=ajp13_worker_lb
224 |
225 | worker.ajp13_worker01.port=8009
226 | worker.ajp13_worker01.host=`WAS Server01 IP`
227 | worker.ajp13_worker01.type=ajp13
228 | worker.ajp13_worker01.lbfactor=50
229 |
230 | worker.ajp13_worker02.port=8009
231 | worker.ajp13_worker02.host=`WAS Server02 IP`
232 | worker.ajp13_worker02.type=ajp13
233 | worker.ajp13_worker02.lbfactor=50
234 |
235 | worker.ajp13_worker_lb.type=lb
236 | worker.ajp13_worker_lb.balance_workers=ajp13_worker01,ajp13_worker02
237 | ```
238 |
239 | !!! note
240 | Loadbalancing
241 | https://tomcat.apache.org/connectors-doc/common_howto/loadbalancers.html
242 |
243 | In order to forward traffic to tomcat, add JkMount configuration in site default file(`/etc/apache2/sites-enabled/000-default.conf`)
244 |
245 | ```xml
246 |
247 | ServerAdmin localhost
248 | DocumentRoot /var/www/html
249 | JkMount /*.jsp ajp13_worker_lb
250 | ErrorLog ${APACHE_LOG_DIR}/error.log
251 | CustomLog ${APACHE_LOG_DIR}/access.log combined
252 |
253 | ```
254 |
255 | Restart Apache service
256 | ```bash
257 | $ sudo systemctl restart apache.service
258 | ```
259 |
260 | Now, the Apache forwards JSP request to Tomcat and response
261 |
262 | http://WEB_SERVER_IP:8080/demo/index.jsp
263 |
264 | Congratulations, you have integrated WEB, WAS tier
265 |
266 |
267 | ## 4. Tomcat Session Clustering with Redis
268 |
269 | We have several options to set up the session clustering, and this tutorial is going to use [Redisson-tomcat](https://github.com/redisson/redisson/tree/master/redisson-tomcat) library which is the most active library for Redis session clustering.
270 |
271 | ### Create the ElastiCache cluster
272 | First, create Redis via [ElastiCache](https://ap-northeast-2.console.aws.amazon.com/elasticache/home) cluster, and allow 6379 for WAS server SG group.
273 |
274 | ### Setup the Redisson library
275 | Download `redisson-all`, `redisson-tomcat` library in tomcat lib directory
276 |
277 | ```bash
278 | $ sudo curl -O https://repository.sonatype.org/service/local/repositories/central-proxy/content/org/redisson/redisson-all/3.15.0/redisson-all-3.15.0.jar
279 |
280 | $ sudo curl -O https://repository.sonatype.org/service/local/repositories/central-proxy/content/org/redisson/redisson
281 | -tomcat-9/3.15.0/redisson-tomcat-9-3.15.0.jar
282 |
283 | $ sudo mv redisson* /opt/tomcat/lib/
284 | ```
285 |
286 | Add the redisson class in `conf/context.xml`
287 | ```xml
288 |
292 | ```
293 |
294 | Setup the `conf/redisson.conf`
295 | ```log
296 | {
297 | "singleServerConfig":{
298 | "address": "redis://`ElastiCache_Cluster`:6379"
299 | },
300 | "threads":0,
301 | "nettyThreads":0,
302 | "transportMode":"NIO"
303 | }
304 | ```
305 |
306 | Restart tomcat service
307 | ```bash
308 | $ sudo systemctl restart tomcat.service
309 | ```
310 |
311 | Now, you can check session information in Redis
312 |
313 | If you don't have `redis-client`, install redis-tools apt package
314 | ```bash
315 | apt-get install redis-tools
316 | ```
317 |
318 | Access redis cluster and check keys which are the session ID.
319 | ```bash
320 | $ redis-cli -h session01.mvqc4c.0001.apn2.cache.amazonaws.com
321 |
322 | session01.mvqc4c.0001.apn2.cache.amazonaws.com:6379> KEYS *
323 | 1) "redisson:tomcat_session:959CB3E05C307CB9ECCEB4534E84CFE8.ajp13_worker01"
324 | 2) "redisson:tomcat_session:7616482947EC5AC55A6ACDFF5F4BEC01.ajp13_worker02"
325 | ```
326 |
327 | Add following JSP file to check via browser
328 |
329 | `webapps/demo/session.jsp`
330 | ```html
331 |
332 |
333 |
334 |
335 | Session ID
336 | <%=session.getId()%>
337 |
338 |
339 | Server IP
340 | <%=request.getLocalAddr()%>
341 |
342 |
343 | Server Name: <%=request.getLocalName()%>
344 |
345 |
346 | ```
347 |
348 | Restart apache2 service
349 | ```bash
350 | $ sudo systemctl restart apache2
351 | ```
352 |
353 | http://WEB_SERVER_IP/demo/session.jsp
354 |
355 | Please stop one of the tomcat servers and check the session is still in place
356 | Congratulations, you have integrated Session Clustering
357 |
358 | ## 5. Implement Database
359 |
360 | ### Deploy a RDS
361 | First, create Mysql via [RDS](https://ap-northeast-2.console.aws.amazon.com/rds/home), and allow 3306 for WAS server SG group.
362 |
363 | ### Create a dummy database
364 |
365 | Access RDS and create a Dummy database
366 | ```
367 | create database javatest;
368 | use javatest;
369 | create table testdata (id int not null auto_increment primary key, foo varchar(25), bar int);
370 | ```
371 |
372 | ```
373 | insert into testdata values(null, 'hello', 12345);
374 | select * from testdata;
375 | ```
376 |
377 | ### Setup mysql connector for Tomcat
378 |
379 | In order to connect mysql, add mysql connector in the WAS(Tomcat) server(s)
380 | ```bash
381 | $ cd tmp/
382 |
383 | $ curl -O https://cdn.mysql.com//Downloads/Connector-J/mysql-connector-java-8.0.23.zip
384 |
385 | $sudo mv /tmp/mysql-connector-java-8.0.23/mysql-connector-java-8.0.23.jar /opt/tomcat/lib/
386 | ```
387 |
388 | Update conf/context.xml
389 | ```bash
390 |
391 | ```
392 | Please change the `DB_USERNAME`, `DB_PASSWORD`, and `RDS_ENDPOINT`
393 |
394 | Add following JSP file in the `webapps/demo/testdb.jsp` to check via browser
395 | ```jsp
396 | <%@page import="java.sql.DriverManager"%>
397 | <%@page import="java.sql.ResultSet"%>
398 | <%@page import="java.sql.Statement"%>
399 | <%@page import="java.sql.Connection"%>
400 | <%
401 | String id = request.getParameter("userid"); String driver =
402 | "com.mysql.jdbc.Driver"; String connectionUrl =
403 | "jdbc:mysql://RDS_ENDPOINT:3306/";
404 | String database = "javatest"; String userid = "DB_USERNAME"; String password =
405 | "DB_PASSWORD"; try { Class.forName(driver); } catch (ClassNotFoundException e) {
406 | e.printStackTrace(); } Connection connection = null; Statement statement = null;
407 | ResultSet resultSet = null; %>
408 |
409 |
410 |
411 |
412 |
413 | session id
414 | <%=session.getId()%>
415 |
416 |
417 | foo
418 | bar
419 |
420 | <% try{ connection = DriverManager.getConnection(connectionUrl+database,
421 | userid, password); statement=connection.createStatement(); String sql
422 | ="select id, foo, bar from testdata"; resultSet =
423 | statement.executeQuery(sql); while(resultSet.next()){ %>
424 |
425 | <%=resultSet.getString("foo") %>
426 | <%=resultSet.getString("bar") %>
427 |
428 | <% } connection.close(); } catch (Exception e) { e.printStackTrace(); } %>
429 |
430 |
431 |
432 | ```
433 |
434 | Restart apache2 service
435 | ```bash
436 | $ sudo systemctl restart tomcat.service
437 | ```
438 |
439 | Now, this testdb.jsp will return the DB result which is in the RDS
440 |
441 | http://WEB_SERVER_IP/demo/testdb.jsp
442 |
443 | 
444 |
445 | Congratulations, you have completed WEB, WAS, DB tutorial
446 |
447 | ## Reference
448 | - https://www.digitalocean.com/community/questions/apache-virtual-host-with-multiple-tomcat-server
449 | - https://github.com/redisson/redisson/wiki/2.-Configuration#221-yaml-file-based-configuration
450 |
451 |
452 |
458 |
459 |
460 |
--------------------------------------------------------------------------------
/docs/kubernetes/assets/kubernetes-cluster-prometheus_rev1.json:
--------------------------------------------------------------------------------
1 | {
2 | "__inputs": [
3 | {
4 | "name": "DS_PROMETHEUS",
5 | "label": "prometheus",
6 | "description": "",
7 | "type": "datasource",
8 | "pluginId": "prometheus",
9 | "pluginName": "Prometheus"
10 | }
11 | ],
12 | "__requires": [
13 | {
14 | "type": "grafana",
15 | "id": "grafana",
16 | "name": "Grafana",
17 | "version": "4.6.2"
18 | },
19 | {
20 | "type": "panel",
21 | "id": "graph",
22 | "name": "Graph",
23 | "version": ""
24 | },
25 | {
26 | "type": "datasource",
27 | "id": "prometheus",
28 | "name": "Prometheus",
29 | "version": "1.0.0"
30 | },
31 | {
32 | "type": "panel",
33 | "id": "singlestat",
34 | "name": "Singlestat",
35 | "version": ""
36 | },
37 | {
38 | "type": "panel",
39 | "id": "text",
40 | "name": "Text",
41 | "version": ""
42 | }
43 | ],
44 | "annotations": {
45 | "list": [
46 | {
47 | "$$hashKey": "object:3607",
48 | "builtIn": 1,
49 | "datasource": "-- Grafana --",
50 | "enable": true,
51 | "hide": true,
52 | "iconColor": "rgba(0, 211, 255, 1)",
53 | "name": "Annotations & Alerts",
54 | "type": "dashboard"
55 | }
56 | ]
57 | },
58 | "description": "Summary metrics about containers running on Kubernetes nodes.\r\n\r\nDashboard was taken from here. This version does not reqiure you to\r\nsetup the Kubernetes-app plugin. (https://github.com/grafana/kubernetes-app)\r\n\r\nUse this Helm chart to launch Grafana into a Kubernetes cluster. It will include this dashboard and many more dashboards to give you visibility into the Kubernetes Cluster. (https://github.com/sekka1/cloud-public/tree/master/kubernetes/pods/grafana-helm)",
59 | "editable": true,
60 | "gnetId": 6417,
61 | "graphTooltip": 1,
62 | "id": 10,
63 | "iteration": 1528328092190,
64 | "links": [
65 | {
66 | "asDropdown": true,
67 | "icon": "external link",
68 | "includeVars": true,
69 | "keepTime": false,
70 | "tags": [
71 | "kubernetes-app"
72 | ],
73 | "title": "Dashboards",
74 | "type": "dashboards"
75 | }
76 | ],
77 | "panels": [
78 | {
79 | "collapsed": false,
80 | "gridPos": {
81 | "h": 1,
82 | "w": 24,
83 | "x": 0,
84 | "y": 0
85 | },
86 | "id": 2,
87 | "panels": [],
88 | "title": "Cluster Health",
89 | "type": "row"
90 | },
91 | {
92 | "cacheTimeout": null,
93 | "colorBackground": false,
94 | "colorValue": false,
95 | "colors": [
96 | "#299c46",
97 | "rgba(237, 129, 40, 0.89)",
98 | "#d44a3a"
99 | ],
100 | "datasource": "${DS_PROMETHEUS}",
101 | "format": "percentunit",
102 | "gauge": {
103 | "maxValue": 100,
104 | "minValue": 0,
105 | "show": true,
106 | "thresholdLabels": false,
107 | "thresholdMarkers": true
108 | },
109 | "gridPos": {
110 | "h": 4,
111 | "w": 6,
112 | "x": 0,
113 | "y": 1
114 | },
115 | "id": 4,
116 | "interval": null,
117 | "links": [],
118 | "mappingType": 1,
119 | "mappingTypes": [
120 | {
121 | "name": "value to text",
122 | "value": 1
123 | },
124 | {
125 | "name": "range to text",
126 | "value": 2
127 | }
128 | ],
129 | "maxDataPoints": 100,
130 | "nullPointMode": "connected",
131 | "nullText": null,
132 | "postfix": "",
133 | "postfixFontSize": "50%",
134 | "prefix": "",
135 | "prefixFontSize": "50%",
136 | "rangeMaps": [
137 | {
138 | "from": "null",
139 | "text": "N/A",
140 | "to": "null"
141 | }
142 | ],
143 | "sparkline": {
144 | "fillColor": "rgba(31, 118, 189, 0.18)",
145 | "full": false,
146 | "lineColor": "rgb(31, 120, 193)",
147 | "show": false
148 | },
149 | "tableColumn": "",
150 | "targets": [
151 | {
152 | "expr": "sum(kube_pod_info{node=~\"$node\"}) / sum(kube_node_status_allocatable_pods{node=~\".*\"})",
153 | "format": "time_series",
154 | "intervalFactor": 1,
155 | "refId": "A"
156 | }
157 | ],
158 | "thresholds": "80,90",
159 | "title": "Cluster Pod Usage",
160 | "type": "singlestat",
161 | "valueFontSize": "80%",
162 | "valueMaps": [
163 | {
164 | "op": "=",
165 | "text": "N/A",
166 | "value": "null"
167 | }
168 | ],
169 | "valueName": "current"
170 | },
171 | {
172 | "cacheTimeout": null,
173 | "colorBackground": false,
174 | "colorValue": false,
175 | "colors": [
176 | "#299c46",
177 | "rgba(237, 129, 40, 0.89)",
178 | "#d44a3a"
179 | ],
180 | "datasource": "${DS_PROMETHEUS}",
181 | "format": "percentunit",
182 | "gauge": {
183 | "maxValue": 100,
184 | "minValue": 0,
185 | "show": true,
186 | "thresholdLabels": false,
187 | "thresholdMarkers": true
188 | },
189 | "gridPos": {
190 | "h": 4,
191 | "w": 6,
192 | "x": 6,
193 | "y": 1
194 | },
195 | "id": 5,
196 | "interval": null,
197 | "links": [],
198 | "mappingType": 1,
199 | "mappingTypes": [
200 | {
201 | "name": "value to text",
202 | "value": 1
203 | },
204 | {
205 | "name": "range to text",
206 | "value": 2
207 | }
208 | ],
209 | "maxDataPoints": 100,
210 | "nullPointMode": "connected",
211 | "nullText": null,
212 | "postfix": "",
213 | "postfixFontSize": "50%",
214 | "prefix": "",
215 | "prefixFontSize": "50%",
216 | "rangeMaps": [
217 | {
218 | "from": "null",
219 | "text": "N/A",
220 | "to": "null"
221 | }
222 | ],
223 | "sparkline": {
224 | "fillColor": "rgba(31, 118, 189, 0.18)",
225 | "full": false,
226 | "lineColor": "rgb(31, 120, 193)",
227 | "show": false
228 | },
229 | "tableColumn": "",
230 | "targets": [
231 | {
232 | "expr": "sum(kube_pod_container_resource_requests_cpu_cores{node=~\"$node\"}) / sum(kube_node_status_allocatable_cpu_cores{node=~\"$node\"})",
233 | "format": "time_series",
234 | "intervalFactor": 1,
235 | "refId": "A"
236 | }
237 | ],
238 | "thresholds": "80,90",
239 | "title": "Cluster CPU Usage",
240 | "type": "singlestat",
241 | "valueFontSize": "80%",
242 | "valueMaps": [
243 | {
244 | "op": "=",
245 | "text": "N/A",
246 | "value": "null"
247 | }
248 | ],
249 | "valueName": "current"
250 | },
251 | {
252 | "cacheTimeout": null,
253 | "colorBackground": false,
254 | "colorValue": false,
255 | "colors": [
256 | "#299c46",
257 | "rgba(237, 129, 40, 0.89)",
258 | "#d44a3a"
259 | ],
260 | "datasource": "${DS_PROMETHEUS}",
261 | "format": "percentunit",
262 | "gauge": {
263 | "maxValue": 100,
264 | "minValue": 0,
265 | "show": true,
266 | "thresholdLabels": false,
267 | "thresholdMarkers": true
268 | },
269 | "gridPos": {
270 | "h": 4,
271 | "w": 6,
272 | "x": 12,
273 | "y": 1
274 | },
275 | "id": 6,
276 | "interval": null,
277 | "links": [],
278 | "mappingType": 1,
279 | "mappingTypes": [
280 | {
281 | "name": "value to text",
282 | "value": 1
283 | },
284 | {
285 | "name": "range to text",
286 | "value": 2
287 | }
288 | ],
289 | "maxDataPoints": 100,
290 | "nullPointMode": "connected",
291 | "nullText": null,
292 | "postfix": "",
293 | "postfixFontSize": "50%",
294 | "prefix": "",
295 | "prefixFontSize": "50%",
296 | "rangeMaps": [
297 | {
298 | "from": "null",
299 | "text": "N/A",
300 | "to": "null"
301 | }
302 | ],
303 | "sparkline": {
304 | "fillColor": "rgba(31, 118, 189, 0.18)",
305 | "full": false,
306 | "lineColor": "rgb(31, 120, 193)",
307 | "show": false
308 | },
309 | "tableColumn": "",
310 | "targets": [
311 | {
312 | "expr": "sum(kube_pod_container_resource_requests_memory_bytes{node=~\"$node\"}) / sum(kube_node_status_allocatable_memory_bytes{node=~\"$node\"})",
313 | "format": "time_series",
314 | "intervalFactor": 1,
315 | "refId": "A"
316 | }
317 | ],
318 | "thresholds": "80,90",
319 | "title": "Cluster Memory Usage",
320 | "type": "singlestat",
321 | "valueFontSize": "80%",
322 | "valueMaps": [
323 | {
324 | "op": "=",
325 | "text": "N/A",
326 | "value": "null"
327 | }
328 | ],
329 | "valueName": "current"
330 | },
331 | {
332 | "cacheTimeout": null,
333 | "colorBackground": false,
334 | "colorValue": false,
335 | "colors": [
336 | "#299c46",
337 | "rgba(237, 129, 40, 0.89)",
338 | "#d44a3a"
339 | ],
340 | "datasource": "${DS_PROMETHEUS}",
341 | "format": "percentunit",
342 | "gauge": {
343 | "maxValue": 100,
344 | "minValue": 0,
345 | "show": true,
346 | "thresholdLabels": false,
347 | "thresholdMarkers": true
348 | },
349 | "gridPos": {
350 | "h": 4,
351 | "w": 6,
352 | "x": 18,
353 | "y": 1
354 | },
355 | "id": 7,
356 | "interval": null,
357 | "links": [],
358 | "mappingType": 1,
359 | "mappingTypes": [
360 | {
361 | "name": "value to text",
362 | "value": 1
363 | },
364 | {
365 | "name": "range to text",
366 | "value": 2
367 | }
368 | ],
369 | "maxDataPoints": 100,
370 | "nullPointMode": "connected",
371 | "nullText": null,
372 | "postfix": "",
373 | "postfixFontSize": "50%",
374 | "prefix": "",
375 | "prefixFontSize": "50%",
376 | "rangeMaps": [
377 | {
378 | "from": "null",
379 | "text": "N/A",
380 | "to": "null"
381 | }
382 | ],
383 | "sparkline": {
384 | "fillColor": "rgba(31, 118, 189, 0.18)",
385 | "full": false,
386 | "lineColor": "rgb(31, 120, 193)",
387 | "show": false
388 | },
389 | "tableColumn": "",
390 | "targets": [
391 | {
392 | "expr": "(sum (node_filesystem_size{nodename=~\"$node\"}) - sum (node_filesystem_free{nodename=~\"$node\"})) / sum (node_filesystem_size{nodename=~\"$node\"})",
393 | "format": "time_series",
394 | "intervalFactor": 1,
395 | "refId": "A"
396 | }
397 | ],
398 | "thresholds": "80,90",
399 | "title": "Cluster Disk Usage",
400 | "type": "singlestat",
401 | "valueFontSize": "80%",
402 | "valueMaps": [
403 | {
404 | "op": "=",
405 | "text": "N/A",
406 | "value": "null"
407 | }
408 | ],
409 | "valueName": "current"
410 | },
411 | {
412 | "aliasColors": {},
413 | "bars": false,
414 | "dashLength": 10,
415 | "dashes": false,
416 | "datasource": "${DS_PROMETHEUS}",
417 | "fill": 1,
418 | "gridPos": {
419 | "h": 5,
420 | "w": 6,
421 | "x": 0,
422 | "y": 5
423 | },
424 | "id": 9,
425 | "legend": {
426 | "avg": false,
427 | "current": false,
428 | "max": false,
429 | "min": false,
430 | "show": true,
431 | "total": false,
432 | "values": false
433 | },
434 | "lines": true,
435 | "linewidth": 1,
436 | "links": [],
437 | "nullPointMode": "null",
438 | "percentage": false,
439 | "pointradius": 5,
440 | "points": false,
441 | "renderer": "flot",
442 | "seriesOverrides": [],
443 | "spaceLength": 10,
444 | "stack": false,
445 | "steppedLine": false,
446 | "targets": [
447 | {
448 | "expr": "sum(kube_node_status_allocatable_pods{node=~\"$node\"})",
449 | "format": "time_series",
450 | "intervalFactor": 1,
451 | "legendFormat": "allocatable",
452 | "refId": "A"
453 | },
454 | {
455 | "expr": "sum(kube_node_status_capacity_pods{node=~\"$node\"})",
456 | "format": "time_series",
457 | "intervalFactor": 1,
458 | "legendFormat": "capacity",
459 | "refId": "B"
460 | },
461 | {
462 | "expr": "sum(kube_pod_info{node=~\"$node\"})",
463 | "format": "time_series",
464 | "intervalFactor": 1,
465 | "legendFormat": "requested",
466 | "refId": "C"
467 | }
468 | ],
469 | "thresholds": [],
470 | "timeFrom": null,
471 | "timeShift": null,
472 | "title": "Cluster Pod Capacity",
473 | "tooltip": {
474 | "shared": true,
475 | "sort": 0,
476 | "value_type": "individual"
477 | },
478 | "type": "graph",
479 | "xaxis": {
480 | "buckets": null,
481 | "mode": "time",
482 | "name": null,
483 | "show": true,
484 | "values": []
485 | },
486 | "yaxes": [
487 | {
488 | "format": "short",
489 | "label": "pods",
490 | "logBase": 1,
491 | "max": null,
492 | "min": null,
493 | "show": true
494 | },
495 | {
496 | "format": "short",
497 | "label": null,
498 | "logBase": 1,
499 | "max": null,
500 | "min": null,
501 | "show": true
502 | }
503 | ],
504 | "yaxis": {
505 | "align": false,
506 | "alignLevel": null
507 | }
508 | },
509 | {
510 | "aliasColors": {},
511 | "bars": false,
512 | "dashLength": 10,
513 | "dashes": false,
514 | "datasource": "${DS_PROMETHEUS}",
515 | "fill": 1,
516 | "gridPos": {
517 | "h": 5,
518 | "w": 6,
519 | "x": 6,
520 | "y": 5
521 | },
522 | "id": 10,
523 | "legend": {
524 | "avg": false,
525 | "current": false,
526 | "max": false,
527 | "min": false,
528 | "show": true,
529 | "total": false,
530 | "values": false
531 | },
532 | "lines": true,
533 | "linewidth": 1,
534 | "links": [],
535 | "nullPointMode": "null",
536 | "percentage": false,
537 | "pointradius": 5,
538 | "points": false,
539 | "renderer": "flot",
540 | "seriesOverrides": [],
541 | "spaceLength": 10,
542 | "stack": false,
543 | "steppedLine": false,
544 | "targets": [
545 | {
546 | "expr": "sum(kube_node_status_capacity_cpu_cores{node=~\"$node\"})",
547 | "format": "time_series",
548 | "intervalFactor": 1,
549 | "legendFormat": "allocatable",
550 | "refId": "A"
551 | },
552 | {
553 | "expr": "sum(kube_node_status_allocatable_cpu_cores{node=~\"$node\"})",
554 | "format": "time_series",
555 | "intervalFactor": 1,
556 | "legendFormat": "capacity",
557 | "refId": "B"
558 | },
559 | {
560 | "expr": "sum(kube_pod_container_resource_requests_cpu_cores{node=~\"$node\"})",
561 | "format": "time_series",
562 | "intervalFactor": 1,
563 | "legendFormat": "requested",
564 | "refId": "C"
565 | }
566 | ],
567 | "thresholds": [],
568 | "timeFrom": null,
569 | "timeShift": null,
570 | "title": "Cluster CPU Capacity",
571 | "tooltip": {
572 | "shared": true,
573 | "sort": 0,
574 | "value_type": "individual"
575 | },
576 | "type": "graph",
577 | "xaxis": {
578 | "buckets": null,
579 | "mode": "time",
580 | "name": null,
581 | "show": true,
582 | "values": []
583 | },
584 | "yaxes": [
585 | {
586 | "decimals": null,
587 | "format": "none",
588 | "label": "cores",
589 | "logBase": 1,
590 | "max": null,
591 | "min": null,
592 | "show": true
593 | },
594 | {
595 | "format": "short",
596 | "label": null,
597 | "logBase": 1,
598 | "max": null,
599 | "min": null,
600 | "show": true
601 | }
602 | ],
603 | "yaxis": {
604 | "align": false,
605 | "alignLevel": null
606 | }
607 | },
608 | {
609 | "aliasColors": {},
610 | "bars": false,
611 | "dashLength": 10,
612 | "dashes": false,
613 | "datasource": "${DS_PROMETHEUS}",
614 | "fill": 1,
615 | "gridPos": {
616 | "h": 5,
617 | "w": 6,
618 | "x": 12,
619 | "y": 5
620 | },
621 | "id": 11,
622 | "legend": {
623 | "avg": false,
624 | "current": false,
625 | "max": false,
626 | "min": false,
627 | "show": true,
628 | "total": false,
629 | "values": false
630 | },
631 | "lines": true,
632 | "linewidth": 1,
633 | "links": [],
634 | "nullPointMode": "null",
635 | "percentage": false,
636 | "pointradius": 5,
637 | "points": false,
638 | "renderer": "flot",
639 | "seriesOverrides": [],
640 | "spaceLength": 10,
641 | "stack": false,
642 | "steppedLine": false,
643 | "targets": [
644 | {
645 | "expr": "sum(kube_node_status_allocatable_memory_bytes{node=~\"$node\"})",
646 | "format": "time_series",
647 | "intervalFactor": 1,
648 | "legendFormat": "allocatable",
649 | "refId": "A"
650 | },
651 | {
652 | "expr": "sum(kube_node_status_capacity_memory_bytes{node=~\"$node\"})",
653 | "format": "time_series",
654 | "intervalFactor": 1,
655 | "legendFormat": "capacity",
656 | "refId": "B"
657 | },
658 | {
659 | "expr": "sum(kube_pod_container_resource_requests_memory_bytes{node=~\"$node\"})",
660 | "format": "time_series",
661 | "intervalFactor": 1,
662 | "legendFormat": "requested",
663 | "refId": "C"
664 | }
665 | ],
666 | "thresholds": [],
667 | "timeFrom": null,
668 | "timeShift": null,
669 | "title": "Cluster Mem Capacity",
670 | "tooltip": {
671 | "shared": true,
672 | "sort": 0,
673 | "value_type": "individual"
674 | },
675 | "type": "graph",
676 | "xaxis": {
677 | "buckets": null,
678 | "mode": "time",
679 | "name": null,
680 | "show": true,
681 | "values": []
682 | },
683 | "yaxes": [
684 | {
685 | "format": "decbytes",
686 | "label": null,
687 | "logBase": 1,
688 | "max": null,
689 | "min": null,
690 | "show": true
691 | },
692 | {
693 | "format": "short",
694 | "label": null,
695 | "logBase": 1,
696 | "max": null,
697 | "min": null,
698 | "show": true
699 | }
700 | ],
701 | "yaxis": {
702 | "align": false,
703 | "alignLevel": null
704 | }
705 | },
706 | {
707 | "aliasColors": {},
708 | "bars": false,
709 | "dashLength": 10,
710 | "dashes": false,
711 | "datasource": "${DS_PROMETHEUS}",
712 | "fill": 1,
713 | "gridPos": {
714 | "h": 5,
715 | "w": 6,
716 | "x": 18,
717 | "y": 5
718 | },
719 | "id": 12,
720 | "legend": {
721 | "avg": false,
722 | "current": false,
723 | "max": false,
724 | "min": false,
725 | "show": true,
726 | "total": false,
727 | "values": false
728 | },
729 | "lines": true,
730 | "linewidth": 1,
731 | "links": [],
732 | "nullPointMode": "null",
733 | "percentage": false,
734 | "pointradius": 5,
735 | "points": false,
736 | "renderer": "flot",
737 | "seriesOverrides": [],
738 | "spaceLength": 10,
739 | "stack": false,
740 | "steppedLine": false,
741 | "targets": [
742 | {
743 | "expr": "sum(node_filesystem_size{nodename=~\"$node\"}) - sum(node_filesystem_free{nodename=~\"$node\"})",
744 | "format": "time_series",
745 | "intervalFactor": 1,
746 | "legendFormat": "usage",
747 | "refId": "A"
748 | },
749 | {
750 | "expr": "sum(node_filesystem_size{nodename=~\"$node\"})",
751 | "format": "time_series",
752 | "intervalFactor": 1,
753 | "legendFormat": "limit",
754 | "refId": "B"
755 | }
756 | ],
757 | "thresholds": [],
758 | "timeFrom": null,
759 | "timeShift": null,
760 | "title": "Cluster Disk Capacity",
761 | "tooltip": {
762 | "shared": true,
763 | "sort": 0,
764 | "value_type": "individual"
765 | },
766 | "type": "graph",
767 | "xaxis": {
768 | "buckets": null,
769 | "mode": "time",
770 | "name": null,
771 | "show": true,
772 | "values": []
773 | },
774 | "yaxes": [
775 | {
776 | "format": "decbytes",
777 | "label": null,
778 | "logBase": 1,
779 | "max": null,
780 | "min": null,
781 | "show": true
782 | },
783 | {
784 | "format": "short",
785 | "label": null,
786 | "logBase": 1,
787 | "max": null,
788 | "min": null,
789 | "show": true
790 | }
791 | ],
792 | "yaxis": {
793 | "align": false,
794 | "alignLevel": null
795 | }
796 | },
797 | {
798 | "collapsed": false,
799 | "gridPos": {
800 | "h": 1,
801 | "w": 24,
802 | "x": 0,
803 | "y": 10
804 | },
805 | "id": 14,
806 | "panels": [],
807 | "title": "Deployments",
808 | "type": "row"
809 | },
810 | {
811 | "columns": [
812 | {
813 | "text": "Current",
814 | "value": "current"
815 | }
816 | ],
817 | "datasource": "${DS_PROMETHEUS}",
818 | "fontSize": "100%",
819 | "gridPos": {
820 | "h": 5,
821 | "w": 6,
822 | "x": 0,
823 | "y": 11
824 | },
825 | "id": 16,
826 | "links": [],
827 | "pageSize": null,
828 | "scroll": true,
829 | "showHeader": true,
830 | "sort": {
831 | "col": 1,
832 | "desc": true
833 | },
834 | "styles": [
835 | {
836 | "alias": "Time",
837 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
838 | "pattern": "Time",
839 | "type": "date"
840 | },
841 | {
842 | "alias": "",
843 | "colorMode": "row",
844 | "colors": [
845 | "rgba(245, 54, 54, 0.9)",
846 | "rgba(237, 129, 40, 0.89)",
847 | "rgba(50, 172, 45, 0.97)"
848 | ],
849 | "decimals": 0,
850 | "pattern": "Metric",
851 | "thresholds": [
852 | "0",
853 | "0",
854 | ".9"
855 | ],
856 | "type": "string",
857 | "unit": "none"
858 | },
859 | {
860 | "alias": "",
861 | "colorMode": "row",
862 | "colors": [
863 | "rgba(245, 54, 54, 0.9)",
864 | "rgba(237, 129, 40, 0.89)",
865 | "rgba(50, 172, 45, 0.97)"
866 | ],
867 | "dateFormat": "YYYY-MM-DD HH:mm:ss",
868 | "decimals": 0,
869 | "link": false,
870 | "pattern": "Value",
871 | "thresholds": [
872 | "0",
873 | "1"
874 | ],
875 | "type": "number",
876 | "unit": "none"
877 | }
878 | ],
879 | "targets": [
880 | {
881 | "expr": "kube_deployment_status_replicas{namespace=~\"$namespace\"}",
882 | "format": "time_series",
883 | "instant": true,
884 | "interval": "",
885 | "intervalFactor": 1,
886 | "legendFormat": "{{ deployment }}",
887 | "refId": "A"
888 | }
889 | ],
890 | "title": "Deployment Replicas - Up To Date",
891 | "transform": "timeseries_to_rows",
892 | "type": "table"
893 | },
894 | {
895 | "cacheTimeout": null,
896 | "colorBackground": false,
897 | "colorValue": false,
898 | "colors": [
899 | "#299c46",
900 | "rgba(237, 129, 40, 0.89)",
901 | "#d44a3a"
902 | ],
903 | "datasource": "${DS_PROMETHEUS}",
904 | "format": "none",
905 | "gauge": {
906 | "maxValue": 100,
907 | "minValue": 0,
908 | "show": false,
909 | "thresholdLabels": false,
910 | "thresholdMarkers": true
911 | },
912 | "gridPos": {
913 | "h": 5,
914 | "w": 6,
915 | "x": 6,
916 | "y": 11
917 | },
918 | "id": 18,
919 | "interval": null,
920 | "links": [],
921 | "mappingType": 1,
922 | "mappingTypes": [
923 | {
924 | "name": "value to text",
925 | "value": 1
926 | },
927 | {
928 | "name": "range to text",
929 | "value": 2
930 | }
931 | ],
932 | "maxDataPoints": 100,
933 | "nullPointMode": "connected",
934 | "nullText": null,
935 | "postfix": "",
936 | "postfixFontSize": "50%",
937 | "prefix": "",
938 | "prefixFontSize": "50%",
939 | "rangeMaps": [
940 | {
941 | "from": "null",
942 | "text": "N/A",
943 | "to": "null"
944 | }
945 | ],
946 | "sparkline": {
947 | "fillColor": "rgba(31, 118, 189, 0.18)",
948 | "full": false,
949 | "lineColor": "rgb(31, 120, 193)",
950 | "show": false
951 | },
952 | "tableColumn": "",
953 | "targets": [
954 | {
955 | "expr": "sum(kube_deployment_status_replicas{namespace=~\"$namespace\"})",
956 | "format": "time_series",
957 | "intervalFactor": 1,
958 | "refId": "A"
959 | }
960 | ],
961 | "thresholds": "",
962 | "title": "Deployment Replicas",
963 | "type": "singlestat",
964 | "valueFontSize": "80%",
965 | "valueMaps": [
966 | {
967 | "op": "=",
968 | "text": "N/A",
969 | "value": "null"
970 | }
971 | ],
972 | "valueName": "avg"
973 | },
974 | {
975 | "cacheTimeout": null,
976 | "colorBackground": false,
977 | "colorValue": false,
978 | "colors": [
979 | "#299c46",
980 | "rgba(237, 129, 40, 0.89)",
981 | "#d44a3a"
982 | ],
983 | "datasource": "${DS_PROMETHEUS}",
984 | "format": "none",
985 | "gauge": {
986 | "maxValue": 100,
987 | "minValue": 0,
988 | "show": false,
989 | "thresholdLabels": false,
990 | "thresholdMarkers": true
991 | },
992 | "gridPos": {
993 | "h": 5,
994 | "w": 6,
995 | "x": 12,
996 | "y": 11
997 | },
998 | "id": 19,
999 | "interval": null,
1000 | "links": [],
1001 | "mappingType": 1,
1002 | "mappingTypes": [
1003 | {
1004 | "name": "value to text",
1005 | "value": 1
1006 | },
1007 | {
1008 | "name": "range to text",
1009 | "value": 2
1010 | }
1011 | ],
1012 | "maxDataPoints": 100,
1013 | "nullPointMode": "connected",
1014 | "nullText": null,
1015 | "postfix": "",
1016 | "postfixFontSize": "50%",
1017 | "prefix": "",
1018 | "prefixFontSize": "50%",
1019 | "rangeMaps": [
1020 | {
1021 | "from": "null",
1022 | "text": "N/A",
1023 | "to": "null"
1024 | }
1025 | ],
1026 | "sparkline": {
1027 | "fillColor": "rgba(31, 118, 189, 0.18)",
1028 | "full": false,
1029 | "lineColor": "rgb(31, 120, 193)",
1030 | "show": false
1031 | },
1032 | "tableColumn": "",
1033 | "targets": [
1034 | {
1035 | "expr": "sum(kube_deployment_status_replicas_updated{namespace=~\"$namespace\"})",
1036 | "format": "time_series",
1037 | "intervalFactor": 1,
1038 | "refId": "A"
1039 | }
1040 | ],
1041 | "thresholds": "",
1042 | "title": "Deployment Replicas - Updated",
1043 | "type": "singlestat",
1044 | "valueFontSize": "80%",
1045 | "valueMaps": [
1046 | {
1047 | "op": "=",
1048 | "text": "N/A",
1049 | "value": "null"
1050 | }
1051 | ],
1052 | "valueName": "avg"
1053 | },
1054 | {
1055 | "cacheTimeout": null,
1056 | "colorBackground": false,
1057 | "colorValue": false,
1058 | "colors": [
1059 | "#299c46",
1060 | "rgba(237, 129, 40, 0.89)",
1061 | "#d44a3a"
1062 | ],
1063 | "datasource": "${DS_PROMETHEUS}",
1064 | "format": "none",
1065 | "gauge": {
1066 | "maxValue": 100,
1067 | "minValue": 0,
1068 | "show": false,
1069 | "thresholdLabels": false,
1070 | "thresholdMarkers": true
1071 | },
1072 | "gridPos": {
1073 | "h": 5,
1074 | "w": 6,
1075 | "x": 18,
1076 | "y": 11
1077 | },
1078 | "id": 20,
1079 | "interval": null,
1080 | "links": [],
1081 | "mappingType": 1,
1082 | "mappingTypes": [
1083 | {
1084 | "name": "value to text",
1085 | "value": 1
1086 | },
1087 | {
1088 | "name": "range to text",
1089 | "value": 2
1090 | }
1091 | ],
1092 | "maxDataPoints": 100,
1093 | "nullPointMode": "connected",
1094 | "nullText": null,
1095 | "postfix": "",
1096 | "postfixFontSize": "50%",
1097 | "prefix": "",
1098 | "prefixFontSize": "50%",
1099 | "rangeMaps": [
1100 | {
1101 | "from": "null",
1102 | "text": "N/A",
1103 | "to": "null"
1104 | }
1105 | ],
1106 | "sparkline": {
1107 | "fillColor": "rgba(31, 118, 189, 0.18)",
1108 | "full": false,
1109 | "lineColor": "rgb(31, 120, 193)",
1110 | "show": false
1111 | },
1112 | "tableColumn": "",
1113 | "targets": [
1114 | {
1115 | "expr": "sum(kube_deployment_status_replicas_unavailable{namespace=~\"$namespace\"})",
1116 | "format": "time_series",
1117 | "intervalFactor": 1,
1118 | "refId": "A"
1119 | }
1120 | ],
1121 | "thresholds": "",
1122 | "title": "Deployment Replicas - Unavailable",
1123 | "type": "singlestat",
1124 | "valueFontSize": "80%",
1125 | "valueMaps": [
1126 | {
1127 | "op": "=",
1128 | "text": "N/A",
1129 | "value": "null"
1130 | }
1131 | ],
1132 | "valueName": "avg"
1133 | },
1134 | {
1135 | "collapsed": false,
1136 | "gridPos": {
1137 | "h": 1,
1138 | "w": 24,
1139 | "x": 0,
1140 | "y": 16
1141 | },
1142 | "id": 22,
1143 | "panels": [],
1144 | "title": "Node",
1145 | "type": "row"
1146 | },
1147 | {
1148 | "cacheTimeout": null,
1149 | "colorBackground": false,
1150 | "colorValue": false,
1151 | "colors": [
1152 | "#299c46",
1153 | "rgba(237, 129, 40, 0.89)",
1154 | "#d44a3a"
1155 | ],
1156 | "datasource": "${DS_PROMETHEUS}",
1157 | "format": "none",
1158 | "gauge": {
1159 | "maxValue": 100,
1160 | "minValue": 0,
1161 | "show": false,
1162 | "thresholdLabels": false,
1163 | "thresholdMarkers": true
1164 | },
1165 | "gridPos": {
1166 | "h": 3,
1167 | "w": 8,
1168 | "x": 0,
1169 | "y": 17
1170 | },
1171 | "id": 24,
1172 | "interval": null,
1173 | "links": [],
1174 | "mappingType": 1,
1175 | "mappingTypes": [
1176 | {
1177 | "name": "value to text",
1178 | "value": 1
1179 | },
1180 | {
1181 | "name": "range to text",
1182 | "value": 2
1183 | }
1184 | ],
1185 | "maxDataPoints": 100,
1186 | "nullPointMode": "connected",
1187 | "nullText": null,
1188 | "postfix": "",
1189 | "postfixFontSize": "50%",
1190 | "prefix": "",
1191 | "prefixFontSize": "50%",
1192 | "rangeMaps": [
1193 | {
1194 | "from": "null",
1195 | "text": "N/A",
1196 | "to": "null"
1197 | }
1198 | ],
1199 | "sparkline": {
1200 | "fillColor": "rgba(31, 118, 189, 0.18)",
1201 | "full": false,
1202 | "lineColor": "rgb(31, 120, 193)",
1203 | "show": false
1204 | },
1205 | "tableColumn": "",
1206 | "targets": [
1207 | {
1208 | "expr": "sum(kube_node_info{node=~\"$node\"})",
1209 | "format": "time_series",
1210 | "intervalFactor": 1,
1211 | "refId": "A"
1212 | }
1213 | ],
1214 | "thresholds": "",
1215 | "title": "Number Of Nodes",
1216 | "type": "singlestat",
1217 | "valueFontSize": "80%",
1218 | "valueMaps": [
1219 | {
1220 | "op": "=",
1221 | "text": "N/A",
1222 | "value": "null"
1223 | }
1224 | ],
1225 | "valueName": "avg"
1226 | },
1227 | {
1228 | "cacheTimeout": null,
1229 | "colorBackground": true,
1230 | "colorValue": false,
1231 | "colors": [
1232 | "#299c46",
1233 | "rgba(237, 129, 40, 0.89)",
1234 | "#d44a3a"
1235 | ],
1236 | "datasource": "${DS_PROMETHEUS}",
1237 | "format": "none",
1238 | "gauge": {
1239 | "maxValue": 100,
1240 | "minValue": 0,
1241 | "show": false,
1242 | "thresholdLabels": false,
1243 | "thresholdMarkers": true
1244 | },
1245 | "gridPos": {
1246 | "h": 3,
1247 | "w": 8,
1248 | "x": 8,
1249 | "y": 17
1250 | },
1251 | "id": 25,
1252 | "interval": null,
1253 | "links": [],
1254 | "mappingType": 1,
1255 | "mappingTypes": [
1256 | {
1257 | "name": "value to text",
1258 | "value": 1
1259 | },
1260 | {
1261 | "name": "range to text",
1262 | "value": 2
1263 | }
1264 | ],
1265 | "maxDataPoints": 100,
1266 | "nullPointMode": "connected",
1267 | "nullText": null,
1268 | "postfix": "",
1269 | "postfixFontSize": "50%",
1270 | "prefix": "",
1271 | "prefixFontSize": "50%",
1272 | "rangeMaps": [
1273 | {
1274 | "from": "null",
1275 | "text": "N/A",
1276 | "to": "null"
1277 | }
1278 | ],
1279 | "sparkline": {
1280 | "fillColor": "rgba(31, 118, 189, 0.18)",
1281 | "full": false,
1282 | "lineColor": "rgb(31, 120, 193)",
1283 | "show": false
1284 | },
1285 | "tableColumn": "",
1286 | "targets": [
1287 | {
1288 | "expr": "sum(kube_node_status_condition{condition=\"OutOfDisk\", node=~\"$node\", status=\"true\"})",
1289 | "format": "time_series",
1290 | "intervalFactor": 1,
1291 | "refId": "A"
1292 | }
1293 | ],
1294 | "thresholds": "1",
1295 | "title": "Nodes Out of Disk",
1296 | "type": "singlestat",
1297 | "valueFontSize": "80%",
1298 | "valueMaps": [
1299 | {
1300 | "op": "=",
1301 | "text": "N/A",
1302 | "value": "null"
1303 | }
1304 | ],
1305 | "valueName": "current"
1306 | },
1307 | {
1308 | "cacheTimeout": null,
1309 | "colorBackground": true,
1310 | "colorValue": false,
1311 | "colors": [
1312 | "#299c46",
1313 | "rgba(237, 129, 40, 0.89)",
1314 | "#d44a3a"
1315 | ],
1316 | "datasource": "${DS_PROMETHEUS}",
1317 | "format": "none",
1318 | "gauge": {
1319 | "maxValue": 100,
1320 | "minValue": 0,
1321 | "show": false,
1322 | "thresholdLabels": false,
1323 | "thresholdMarkers": true
1324 | },
1325 | "gridPos": {
1326 | "h": 3,
1327 | "w": 8,
1328 | "x": 16,
1329 | "y": 17
1330 | },
1331 | "id": 26,
1332 | "interval": null,
1333 | "links": [],
1334 | "mappingType": 1,
1335 | "mappingTypes": [
1336 | {
1337 | "name": "value to text",
1338 | "value": 1
1339 | },
1340 | {
1341 | "name": "range to text",
1342 | "value": 2
1343 | }
1344 | ],
1345 | "maxDataPoints": 100,
1346 | "nullPointMode": "connected",
1347 | "nullText": null,
1348 | "postfix": "",
1349 | "postfixFontSize": "50%",
1350 | "prefix": "",
1351 | "prefixFontSize": "50%",
1352 | "rangeMaps": [
1353 | {
1354 | "from": "null",
1355 | "text": "N/A",
1356 | "to": "null"
1357 | }
1358 | ],
1359 | "sparkline": {
1360 | "fillColor": "rgba(31, 118, 189, 0.18)",
1361 | "full": false,
1362 | "lineColor": "rgb(31, 120, 193)",
1363 | "show": false
1364 | },
1365 | "tableColumn": "",
1366 | "targets": [
1367 | {
1368 | "expr": "sum(kube_node_spec_unschedulable{node=~\"$node\"})",
1369 | "format": "time_series",
1370 | "intervalFactor": 1,
1371 | "refId": "A"
1372 | }
1373 | ],
1374 | "thresholds": "1",
1375 | "title": "Nodes Unavailable",
1376 | "type": "singlestat",
1377 | "valueFontSize": "80%",
1378 | "valueMaps": [
1379 | {
1380 | "op": "=",
1381 | "text": "N/A",
1382 | "value": "null"
1383 | }
1384 | ],
1385 | "valueName": "current"
1386 | },
1387 | {
1388 | "collapsed": false,
1389 | "gridPos": {
1390 | "h": 1,
1391 | "w": 24,
1392 | "x": 0,
1393 | "y": 20
1394 | },
1395 | "id": 28,
1396 | "panels": [],
1397 | "title": "Pods",
1398 | "type": "row"
1399 | },
1400 | {
1401 | "cacheTimeout": null,
1402 | "colorBackground": false,
1403 | "colorValue": false,
1404 | "colors": [
1405 | "#299c46",
1406 | "rgba(237, 129, 40, 0.89)",
1407 | "#d44a3a"
1408 | ],
1409 | "datasource": "${DS_PROMETHEUS}",
1410 | "format": "none",
1411 | "gauge": {
1412 | "maxValue": 100,
1413 | "minValue": 0,
1414 | "show": false,
1415 | "thresholdLabels": false,
1416 | "thresholdMarkers": true
1417 | },
1418 | "gridPos": {
1419 | "h": 3,
1420 | "w": 12,
1421 | "x": 0,
1422 | "y": 21
1423 | },
1424 | "id": 30,
1425 | "interval": null,
1426 | "links": [],
1427 | "mappingType": 1,
1428 | "mappingTypes": [
1429 | {
1430 | "name": "value to text",
1431 | "value": 1
1432 | },
1433 | {
1434 | "name": "range to text",
1435 | "value": 2
1436 | }
1437 | ],
1438 | "maxDataPoints": 100,
1439 | "nullPointMode": "connected",
1440 | "nullText": null,
1441 | "postfix": "",
1442 | "postfixFontSize": "50%",
1443 | "prefix": "",
1444 | "prefixFontSize": "50%",
1445 | "rangeMaps": [
1446 | {
1447 | "from": "null",
1448 | "text": "N/A",
1449 | "to": "null"
1450 | }
1451 | ],
1452 | "sparkline": {
1453 | "fillColor": "rgba(78, 203, 42, 0.28)",
1454 | "full": false,
1455 | "lineColor": "#629e51",
1456 | "show": true
1457 | },
1458 | "tableColumn": "",
1459 | "targets": [
1460 | {
1461 | "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Running\"})",
1462 | "format": "time_series",
1463 | "interval": "",
1464 | "intervalFactor": 1,
1465 | "refId": "A"
1466 | }
1467 | ],
1468 | "thresholds": "",
1469 | "title": "Pods Running",
1470 | "type": "singlestat",
1471 | "valueFontSize": "80%",
1472 | "valueMaps": [
1473 | {
1474 | "op": "=",
1475 | "text": "N/A",
1476 | "value": "null"
1477 | }
1478 | ],
1479 | "valueName": "current"
1480 | },
1481 | {
1482 | "cacheTimeout": null,
1483 | "colorBackground": false,
1484 | "colorValue": false,
1485 | "colors": [
1486 | "#299c46",
1487 | "rgba(237, 129, 40, 0.89)",
1488 | "#d44a3a"
1489 | ],
1490 | "datasource": "${DS_PROMETHEUS}",
1491 | "format": "none",
1492 | "gauge": {
1493 | "maxValue": 100,
1494 | "minValue": 0,
1495 | "show": false,
1496 | "thresholdLabels": false,
1497 | "thresholdMarkers": true
1498 | },
1499 | "gridPos": {
1500 | "h": 3,
1501 | "w": 12,
1502 | "x": 12,
1503 | "y": 21
1504 | },
1505 | "id": 31,
1506 | "interval": null,
1507 | "links": [],
1508 | "mappingType": 1,
1509 | "mappingTypes": [
1510 | {
1511 | "name": "value to text",
1512 | "value": 1
1513 | },
1514 | {
1515 | "name": "range to text",
1516 | "value": 2
1517 | }
1518 | ],
1519 | "maxDataPoints": 100,
1520 | "nullPointMode": "connected",
1521 | "nullText": null,
1522 | "postfix": "",
1523 | "postfixFontSize": "50%",
1524 | "prefix": "",
1525 | "prefixFontSize": "50%",
1526 | "rangeMaps": [
1527 | {
1528 | "from": "null",
1529 | "text": "N/A",
1530 | "to": "null"
1531 | }
1532 | ],
1533 | "sparkline": {
1534 | "fillColor": "rgba(78, 203, 42, 0.28)",
1535 | "full": false,
1536 | "lineColor": "#629e51",
1537 | "show": true
1538 | },
1539 | "tableColumn": "",
1540 | "targets": [
1541 | {
1542 | "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Pending\"})",
1543 | "format": "time_series",
1544 | "interval": "",
1545 | "intervalFactor": 1,
1546 | "refId": "A"
1547 | }
1548 | ],
1549 | "thresholds": "",
1550 | "title": "Pods Pending",
1551 | "type": "singlestat",
1552 | "valueFontSize": "80%",
1553 | "valueMaps": [
1554 | {
1555 | "op": "=",
1556 | "text": "N/A",
1557 | "value": "null"
1558 | }
1559 | ],
1560 | "valueName": "current"
1561 | },
1562 | {
1563 | "cacheTimeout": null,
1564 | "colorBackground": false,
1565 | "colorValue": false,
1566 | "colors": [
1567 | "#299c46",
1568 | "rgba(237, 129, 40, 0.89)",
1569 | "#d44a3a"
1570 | ],
1571 | "datasource": "${DS_PROMETHEUS}",
1572 | "format": "none",
1573 | "gauge": {
1574 | "maxValue": 100,
1575 | "minValue": 0,
1576 | "show": false,
1577 | "thresholdLabels": false,
1578 | "thresholdMarkers": true
1579 | },
1580 | "gridPos": {
1581 | "h": 3,
1582 | "w": 8,
1583 | "x": 0,
1584 | "y": 24
1585 | },
1586 | "id": 32,
1587 | "interval": null,
1588 | "links": [],
1589 | "mappingType": 1,
1590 | "mappingTypes": [
1591 | {
1592 | "name": "value to text",
1593 | "value": 1
1594 | },
1595 | {
1596 | "name": "range to text",
1597 | "value": 2
1598 | }
1599 | ],
1600 | "maxDataPoints": 100,
1601 | "nullPointMode": "connected",
1602 | "nullText": null,
1603 | "postfix": "",
1604 | "postfixFontSize": "50%",
1605 | "prefix": "",
1606 | "prefixFontSize": "50%",
1607 | "rangeMaps": [
1608 | {
1609 | "from": "null",
1610 | "text": "N/A",
1611 | "to": "null"
1612 | }
1613 | ],
1614 | "sparkline": {
1615 | "fillColor": "rgba(78, 203, 42, 0.28)",
1616 | "full": false,
1617 | "lineColor": "#629e51",
1618 | "show": true
1619 | },
1620 | "tableColumn": "",
1621 | "targets": [
1622 | {
1623 | "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Failed\"})",
1624 | "format": "time_series",
1625 | "interval": "",
1626 | "intervalFactor": 1,
1627 | "refId": "A"
1628 | }
1629 | ],
1630 | "thresholds": "",
1631 | "title": "Pods Failed",
1632 | "type": "singlestat",
1633 | "valueFontSize": "80%",
1634 | "valueMaps": [
1635 | {
1636 | "op": "=",
1637 | "text": "N/A",
1638 | "value": "null"
1639 | }
1640 | ],
1641 | "valueName": "current"
1642 | },
1643 | {
1644 | "cacheTimeout": null,
1645 | "colorBackground": false,
1646 | "colorValue": false,
1647 | "colors": [
1648 | "#299c46",
1649 | "rgba(237, 129, 40, 0.89)",
1650 | "#d44a3a"
1651 | ],
1652 | "datasource": "${DS_PROMETHEUS}",
1653 | "format": "none",
1654 | "gauge": {
1655 | "maxValue": 100,
1656 | "minValue": 0,
1657 | "show": false,
1658 | "thresholdLabels": false,
1659 | "thresholdMarkers": true
1660 | },
1661 | "gridPos": {
1662 | "h": 3,
1663 | "w": 8,
1664 | "x": 8,
1665 | "y": 24
1666 | },
1667 | "id": 33,
1668 | "interval": null,
1669 | "links": [],
1670 | "mappingType": 1,
1671 | "mappingTypes": [
1672 | {
1673 | "name": "value to text",
1674 | "value": 1
1675 | },
1676 | {
1677 | "name": "range to text",
1678 | "value": 2
1679 | }
1680 | ],
1681 | "maxDataPoints": 100,
1682 | "nullPointMode": "connected",
1683 | "nullText": null,
1684 | "postfix": "",
1685 | "postfixFontSize": "50%",
1686 | "prefix": "",
1687 | "prefixFontSize": "50%",
1688 | "rangeMaps": [
1689 | {
1690 | "from": "null",
1691 | "text": "N/A",
1692 | "to": "null"
1693 | }
1694 | ],
1695 | "sparkline": {
1696 | "fillColor": "rgba(78, 203, 42, 0.28)",
1697 | "full": false,
1698 | "lineColor": "#629e51",
1699 | "show": true
1700 | },
1701 | "tableColumn": "",
1702 | "targets": [
1703 | {
1704 | "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Succeeded\"})",
1705 | "format": "time_series",
1706 | "interval": "",
1707 | "intervalFactor": 1,
1708 | "refId": "A"
1709 | }
1710 | ],
1711 | "thresholds": "",
1712 | "title": "Pods Succeeded",
1713 | "type": "singlestat",
1714 | "valueFontSize": "80%",
1715 | "valueMaps": [
1716 | {
1717 | "op": "=",
1718 | "text": "N/A",
1719 | "value": "null"
1720 | }
1721 | ],
1722 | "valueName": "current"
1723 | },
1724 | {
1725 | "cacheTimeout": null,
1726 | "colorBackground": false,
1727 | "colorValue": false,
1728 | "colors": [
1729 | "#299c46",
1730 | "rgba(237, 129, 40, 0.89)",
1731 | "#d44a3a"
1732 | ],
1733 | "datasource": "${DS_PROMETHEUS}",
1734 | "format": "none",
1735 | "gauge": {
1736 | "maxValue": 100,
1737 | "minValue": 0,
1738 | "show": false,
1739 | "thresholdLabels": false,
1740 | "thresholdMarkers": true
1741 | },
1742 | "gridPos": {
1743 | "h": 3,
1744 | "w": 8,
1745 | "x": 16,
1746 | "y": 24
1747 | },
1748 | "id": 34,
1749 | "interval": null,
1750 | "links": [],
1751 | "mappingType": 1,
1752 | "mappingTypes": [
1753 | {
1754 | "name": "value to text",
1755 | "value": 1
1756 | },
1757 | {
1758 | "name": "range to text",
1759 | "value": 2
1760 | }
1761 | ],
1762 | "maxDataPoints": 100,
1763 | "nullPointMode": "connected",
1764 | "nullText": null,
1765 | "postfix": "",
1766 | "postfixFontSize": "50%",
1767 | "prefix": "",
1768 | "prefixFontSize": "50%",
1769 | "rangeMaps": [
1770 | {
1771 | "from": "null",
1772 | "text": "N/A",
1773 | "to": "null"
1774 | }
1775 | ],
1776 | "sparkline": {
1777 | "fillColor": "rgba(78, 203, 42, 0.28)",
1778 | "full": false,
1779 | "lineColor": "#629e51",
1780 | "show": true
1781 | },
1782 | "tableColumn": "",
1783 | "targets": [
1784 | {
1785 | "expr": "sum(kube_pod_status_phase{namespace=~\"$namespace\", phase=\"Unknown\"})",
1786 | "format": "time_series",
1787 | "interval": "",
1788 | "intervalFactor": 1,
1789 | "refId": "A"
1790 | }
1791 | ],
1792 | "thresholds": "",
1793 | "title": "Pods Unknown",
1794 | "type": "singlestat",
1795 | "valueFontSize": "80%",
1796 | "valueMaps": [
1797 | {
1798 | "op": "=",
1799 | "text": "N/A",
1800 | "value": "null"
1801 | }
1802 | ],
1803 | "valueName": "current"
1804 | },
1805 | {
1806 | "collapsed": false,
1807 | "gridPos": {
1808 | "h": 1,
1809 | "w": 24,
1810 | "x": 0,
1811 | "y": 27
1812 | },
1813 | "id": 36,
1814 | "panels": [],
1815 | "title": "Containers",
1816 | "type": "row"
1817 | },
1818 | {
1819 | "cacheTimeout": null,
1820 | "colorBackground": false,
1821 | "colorValue": false,
1822 | "colors": [
1823 | "#299c46",
1824 | "rgba(237, 129, 40, 0.89)",
1825 | "#d44a3a"
1826 | ],
1827 | "datasource": "${DS_PROMETHEUS}",
1828 | "format": "none",
1829 | "gauge": {
1830 | "maxValue": 100,
1831 | "minValue": 0,
1832 | "show": false,
1833 | "thresholdLabels": false,
1834 | "thresholdMarkers": true
1835 | },
1836 | "gridPos": {
1837 | "h": 3,
1838 | "w": 6,
1839 | "x": 0,
1840 | "y": 28
1841 | },
1842 | "id": 38,
1843 | "interval": null,
1844 | "links": [],
1845 | "mappingType": 1,
1846 | "mappingTypes": [
1847 | {
1848 | "name": "value to text",
1849 | "value": 1
1850 | },
1851 | {
1852 | "name": "range to text",
1853 | "value": 2
1854 | }
1855 | ],
1856 | "maxDataPoints": 100,
1857 | "nullPointMode": "connected",
1858 | "nullText": null,
1859 | "postfix": "",
1860 | "postfixFontSize": "50%",
1861 | "prefix": "",
1862 | "prefixFontSize": "50%",
1863 | "rangeMaps": [
1864 | {
1865 | "from": "null",
1866 | "text": "N/A",
1867 | "to": "null"
1868 | }
1869 | ],
1870 | "sparkline": {
1871 | "fillColor": "rgba(31, 118, 189, 0.18)",
1872 | "full": false,
1873 | "lineColor": "rgb(31, 120, 193)",
1874 | "show": true
1875 | },
1876 | "tableColumn": "",
1877 | "targets": [
1878 | {
1879 | "expr": "sum(kube_pod_container_status_running{namespace=~\"$namespace\"})",
1880 | "format": "time_series",
1881 | "intervalFactor": 1,
1882 | "refId": "A"
1883 | }
1884 | ],
1885 | "thresholds": "",
1886 | "title": "Containers Running",
1887 | "type": "singlestat",
1888 | "valueFontSize": "80%",
1889 | "valueMaps": [
1890 | {
1891 | "op": "=",
1892 | "text": "N/A",
1893 | "value": "null"
1894 | }
1895 | ],
1896 | "valueName": "current"
1897 | },
1898 | {
1899 | "cacheTimeout": null,
1900 | "colorBackground": false,
1901 | "colorValue": false,
1902 | "colors": [
1903 | "#299c46",
1904 | "rgba(237, 129, 40, 0.89)",
1905 | "#d44a3a"
1906 | ],
1907 | "datasource": "${DS_PROMETHEUS}",
1908 | "format": "none",
1909 | "gauge": {
1910 | "maxValue": 100,
1911 | "minValue": 0,
1912 | "show": false,
1913 | "thresholdLabels": false,
1914 | "thresholdMarkers": true
1915 | },
1916 | "gridPos": {
1917 | "h": 3,
1918 | "w": 6,
1919 | "x": 6,
1920 | "y": 28
1921 | },
1922 | "id": 39,
1923 | "interval": null,
1924 | "links": [],
1925 | "mappingType": 1,
1926 | "mappingTypes": [
1927 | {
1928 | "name": "value to text",
1929 | "value": 1
1930 | },
1931 | {
1932 | "name": "range to text",
1933 | "value": 2
1934 | }
1935 | ],
1936 | "maxDataPoints": 100,
1937 | "nullPointMode": "connected",
1938 | "nullText": null,
1939 | "postfix": "",
1940 | "postfixFontSize": "50%",
1941 | "prefix": "",
1942 | "prefixFontSize": "50%",
1943 | "rangeMaps": [
1944 | {
1945 | "from": "null",
1946 | "text": "N/A",
1947 | "to": "null"
1948 | }
1949 | ],
1950 | "sparkline": {
1951 | "fillColor": "rgba(31, 118, 189, 0.18)",
1952 | "full": false,
1953 | "lineColor": "rgb(31, 120, 193)",
1954 | "show": true
1955 | },
1956 | "tableColumn": "",
1957 | "targets": [
1958 | {
1959 | "expr": "sum(kube_pod_container_status_waiting{namespace=~\"$namespace\"})",
1960 | "format": "time_series",
1961 | "intervalFactor": 1,
1962 | "refId": "A"
1963 | }
1964 | ],
1965 | "thresholds": "",
1966 | "title": "Containers Waiting",
1967 | "type": "singlestat",
1968 | "valueFontSize": "80%",
1969 | "valueMaps": [
1970 | {
1971 | "op": "=",
1972 | "text": "N/A",
1973 | "value": "null"
1974 | }
1975 | ],
1976 | "valueName": "current"
1977 | },
1978 | {
1979 | "cacheTimeout": null,
1980 | "colorBackground": false,
1981 | "colorValue": false,
1982 | "colors": [
1983 | "#299c46",
1984 | "rgba(237, 129, 40, 0.89)",
1985 | "#d44a3a"
1986 | ],
1987 | "datasource": "${DS_PROMETHEUS}",
1988 | "format": "none",
1989 | "gauge": {
1990 | "maxValue": 100,
1991 | "minValue": 0,
1992 | "show": false,
1993 | "thresholdLabels": false,
1994 | "thresholdMarkers": true
1995 | },
1996 | "gridPos": {
1997 | "h": 3,
1998 | "w": 6,
1999 | "x": 12,
2000 | "y": 28
2001 | },
2002 | "id": 40,
2003 | "interval": null,
2004 | "links": [],
2005 | "mappingType": 1,
2006 | "mappingTypes": [
2007 | {
2008 | "name": "value to text",
2009 | "value": 1
2010 | },
2011 | {
2012 | "name": "range to text",
2013 | "value": 2
2014 | }
2015 | ],
2016 | "maxDataPoints": 100,
2017 | "nullPointMode": "connected",
2018 | "nullText": null,
2019 | "postfix": "",
2020 | "postfixFontSize": "50%",
2021 | "prefix": "",
2022 | "prefixFontSize": "50%",
2023 | "rangeMaps": [
2024 | {
2025 | "from": "null",
2026 | "text": "N/A",
2027 | "to": "null"
2028 | }
2029 | ],
2030 | "sparkline": {
2031 | "fillColor": "rgba(31, 118, 189, 0.18)",
2032 | "full": false,
2033 | "lineColor": "rgb(31, 120, 193)",
2034 | "show": true
2035 | },
2036 | "tableColumn": "",
2037 | "targets": [
2038 | {
2039 | "expr": "sum(kube_pod_container_status_terminated{namespace=~\"$namespace\"})",
2040 | "format": "time_series",
2041 | "intervalFactor": 1,
2042 | "refId": "A"
2043 | }
2044 | ],
2045 | "thresholds": "",
2046 | "title": "Containers Terminated",
2047 | "type": "singlestat",
2048 | "valueFontSize": "80%",
2049 | "valueMaps": [
2050 | {
2051 | "op": "=",
2052 | "text": "N/A",
2053 | "value": "null"
2054 | }
2055 | ],
2056 | "valueName": "current"
2057 | },
2058 | {
2059 | "cacheTimeout": null,
2060 | "colorBackground": false,
2061 | "colorValue": false,
2062 | "colors": [
2063 | "#299c46",
2064 | "rgba(237, 129, 40, 0.89)",
2065 | "#d44a3a"
2066 | ],
2067 | "datasource": "${DS_PROMETHEUS}",
2068 | "format": "none",
2069 | "gauge": {
2070 | "maxValue": 100,
2071 | "minValue": 0,
2072 | "show": false,
2073 | "thresholdLabels": false,
2074 | "thresholdMarkers": true
2075 | },
2076 | "gridPos": {
2077 | "h": 3,
2078 | "w": 6,
2079 | "x": 18,
2080 | "y": 28
2081 | },
2082 | "id": 41,
2083 | "interval": null,
2084 | "links": [],
2085 | "mappingType": 1,
2086 | "mappingTypes": [
2087 | {
2088 | "name": "value to text",
2089 | "value": 1
2090 | },
2091 | {
2092 | "name": "range to text",
2093 | "value": 2
2094 | }
2095 | ],
2096 | "maxDataPoints": 100,
2097 | "nullPointMode": "connected",
2098 | "nullText": null,
2099 | "postfix": "",
2100 | "postfixFontSize": "50%",
2101 | "prefix": "",
2102 | "prefixFontSize": "50%",
2103 | "rangeMaps": [
2104 | {
2105 | "from": "null",
2106 | "text": "N/A",
2107 | "to": "null"
2108 | }
2109 | ],
2110 | "sparkline": {
2111 | "fillColor": "rgba(31, 118, 189, 0.18)",
2112 | "full": false,
2113 | "lineColor": "rgb(31, 120, 193)",
2114 | "show": true
2115 | },
2116 | "tableColumn": "",
2117 | "targets": [
2118 | {
2119 | "expr": "sum(delta(kube_pod_container_status_restarts{namespace=\"kube-system\"}[30m]))",
2120 | "format": "time_series",
2121 | "intervalFactor": 1,
2122 | "refId": "A"
2123 | }
2124 | ],
2125 | "thresholds": "",
2126 | "title": "Containers Restarts (Last 30 Minutes)",
2127 | "type": "singlestat",
2128 | "valueFontSize": "80%",
2129 | "valueMaps": [
2130 | {
2131 | "op": "=",
2132 | "text": "N/A",
2133 | "value": "null"
2134 | }
2135 | ],
2136 | "valueName": "current"
2137 | },
2138 | {
2139 | "cacheTimeout": null,
2140 | "colorBackground": false,
2141 | "colorValue": false,
2142 | "colors": [
2143 | "#299c46",
2144 | "rgba(237, 129, 40, 0.89)",
2145 | "#d44a3a"
2146 | ],
2147 | "datasource": "${DS_PROMETHEUS}",
2148 | "format": "none",
2149 | "gauge": {
2150 | "maxValue": 100,
2151 | "minValue": 0,
2152 | "show": false,
2153 | "thresholdLabels": false,
2154 | "thresholdMarkers": true
2155 | },
2156 | "gridPos": {
2157 | "h": 3,
2158 | "w": 12,
2159 | "x": 0,
2160 | "y": 31
2161 | },
2162 | "id": 43,
2163 | "interval": null,
2164 | "links": [],
2165 | "mappingType": 1,
2166 | "mappingTypes": [
2167 | {
2168 | "name": "value to text",
2169 | "value": 1
2170 | },
2171 | {
2172 | "name": "range to text",
2173 | "value": 2
2174 | }
2175 | ],
2176 | "maxDataPoints": 100,
2177 | "nullPointMode": "connected",
2178 | "nullText": null,
2179 | "postfix": "",
2180 | "postfixFontSize": "50%",
2181 | "prefix": "",
2182 | "prefixFontSize": "50%",
2183 | "rangeMaps": [
2184 | {
2185 | "from": "null",
2186 | "text": "N/A",
2187 | "to": "null"
2188 | }
2189 | ],
2190 | "sparkline": {
2191 | "fillColor": "rgba(31, 118, 189, 0.18)",
2192 | "full": false,
2193 | "lineColor": "rgb(31, 120, 193)",
2194 | "show": true
2195 | },
2196 | "tableColumn": "",
2197 | "targets": [
2198 | {
2199 | "expr": "sum(kube_pod_container_resource_requests_cpu_cores{namespace=~\"$namespace\", node=~\"$node\"})",
2200 | "format": "time_series",
2201 | "intervalFactor": 1,
2202 | "refId": "A"
2203 | }
2204 | ],
2205 | "thresholds": "",
2206 | "title": "CPU Cores Requested by Containers",
2207 | "type": "singlestat",
2208 | "valueFontSize": "80%",
2209 | "valueMaps": [
2210 | {
2211 | "op": "=",
2212 | "text": "N/A",
2213 | "value": "null"
2214 | }
2215 | ],
2216 | "valueName": "current"
2217 | },
2218 | {
2219 | "cacheTimeout": null,
2220 | "colorBackground": false,
2221 | "colorValue": false,
2222 | "colors": [
2223 | "#299c46",
2224 | "rgba(237, 129, 40, 0.89)",
2225 | "#d44a3a"
2226 | ],
2227 | "datasource": "${DS_PROMETHEUS}",
2228 | "format": "decbytes",
2229 | "gauge": {
2230 | "maxValue": 100,
2231 | "minValue": 0,
2232 | "show": false,
2233 | "thresholdLabels": false,
2234 | "thresholdMarkers": true
2235 | },
2236 | "gridPos": {
2237 | "h": 3,
2238 | "w": 12,
2239 | "x": 12,
2240 | "y": 31
2241 | },
2242 | "id": 42,
2243 | "interval": null,
2244 | "links": [],
2245 | "mappingType": 1,
2246 | "mappingTypes": [
2247 | {
2248 | "name": "value to text",
2249 | "value": 1
2250 | },
2251 | {
2252 | "name": "range to text",
2253 | "value": 2
2254 | }
2255 | ],
2256 | "maxDataPoints": 100,
2257 | "nullPointMode": "connected",
2258 | "nullText": null,
2259 | "postfix": "",
2260 | "postfixFontSize": "50%",
2261 | "prefix": "",
2262 | "prefixFontSize": "50%",
2263 | "rangeMaps": [
2264 | {
2265 | "from": "null",
2266 | "text": "N/A",
2267 | "to": "null"
2268 | }
2269 | ],
2270 | "sparkline": {
2271 | "fillColor": "rgba(31, 118, 189, 0.18)",
2272 | "full": false,
2273 | "lineColor": "rgb(31, 120, 193)",
2274 | "show": true
2275 | },
2276 | "tableColumn": "",
2277 | "targets": [
2278 | {
2279 | "expr": "sum(kube_pod_container_resource_requests_memory_bytes{namespace=~\"$namespace\", node=~\"$node\"})",
2280 | "format": "time_series",
2281 | "intervalFactor": 1,
2282 | "refId": "A"
2283 | }
2284 | ],
2285 | "thresholds": "",
2286 | "title": "Memory Requested By Containers",
2287 | "type": "singlestat",
2288 | "valueFontSize": "80%",
2289 | "valueMaps": [
2290 | {
2291 | "op": "=",
2292 | "text": "N/A",
2293 | "value": "null"
2294 | }
2295 | ],
2296 | "valueName": "current"
2297 | },
2298 | {
2299 | "collapsed": false,
2300 | "gridPos": {
2301 | "h": 1,
2302 | "w": 24,
2303 | "x": 0,
2304 | "y": 34
2305 | },
2306 | "id": 45,
2307 | "panels": [],
2308 | "title": "Jobs",
2309 | "type": "row"
2310 | },
2311 | {
2312 | "cacheTimeout": null,
2313 | "colorBackground": false,
2314 | "colorValue": false,
2315 | "colors": [
2316 | "#299c46",
2317 | "rgba(237, 129, 40, 0.89)",
2318 | "#d44a3a"
2319 | ],
2320 | "datasource": "${DS_PROMETHEUS}",
2321 | "format": "none",
2322 | "gauge": {
2323 | "maxValue": 100,
2324 | "minValue": 0,
2325 | "show": false,
2326 | "thresholdLabels": false,
2327 | "thresholdMarkers": true
2328 | },
2329 | "gridPos": {
2330 | "h": 3,
2331 | "w": 8,
2332 | "x": 0,
2333 | "y": 35
2334 | },
2335 | "id": 47,
2336 | "interval": null,
2337 | "links": [],
2338 | "mappingType": 1,
2339 | "mappingTypes": [
2340 | {
2341 | "name": "value to text",
2342 | "value": 1
2343 | },
2344 | {
2345 | "name": "range to text",
2346 | "value": 2
2347 | }
2348 | ],
2349 | "maxDataPoints": 100,
2350 | "nullPointMode": "connected",
2351 | "nullText": null,
2352 | "postfix": "",
2353 | "postfixFontSize": "50%",
2354 | "prefix": "",
2355 | "prefixFontSize": "50%",
2356 | "rangeMaps": [
2357 | {
2358 | "from": "null",
2359 | "text": "N/A",
2360 | "to": "null"
2361 | }
2362 | ],
2363 | "sparkline": {
2364 | "fillColor": "rgba(31, 118, 189, 0.18)",
2365 | "full": false,
2366 | "lineColor": "rgb(31, 120, 193)",
2367 | "show": true
2368 | },
2369 | "tableColumn": "",
2370 | "targets": [
2371 | {
2372 | "expr": "sum(kube_job_status_succeeded{namespace=~\"$namespace\"})",
2373 | "format": "time_series",
2374 | "intervalFactor": 1,
2375 | "refId": "A"
2376 | }
2377 | ],
2378 | "thresholds": "",
2379 | "title": "Jobs Succeeded",
2380 | "type": "singlestat",
2381 | "valueFontSize": "80%",
2382 | "valueMaps": [
2383 | {
2384 | "op": "=",
2385 | "text": "N/A",
2386 | "value": "null"
2387 | }
2388 | ],
2389 | "valueName": "current"
2390 | },
2391 | {
2392 | "cacheTimeout": null,
2393 | "colorBackground": false,
2394 | "colorValue": false,
2395 | "colors": [
2396 | "#299c46",
2397 | "rgba(237, 129, 40, 0.89)",
2398 | "#d44a3a"
2399 | ],
2400 | "datasource": "${DS_PROMETHEUS}",
2401 | "format": "none",
2402 | "gauge": {
2403 | "maxValue": 100,
2404 | "minValue": 0,
2405 | "show": false,
2406 | "thresholdLabels": false,
2407 | "thresholdMarkers": true
2408 | },
2409 | "gridPos": {
2410 | "h": 3,
2411 | "w": 8,
2412 | "x": 8,
2413 | "y": 35
2414 | },
2415 | "id": 48,
2416 | "interval": null,
2417 | "links": [],
2418 | "mappingType": 1,
2419 | "mappingTypes": [
2420 | {
2421 | "name": "value to text",
2422 | "value": 1
2423 | },
2424 | {
2425 | "name": "range to text",
2426 | "value": 2
2427 | }
2428 | ],
2429 | "maxDataPoints": 100,
2430 | "nullPointMode": "connected",
2431 | "nullText": null,
2432 | "postfix": "",
2433 | "postfixFontSize": "50%",
2434 | "prefix": "",
2435 | "prefixFontSize": "50%",
2436 | "rangeMaps": [
2437 | {
2438 | "from": "null",
2439 | "text": "N/A",
2440 | "to": "null"
2441 | }
2442 | ],
2443 | "sparkline": {
2444 | "fillColor": "rgba(31, 118, 189, 0.18)",
2445 | "full": false,
2446 | "lineColor": "rgb(31, 120, 193)",
2447 | "show": true
2448 | },
2449 | "tableColumn": "",
2450 | "targets": [
2451 | {
2452 | "expr": "sum(kube_job_status_active{namespace=~\"$namespace\"})",
2453 | "format": "time_series",
2454 | "intervalFactor": 1,
2455 | "refId": "A"
2456 | }
2457 | ],
2458 | "thresholds": "",
2459 | "title": "Jobs Succeeded",
2460 | "type": "singlestat",
2461 | "valueFontSize": "80%",
2462 | "valueMaps": [
2463 | {
2464 | "op": "=",
2465 | "text": "N/A",
2466 | "value": "null"
2467 | }
2468 | ],
2469 | "valueName": "current"
2470 | },
2471 | {
2472 | "cacheTimeout": null,
2473 | "colorBackground": false,
2474 | "colorValue": false,
2475 | "colors": [
2476 | "#299c46",
2477 | "rgba(237, 129, 40, 0.89)",
2478 | "#d44a3a"
2479 | ],
2480 | "datasource": "${DS_PROMETHEUS}",
2481 | "format": "none",
2482 | "gauge": {
2483 | "maxValue": 100,
2484 | "minValue": 0,
2485 | "show": false,
2486 | "thresholdLabels": false,
2487 | "thresholdMarkers": true
2488 | },
2489 | "gridPos": {
2490 | "h": 3,
2491 | "w": 8,
2492 | "x": 16,
2493 | "y": 35
2494 | },
2495 | "id": 49,
2496 | "interval": null,
2497 | "links": [],
2498 | "mappingType": 1,
2499 | "mappingTypes": [
2500 | {
2501 | "name": "value to text",
2502 | "value": 1
2503 | },
2504 | {
2505 | "name": "range to text",
2506 | "value": 2
2507 | }
2508 | ],
2509 | "maxDataPoints": 100,
2510 | "nullPointMode": "connected",
2511 | "nullText": null,
2512 | "postfix": "",
2513 | "postfixFontSize": "50%",
2514 | "prefix": "",
2515 | "prefixFontSize": "50%",
2516 | "rangeMaps": [
2517 | {
2518 | "from": "null",
2519 | "text": "N/A",
2520 | "to": "null"
2521 | }
2522 | ],
2523 | "sparkline": {
2524 | "fillColor": "rgba(31, 118, 189, 0.18)",
2525 | "full": false,
2526 | "lineColor": "rgb(31, 120, 193)",
2527 | "show": true
2528 | },
2529 | "tableColumn": "",
2530 | "targets": [
2531 | {
2532 | "expr": "sum(kube_job_status_failed{namespace=~\"$namespace\"})",
2533 | "format": "time_series",
2534 | "intervalFactor": 1,
2535 | "refId": "A"
2536 | }
2537 | ],
2538 | "thresholds": "",
2539 | "title": "Jobs Failed",
2540 | "type": "singlestat",
2541 | "valueFontSize": "80%",
2542 | "valueMaps": [
2543 | {
2544 | "op": "=",
2545 | "text": "N/A",
2546 | "value": "null"
2547 | }
2548 | ],
2549 | "valueName": "current"
2550 | }
2551 | ],
2552 | "schemaVersion": 16,
2553 | "style": "dark",
2554 | "tags": [
2555 | "kubernetes",
2556 | "kubernetes-app"
2557 | ],
2558 | "templating": {
2559 | "list": [
2560 | {
2561 | "current": {
2562 | "text": "No data sources found",
2563 | "value": ""
2564 | },
2565 | "hide": 2,
2566 | "label": "",
2567 | "name": "datasource",
2568 | "options": [],
2569 | "query": "prometheus",
2570 | "refresh": 1,
2571 | "regex": "/$ds/",
2572 | "type": "datasource"
2573 | },
2574 | {
2575 | "current": {
2576 | "text": ".*",
2577 | "value": ".*"
2578 | },
2579 | "hide": 0,
2580 | "label": null,
2581 | "name": "node",
2582 | "options": [
2583 | {
2584 | "selected": true,
2585 | "text": ".*",
2586 | "value": ".*"
2587 | }
2588 | ],
2589 | "query": ".*",
2590 | "type": "constant"
2591 | },
2592 | {
2593 | "current": {
2594 | "text": ".*",
2595 | "value": ".*"
2596 | },
2597 | "hide": 0,
2598 | "label": null,
2599 | "name": "namespace",
2600 | "options": [
2601 | {
2602 | "selected": true,
2603 | "text": ".*",
2604 | "value": ".*"
2605 | }
2606 | ],
2607 | "query": ".*",
2608 | "type": "constant"
2609 | }
2610 | ]
2611 | },
2612 | "time": {
2613 | "from": "now-30m",
2614 | "to": "now"
2615 | },
2616 | "timepicker": {
2617 | "refresh_intervals": [
2618 | "5s",
2619 | "10s",
2620 | "30s",
2621 | "1m",
2622 | "5m",
2623 | "15m",
2624 | "30m",
2625 | "1h",
2626 | "2h",
2627 | "1d"
2628 | ],
2629 | "time_options": [
2630 | "5m",
2631 | "15m",
2632 | "1h",
2633 | "6h",
2634 | "12h",
2635 | "24h",
2636 | "2d",
2637 | "7d",
2638 | "30d"
2639 | ]
2640 | },
2641 | "timezone": "browser",
2642 | "title": "Kubernetes Cluster (Prometheus)",
2643 | "uid": "4XuMd2Iiz",
2644 | "version": 1
2645 | }
--------------------------------------------------------------------------------