Skip to content

Commit 96e8c91

Browse files
authored
Merge branch 'main' into MarcGueury-patch-6
2 parents d84e184 + 4da22e3 commit 96e8c91

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+6340
-0
lines changed

.gitignore

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,34 @@ shared-assets/bastion-py-script/.oci/
33
shared-assets/bastion-py-script/temp/
44
temp/
55
app-dev/app-integration-and-automation/oracle-integration-cloud/01-oic-connectivity-agent/README_tmp.html
6+
7+
8+
# Local .terraform directories
9+
**/.terraform/*
10+
11+
12+
# Crash log files
13+
crash.log
14+
crash.*.log
15+
16+
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
17+
# password, private keys, and other secrets. These should not be part of version
18+
# control as they are data points which are potentially sensitive and subject
19+
# to change depending on the environment.
20+
*.tfvars
21+
*.tfvars.json
22+
23+
24+
# Ignore override files as they are usually used to override resources locally and so
25+
# are not checked in
26+
override.tf
27+
override.tf.json
28+
*_override.tf
29+
*_override.tf.json
30+
31+
# Ignore CLI configuration files
32+
.terraformrc
33+
terraform.rc
34+
35+
# Terraform lock files
36+
*.lock.hcl
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# OKE GitOps with ArgoCD
2+
3+
This repository's objective is to get you started quickly adopting a GitOps strategy for managing your OKE cluster.
4+
GitOps is just a series of best practices to manage operation using a Git repository.
5+
Administering a Kubernetes cluster is not an easy task, and I often see people getting lost in the forest of YAMLs and, with time,
6+
losing track of what is actually deployed in the cluster.
7+
8+
To help simplifying the experience, it would be optimal to have all the configurations in a Git repository, so that we
9+
can organize our YAMLs in folders and inspect the code when we forget some nuances abut what has been already deployed.
10+
11+
Problem is, GitOps requires a shift in mentality, as most of the operation team I have met are not familiar with Kubernetes, Git and modern operations.
12+
13+
Hence, the idea of creating this template to get people started with GitOps and ArgoCD to manage OKE clusters.
14+
15+
Before actually starting, it's good to remind us some best practices and concepts.
16+
17+
## WHY GitOps?
18+
19+
Traditionally, a Git repository is used by developers to version their custom application code.
20+
With recent years, the types of things we can create through code has drastically spiked, so Git repositories are also used by operation teams.
21+
Some examples:
22+
23+
* Application code
24+
* Configuration as Code
25+
* Infrastructure as Code
26+
27+
Having everything as code might seem something difficult and pointless at first, but with time, as the number of components increases, you will find out that it's way easier to debug complex and big
28+
systems if you have them defined as code.
29+
30+
After all, the key to effectively manage a complex infrastructure is to have everything visible and do not lose control as complexity spikes.
31+
Some other advantages of GitOps are:
32+
* Faster and safer deployments
33+
* Easier rollbacks
34+
* Straightforward auditing
35+
* Better traceability
36+
* Eliminating configuration drift
37+
38+
## WHY Kubernetes?
39+
40+
When organizations start thinking of adopting Kubernetes as the reference development platform, I have always seen people struggling
41+
to get used to it, especially the operation teams who were used to managing on-prem servers or VMs.
42+
Some people even fear Kubernetes, saying it adds too much complexity in any architecture, and also that there is too much to study to get used to it.
43+
Working with customers, I have heard many good and bad things about Kubernetes, but in my opinion the truth lies in between.
44+
Let's see some common thinking I have observed over these years:
45+
* Kubernetes is just another system we need to take care of.
46+
* A: no it is not! Kubernetes is a PLATFORM where other platforms are deployed on top of it. Think about it, in Kubernetes you can deploy anything: database systems, applications, Kafka, OpenSearch, caching systems and so on. Potentially, you could have your entire IT infrastructure deployed in a single Kubernetes cluster.
47+
* Kubernetes is too complex to actually use it
48+
* A: it is indeed complex, as it is a very powerful platform, but once you get the hang of it, it will become eventually easy. Not everything can be easy at first, especially if we want to manage a platform to create other platforms.
49+
* A: There are also many tutorials and a rich documentation, as well as certifications and courses. But of course, the best way to learn is always through practice.
50+
* Q: Why is Kubernetes so complex?
51+
* A: Kubernetes is an Open Source platform, where people are supposed to deploy applications and the tools they prefer.
52+
Being an open and customizable platform, there are a lot of choices to make and a lot of possibilities. If people are given
53+
a lot of options, they tend to get lost in this maze of choices, especially if it is the first time they are dealing with Kubernetes.
54+
For example, I often get these questions:
55+
* How can we secure our Kubernetes cluster?
56+
* Which ingress controller should we use? Or is it better to use Gateway API?
57+
* Which tools are we supposed to use for logging? And what about monitoring and tracing?
58+
* How many Kubernetes clusters should we have?
59+
* How can we manage certificates?
60+
* Should we have a service mesh in place?
61+
* As a general suggestion, freedom of choice shouldn't be seen as something overwhelming, but it should be regarded as something positive.
62+
You can start by deploying a tool based on some suggestions, evaluate it and uninstall it from the cluster if you don't like it.
63+
* Q: What is the main challenge of managing a Kubernetes cluster?
64+
* A: In my opinion, what I have seen is that people struggle to administer a cluster because of lack of experience, automations and standards.
65+
Because of deadlines and other priorities, it is also difficult for people in the operation teams to study Kubernetes.
66+
* Although documentation is there, nothing beats actual experience, and most of the problems actually come to light when you have already started.
67+
68+
In short, complexity is the main problem with Kubernetes, but there are some ways to mitigate complexity, and even some unexpected allies.
69+
70+
## Provisioning Kubernetes: cloud providers are your best friends
71+
72+
Provisioning a Kubernetes cluster is actually quite a daunting task. You need machines for the control plane and the data plane (the worker nodes), build some specific OS images and a way to bootstrap the cluster. One common way is to use tools like Kubeadm to bootstrap a cluster.
73+
You should also size properly the control plane, install etcd, install MetalLB if you want to expose services with a Load Balancer, provision a storage infrastructure, install a CNI for the cluster, create periodic backups of etcd and so on...
74+
In short, provisioning a new Kubernetes cluster is really difficult as it involves a lot of decisions in the process.
75+
76+
But let's not panic, as luckily all cloud providers offer a managed Kubernetes cluster as a service!
77+
Let's take Oracle Cloud and the service OKE (Oracle Kubernetes Engine).
78+
With OKE, the whole Control Plane is managed by Oracle, and compared to provisioning an on-prem cluster, you get the following advantages:
79+
80+
* No need to provision machines for the control plane, as the OKE service will take care of it
81+
* No need to think of making the control plane highly available, as OKE offers guaranteed SLAs
82+
* Backup of etcd is done by Oracle automatically every 15 minutes, and restored automatically in case of disruption
83+
* No need to learn Kubeadm, as the bootstrapping process is automated
84+
* No need to install MetalLB, as service of type LoadBalancer will provision a physical Load Balancer by exploiting the OCI Load Balancer service
85+
* No need to provision a storage infrastructure, as there are integration with native Oracle Cloud storage services
86+
* No need to install a CNI, as it is by default provisioned by the OKE service
87+
* No need to install CoreDNS or kube-proxy, as they are already installed and upgraded automatically by Oracle
88+
* No need to build custom OS images for the nodes, as Oracle already gives you pre-built images ready to use
89+
* No need to configure audit logs, they are always enabled and available to inspect
90+
* Easier upgrade process for the whole cluster
91+
* Possibility to automatically scale worker nodes
92+
* Security compliance and certification of the infrastructure
93+
* Support available, as long as you keep your OKE cluster updated
94+
* Integrated Container Registry service for container images
95+
* Possibility to standardize provisioning and do it with the as code approach (oci Terraform provider)
96+
97+
In short, everything is way easier and secured. In addition, if you want more control, you can opt to deploy the control plane using the ClusterAPI provider.
98+
99+
With the help of cloud providers, provisioning a new Kubernetes cluster should take about 15-20 minutes.
100+
101+
## I have got my OKE cluster, so what?
102+
103+
Having the capability to instantly spin up new infrastructure doesn’t always mean that your application developers can take advantage of the new infrastructure in the most optimal way.
104+
Provisioning a Kubernetes cluster is only the first step, and the next step is configuring and administering it.
105+
This step here is where people usually get lost, but here we will try to explain concepts so that they are easily understood and adopting the "as code" strategy.
106+
107+
Generally speaking, there are always 3 kinds of code:
108+
109+
* Application code
110+
* Cluster configurations + Infra applications
111+
* Infrastructure (IaC, Terraform)
112+
113+
Understanding what these codes are and who is responsible for it is essential:
114+
115+
* Application code = Kubernetes manifests to deploy the custom applications built by the Software Development team.
116+
* This is different from the application source code, as the best practice is to separate the source code and the Kubernetes manifests so that they are in different repositories
117+
* There should be 1 Git repository for every development team containing the Kubernetes manifests to deploy an application. The development team is the owner of the repository, not the operation team
118+
* Cluster configurations + Infra applications = Kubernetes manifests to deploy infrastructure related applications and configure the OKE cluster
119+
* Infra applications are those applications that are not developed internally and that serves to maintain the whole cluster.
120+
* Example: cert-manager is an infra application that will automatically generate certificates and renew them before they expire
121+
* There should be 1 Git repository dedicated to infra applications and cluster configurations, to be used by the cluster administrators
122+
* IaC Infrastructure = Terraform code to provision an OKE cluster
123+
* There should be 1 Git repository dedicated to the Terraform infrastructure for the chosen cloud provider
124+
125+
For the IaC infrastructure in Oracle Cloud, you can use also OCI Resource Manager to manage the Terraform state and quickly provision an OKE cluster by using [this stack](../oke-rm)
126+
127+
Next we will focus on the **"cluster administrator"** repository and the way to automate configurations and infra applications provisioning.
128+
129+
## Cluster administration with ArgoCD
130+
131+
ArgoCD is an open source, CNCF graduated project to implement GitOps in Kubernetes clusters.
132+
The base concept is very simple: the ArgoCD controller will be connected to a Git repository and will continuously pull the Kubernetes manifests and deploy them.
133+
So the role of the controller is to keep what is defined as code in the Git repository aligned with the "live" cluster configurations.
134+
The cluster administrators will then configure the cluster through code, and ArgoCD will keep everything in sync and consistent.
135+
136+
With this repository, I want to propose a quick way to install ArgoCD in an OKE cluster and propose a Git template the administer OKE clusters.
137+
This stack will:
138+
* Provision a new OCI DevOps project
139+
* Create 2 OCI Code Repositories: one with pipelines definitions, and another one called "oke-cluster-config" with the git template for the OKE cluster administrators
140+
* Create an OCI Build Pipeline that will mirror the ArgoCD Helm Chart inside the Oracle Cloud Registry, and deploy it in the chosen cluster
141+
142+
[![Deploy to Oracle Cloud](https://oci-resourcemanager-plugin.plugins.oci.oraclecloud.com/latest/deploy-to-oracle-cloud.svg)](https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/oracle-devrel/technology-engineering/releases/download/oke-gitops-1.0.0/stack.zip)
143+
144+
Once the stack has been provisioned, you can modify the ArgoCD version to deploy by editing the `mirror_argo.yaml` file in the `pipelines` repository.
145+
By default, ArgoCD will be deployed in an "insecure" mode to disable the default SSL certificate, but feel free to modify the chart values in the `argo-cd-chart-values` artifact.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
data "oci_identity_user" "current_user" {
2+
user_id = var.current_user_ocid
3+
}
4+
5+
data "oci_identity_tenancy" "current_tenancy" {
6+
tenancy_id = var.tenancy_ocid
7+
}
8+
9+
data "oci_identity_region_subscriptions" "region_subscriptions_data" {
10+
tenancy_id = var.tenancy_ocid
11+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
locals {
2+
git_username = "${data.oci_identity_tenancy.current_tenancy.name}/${data.oci_identity_user.current_user.name}"
3+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module "devops" {
2+
source = "./modules/devops"
3+
compartment_id = var.devops_compartment_id # Both DevOps project and OCIR will be here
4+
region = var.region
5+
tenancy_id = var.tenancy_ocid
6+
create_notification_topic = var.create_notification_topic
7+
notification_topic_id = var.notification_topic_id
8+
notification_topic_name = var.notification_topic_name
9+
notification_topic_description = var.notification_topic_description
10+
devops_project_name = var.devops_project_name
11+
devops_project_description = var.devops_project_description
12+
devops_log_group_name = var.devops_log_group_name
13+
devops_log_group_description = var.devops_log_group_description
14+
devops_log_retention_period_in_days = var.devops_log_retention_period_in_days
15+
16+
git_username = local.git_username
17+
git_password = var.auth_token
18+
ocir_repo_path_prefix = var.ocir_repo_path_prefix
19+
20+
# OKE ENVIRONMENT
21+
oke_cluster_id = var.oke_cluster_id
22+
oke_environment_name = var.oke_environment_name
23+
oke_environment_description = var.oke_environment_description
24+
is_oke_cluster_private = var.is_oke_cluster_private
25+
oke_worker_subnet_id = var.oke_worker_subnet_id
26+
oke_worker_nsg_id = var.oke_worker_nsg_id
27+
}
28+
29+
module "iam" {
30+
source = "./modules/iam"
31+
tenancy_id = var.tenancy_ocid
32+
compartment_id = var.devops_compartment_id
33+
network_compartment_id = var.network_compartment_id
34+
oke_compartment_id = var.oke_compartment_id
35+
devops_policy_name = var.devops_policy_name
36+
domain_name = var.identity_domain_name
37+
dynamic_group_name = var.devops_dynamic_group_name
38+
is_oke_cluster_private = var.is_oke_cluster_private
39+
count = var.create_iam ? 1 : 0
40+
providers = {oci = oci.home}
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
data "oci_artifacts_container_configuration" "ocir_config" {
2+
compartment_id = var.compartment_id
3+
}
4+
5+
data "oci_identity_region_subscriptions" "oci_region_subscriptions" {
6+
tenancy_id = var.tenancy_id
7+
}
8+
9+
locals {
10+
region_key = lower([for s in data.oci_identity_region_subscriptions.oci_region_subscriptions.region_subscriptions : s if s.region_name == var.region][0].region_key)
11+
namespace = data.oci_artifacts_container_configuration.ocir_config.namespace
12+
}
13+
14+
15+
resource oci_devops_deploy_artifact argo_chart {
16+
argument_substitution_mode = "NONE"
17+
deploy_artifact_source {
18+
chart_url = "oci://${local.region_key}.ocir.io/${local.namespace}/${var.ocir_repo_path_prefix}/argo-cd"
19+
deploy_artifact_source_type = "HELM_CHART"
20+
deploy_artifact_version = "$${version}"
21+
helm_verification_key_source {
22+
verification_key_source_type = "NONE"
23+
}
24+
}
25+
deploy_artifact_type = "HELM_CHART"
26+
description = "Location to the internal argo-cd chart generated by the build pipeline"
27+
display_name = "argo-cd-chart"
28+
project_id = oci_devops_project.devops_project.id
29+
}
30+
31+
resource oci_devops_deploy_artifact argo_chart_values {
32+
argument_substitution_mode = "SUBSTITUTE_PLACEHOLDERS"
33+
deploy_artifact_source {
34+
base64encoded_content = filebase64("${path.root}/templates/argo-values.yml")
35+
deploy_artifact_source_type = "INLINE"
36+
}
37+
deploy_artifact_type = "GENERIC_FILE"
38+
description = "Values of the argo-cd Helm Charts"
39+
display_name = "argo-cd-chart-values"
40+
project_id = oci_devops_project.devops_project.id
41+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
resource "oci_devops_build_pipeline" "mirror_argocd" {
2+
project_id = oci_devops_project.devops_project.id
3+
display_name = "mirror-argocd"
4+
description = "Pipeline to mirror the public Helm Chart of ArgoCD into the tenancy OCIR"
5+
}
6+
7+
resource "oci_devops_build_pipeline_stage" "mirror_argocd_stage" {
8+
build_pipeline_id = oci_devops_build_pipeline.mirror_argocd.id
9+
build_pipeline_stage_type = "BUILD"
10+
build_pipeline_stage_predecessor_collection {
11+
items {
12+
id = oci_devops_build_pipeline.mirror_argocd.id
13+
}
14+
}
15+
build_source_collection {
16+
items {
17+
connection_type = "DEVOPS_CODE_REPOSITORY"
18+
branch = "main"
19+
name = "pipelines"
20+
repository_id = oci_devops_repository.devops_pipelines_repo.id
21+
repository_url = oci_devops_repository.devops_pipelines_repo.http_url
22+
}
23+
}
24+
build_spec_file = "mirror_argo.yaml"
25+
display_name = "Mirror Helm Chart"
26+
description = "Stage to import a public Helm Chart into the tenancy Oracle Container Registry"
27+
primary_build_source = "pipelines"
28+
image = "OL7_X86_64_STANDARD_10"
29+
stage_execution_timeout_in_seconds = 36000
30+
}
31+
32+
resource "oci_devops_build_pipeline_stage" "trigger_helm_deploy" {
33+
build_pipeline_id = oci_devops_build_pipeline.mirror_argocd.id
34+
build_pipeline_stage_type = "TRIGGER_DEPLOYMENT_PIPELINE"
35+
build_pipeline_stage_predecessor_collection {
36+
items {
37+
id = oci_devops_build_pipeline_stage.mirror_argocd_stage.id
38+
}
39+
}
40+
deploy_pipeline_id = oci_devops_deploy_pipeline.deploy_pipeline_helm.id
41+
description = "Trigger CD pipeline to deploy on OKE"
42+
display_name = "Trigger Helm Deployment pipeline"
43+
is_pass_all_parameters_enabled = true
44+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
resource "oci_devops_deploy_pipeline" "deploy_pipeline_helm" {
3+
project_id = oci_devops_project.devops_project.id
4+
display_name = "helm-install-pipeline"
5+
description = "Deployment pipeline to install Helm charts on a OKE cluster"
6+
}
7+
8+
9+
10+
resource oci_devops_deploy_stage deploy_helm_stage {
11+
are_hooks_enabled = true
12+
deploy_pipeline_id = oci_devops_deploy_pipeline.deploy_pipeline_helm.id
13+
deploy_stage_predecessor_collection {
14+
items {
15+
id = oci_devops_deploy_pipeline.deploy_pipeline_helm.id
16+
}
17+
}
18+
deploy_stage_type = "OKE_HELM_CHART_DEPLOYMENT"
19+
description = "Install the Helm chart on the specified OKE environment"
20+
display_name = "deploy-helm"
21+
helm_chart_deploy_artifact_id = oci_devops_deploy_artifact.argo_chart.id
22+
max_history = 5
23+
namespace = "$${namespace}"
24+
oke_cluster_deploy_environment_id = var.is_oke_cluster_private ? oci_devops_deploy_environment.oke_environment_private.0.id : oci_devops_deploy_environment.oke_environment_public.0.id
25+
purpose = "EXECUTE_HELM_UPGRADE"
26+
release_name = "$${artifact}"
27+
rollback_policy {
28+
policy_type = "AUTOMATED_STAGE_ROLLBACK_POLICY"
29+
}
30+
should_skip_crds = false
31+
timeout_in_seconds = "300"
32+
values_artifact_ids = [oci_devops_deploy_artifact.argo_chart_values.id]
33+
}

0 commit comments

Comments
 (0)