diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ba3f231 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +.exe filter=lfs diff=lfs merge=lfs -text +*.exe filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml new file mode 100644 index 0000000..d591e9c --- /dev/null +++ b/.github/workflows/docker-image.yaml @@ -0,0 +1,49 @@ +name: Docker Image CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + + build-and-push: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + + steps: + - uses: actions/checkout@v4 + + # Step 1: Log in to Amazon ECR + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: arn:aws:iam::891376975226:role/OIDCRolefors3 + aws-region: us-east-1 + + - name: Login to Amazon ECR + run: | + aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 891376975226.dkr.ecr.us-east-1.amazonaws.com + + # Step 2: Build the Docker image + - name: Build the Docker image + run: | + IMAGE_NAME=$(basename "$PWD") + docker build . --file Dockerfile --tag $IMAGE_NAME:latest + + # Step 3: Tag the image with ECR repository URL + - name: Tag the Docker image + run: | + IMAGE_NAME=$(basename "$PWD") + ECR_URI=891376975226.dkr.ecr.us-east-1.amazonaws.com/$IMAGE_NAME + docker tag $IMAGE_NAME:latest $ECR_URI:latest + + # Step 4: Push the Docker image to ECR + - name: Push the Docker image to ECR + run: | + IMAGE_NAME=$(basename "$PWD") + ECR_URI=891376975226.dkr.ecr.us-east-1.amazonaws.com/$IMAGE_NAME + docker push $ECR_URI:latest diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6036112 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +docker_registry_secret: + kubectl create secret docker-registry regcred \ + --docker-server={AWS-ACCOUNT}.dkr.ecr.{}.amazonaws.com \ + --docker-username=AWS \ + --docker-password=$(aws ecr get-login-password) \ + +docker-build: + docker build -f bird/Dockerfile -t bird . + + +docker-push: + + +k8s-deploy: diff --git a/bird/Dockerfile b/bird/Dockerfile new file mode 100644 index 0000000..b9f53e2 --- /dev/null +++ b/bird/Dockerfile @@ -0,0 +1,19 @@ +FROM golang:1.22.5-alpine AS builder + +WORKDIR /app + +COPY go.mod ./ +RUN go mod download + +# Copy the rest of the application source code +COPY . . + +RUN go build -o api . + +FROM alpine:3.18 + +WORKDIR /app + +COPY --from=builder /app/api /app/api + +CMD ["./api"] diff --git a/bird/main.go b/bird/main.go index 99f03fe..e6cff08 100644 --- a/bird/main.go +++ b/bird/main.go @@ -5,9 +5,10 @@ import ( "encoding/json" "fmt" "io" - "math/rand/v2" + "math/rand" "net/http" "net/url" + "time" ) type Bird struct { @@ -16,6 +17,7 @@ type Bird struct { Image string } +// Function to return a default bird in case of errors func defaultBird(err error) Bird { return Bird{ Name: "Bird in disguise", @@ -24,48 +26,79 @@ func defaultBird(err error) Bird { } } +// Function to get bird image by bird name func getBirdImage(birdName string) (string, error) { - res, err := http.Get(fmt.Sprintf("http://localhost:4200?birdName=%s", url.QueryEscape(birdName))) - if err != nil { - return "", err - } - body, err := io.ReadAll(res.Body) - return string(body), err + res, err := http.Get(fmt.Sprintf("http://localhost:4200?birdName=%s", url.QueryEscape(birdName))) + if err != nil { + return "", err + } + defer res.Body.Close() // Ensure body is closed after reading + + body, err := io.ReadAll(res.Body) + if err != nil { + return "", err + } + return string(body), nil } +// Function to fetch bird factoid from API func getBirdFactoid() Bird { - res, err := http.Get(fmt.Sprintf("%s%d", "https://freetestapi.com/api/v1/birds/", rand.IntN(50))) + res, err := http.Get(fmt.Sprintf("%s%d", "https://freetestapi.com/api/v1/birds/", rand.Intn(50))) if err != nil { fmt.Printf("Error reading bird API: %s\n", err) return defaultBird(err) } + defer res.Body.Close() // Ensure body is closed after reading + body, err := io.ReadAll(res.Body) if err != nil { fmt.Printf("Error parsing bird API response: %s\n", err) return defaultBird(err) } + var bird Bird err = json.Unmarshal(body, &bird) if err != nil { - fmt.Printf("Error unmarshalling bird: %s", err) + fmt.Printf("Error unmarshalling bird: %s\n", err) + return defaultBird(err) + } + + // Fetch bird image + birdImage, err := getBirdImage(bird.Name) + if err != nil { + fmt.Printf("Error in getting bird image: %s\n", err) return defaultBird(err) } - birdImage, err := getBirdImage(bird.Name) - if err != nil { - fmt.Printf("Error in getting bird image: %s\n", err) - return defaultBird(err) - } - bird.Image = birdImage + bird.Image = birdImage return bird } +// HTTP handler for bird factoid endpoint func bird(w http.ResponseWriter, r *http.Request) { var buffer bytes.Buffer - json.NewEncoder(&buffer).Encode(getBirdFactoid()) - io.WriteString(w, buffer.String()) + err := json.NewEncoder(&buffer).Encode(getBirdFactoid()) + if err != nil { + http.Error(w, "Failed to encode bird factoid", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + w.Write(buffer.Bytes()) +} + +// HTTP handler for health check endpoint +func healthCheck(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("ok")) } func main() { + // Seed the random generator + rand.Seed(time.Now().UnixNano()) + + // Define HTTP handlers http.HandleFunc("/", bird) + http.HandleFunc("/healthz", healthCheck) + + // Start the HTTP server + fmt.Println("Server is starting on port 4201...") http.ListenAndServe(":4201", nil) } diff --git a/birdImage/Dockerfile b/birdImage/Dockerfile new file mode 100644 index 0000000..a3b2993 --- /dev/null +++ b/birdImage/Dockerfile @@ -0,0 +1,21 @@ +FROM golang:1.22.5-alpine AS builder + +WORKDIR /app + +COPY go.mod ./ +RUN go mod download + +# Copy the rest of the application source code +COPY . . + +RUN go build -o api . + +FROM alpine:3.18 + +WORKDIR /app + +COPY --from=builder /app/api /app/api + +EXPOSE 8080 + +CMD ["./api"] diff --git a/birdImage/main.go b/birdImage/main.go index 15feacb..8c423e7 100644 --- a/birdImage/main.go +++ b/birdImage/main.go @@ -10,62 +10,82 @@ import ( ) type Urls struct { - Thumb string + Thumb string `json:"thumb"` } type Links struct { - Urls Urls + Urls Urls `json:"urls"` } type ImageResponse struct { - Results []Links + Results []Links `json:"results"` } type Bird struct { Image string } +// Default image URL in case of errors or no results func defaultImage() string { - return "https://www.pokemonmillennium.net/wp-content/uploads/2015/11/missingno.png" + return "https://www.pokemonmillennium.net/wp-content/uploads/2015/11/missingno.png" } +// Function to get bird image using Unsplash API func getBirdImage(birdName string) string { - var query = fmt.Sprintf( - "https://api.unsplash.com/search/photos?page=1&query=%s&client_id=P1p3WPuRfpi7BdnG8xOrGKrRSvU1Puxc1aueUWeQVAI&per_page=1", - url.QueryEscape(birdName), - ) + query := fmt.Sprintf( + "https://api.unsplash.com/search/photos?page=1&query=%s&client_id=P1p3WPuRfpi7BdnG8xOrGKrRSvU1Puxc1aueUWeQVAI&per_page=1", + url.QueryEscape(birdName), + ) res, err := http.Get(query) if err != nil { fmt.Printf("Error reading image API: %s\n", err) return defaultImage() } + defer res.Body.Close() // Ensure the body is closed after reading + body, err := io.ReadAll(res.Body) if err != nil { fmt.Printf("Error parsing image API response: %s\n", err) return defaultImage() } + var response ImageResponse err = json.Unmarshal(body, &response) if err != nil { - fmt.Printf("Error unmarshalling bird image: %s", err) + fmt.Printf("Error unmarshalling bird image: %s\n", err) + return defaultImage() + } + + // Check if the result contains any images + if len(response.Results) == 0 { + fmt.Println("No images found for the bird") return defaultImage() } - return response.Results[0].Urls.Thumb + + return response.Results[0].Urls.Thumb } +// Handler for fetching bird image func bird(w http.ResponseWriter, r *http.Request) { var buffer bytes.Buffer - birdName := r.URL.Query().Get("birdName") - if birdName == "" { - json.NewEncoder(&buffer).Encode(defaultImage()) - } else { - json.NewEncoder(&buffer).Encode(getBirdImage(birdName)) - } + birdName := r.URL.Query().Get("birdName") + if birdName == "" { + json.NewEncoder(&buffer).Encode(defaultImage()) + } else { + json.NewEncoder(&buffer).Encode(getBirdImage(birdName)) + } + w.Header().Set("Content-Type", "application/json") io.WriteString(w, buffer.String()) } +// Health check handler +func healthCheck(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("ok")) // Removed the incorrect `=` +} + func main() { http.HandleFunc("/", bird) + http.HandleFunc("/healthz", healthCheck) + fmt.Println("Server running on port 4200...") http.ListenAndServe(":4200", nil) } - diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 0000000..0cb8754 --- /dev/null +++ b/infra/README.md @@ -0,0 +1,34 @@ +About: +This simple infra was provisioned on AWS using IAC(Terraform) to manage a k8s application already deployed using helm. + +Steps to Reproduce +A list of the resources provisioned include: +1. AWS vpc - Provisioned using a module +2. AWS ec2 instance with ubuntu AMI (provisioned using a data source) - The following commands were added to the userdata as part of the bootscript in order to install k8s and docker within the instance + +curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644 +curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--tls-san your_server_ip" sh - +sudo apt update -y && sudo apt install docker.io -y +sudo usermod -aG docker $USER + newgrp docker + + 3. AWS security group + 4. AWS ECR + +As soon as the ec2 instance is deployed you will be able to ssh into it using +ssh -i ubuntu@ or using ec2-instance-connect. The k3 will already be installed via the user data. +An attempt to run kubectl get nodes creates the following error: +'''k3s kubectl version +WARN[0000] Unable to read /etc/rancher/k3s/k3s.yaml, please start server with --write-kubeconfig-mode to modify kube config permissions +error: error loading config file "/etc/rancher/k3s/k3s.yaml" : open /etc/rancher/k3s/k3s.yaml: permission denied''' + +in order to overcome this , run the following commands: +export KUBECONFIG=~/.kube/config +mkdir ~/.kube 2> /dev/null +sudo k3s kubectl config view --raw > "$KUBECONFIG" +chmod 600 "$KUBECONFIG" + +afterwards all commands can run +its important to change the default namespace for the context to bird using the following commands : +> + command to verify it has been changed to bird as default \ No newline at end of file diff --git a/infra/ami.tf b/infra/ami.tf new file mode 100644 index 0000000..645f740 --- /dev/null +++ b/infra/ami.tf @@ -0,0 +1,25 @@ +#data source for the AMI +data "aws_ami" "ubuntu" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["al2023-ami-*"] + } + + filter { + name = "root-device-type" + values = ["ebs"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } + + filter { + name = "architecture" + values = ["x86_64"] + } +} \ No newline at end of file diff --git a/infra/ec2.tf b/infra/ec2.tf new file mode 100644 index 0000000..7355c86 --- /dev/null +++ b/infra/ec2.tf @@ -0,0 +1,20 @@ + +module "ec2_instance" { + source = "terraform-aws-modules/ec2-instance/aws" + + name = "test-instance" + + instance_type = "t2.micro" + ami = "ami-0e86e20dae9224db8" + key_name = "deployer-key" + availability_zone = var.vpc_availability_zones[0] + user_data = file("user_data.sh") + associate_public_ip_address = true + monitoring = true + vpc_security_group_ids = [aws_security_group.bastion-instance.id] + subnet_id = module.vpc.public_subnets[0] + + tags = { + Name = local.name + } +} \ No newline at end of file diff --git a/infra/ecr.tf b/infra/ecr.tf new file mode 100644 index 0000000..d930506 --- /dev/null +++ b/infra/ecr.tf @@ -0,0 +1,29 @@ +module "ecr" { + source = "terraform-aws-modules/ecr/aws" + + repository_name = "private-example" + + repository_read_write_access_arns = ["arn:aws:iam::891376975226:role/Ec2roleforECR"] + repository_lifecycle_policy = jsonencode({ + rules = [ + { + rulePriority = 1, + description = "Keep last 30 images", + selection = { + tagStatus = "tagged", + tagPrefixList = ["v"], + countType = "imageCountMoreThan", + countNumber = 30 + }, + action = { + type = "expire" + } + } + ] + }) + + tags = { + Terraform = "true" + Environment = "dev" + } +} \ No newline at end of file diff --git a/infra/key-pair.tf b/infra/key-pair.tf new file mode 100644 index 0000000..2cac14d --- /dev/null +++ b/infra/key-pair.tf @@ -0,0 +1,13 @@ +resource "aws_key_pair" "deployer" { + key_name = "deployer-key" + public_key = tls_private_key.ed25519-example.public_key_openssh +} + +resource "tls_private_key" "ed25519-example" { + algorithm = "RSA" + rsa_bits = 4096 +} +resource "local_file" "TF-key" { + content = tls_private_key.ed25519-example.private_key_pem + filename = "deployer-key.pem" +} \ No newline at end of file diff --git a/infra/local-values.tf b/infra/local-values.tf new file mode 100644 index 0000000..0b87860 --- /dev/null +++ b/infra/local-values.tf @@ -0,0 +1,10 @@ +locals { + owners = var.business_division + environment = var.environment + + name = "${var.business_division}-${var.environment}" + common_tags = { + owners = local.owners + environment = local.environment + } +} \ No newline at end of file diff --git a/infra/main.tf b/infra/main.tf new file mode 100644 index 0000000..79f5f81 --- /dev/null +++ b/infra/main.tf @@ -0,0 +1,14 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=3.29" + } + } +} + +provider "aws" { + profile = "default" + region = var.aws_region +} + diff --git a/infra/output.tf b/infra/output.tf new file mode 100644 index 0000000..7af6a6f --- /dev/null +++ b/infra/output.tf @@ -0,0 +1,23 @@ +output "instance_ip_addr" { + description = "ip address of the instance" + value = module.ec2_instance.public_ip +} + +output "aws_vpc" { + value = module.vpc.vpc_id +} + +output "arn" { + value = module.ec2_instance.arn +} + +output "igw_arn" { + value = module.vpc.igw_arn +} + +output "azs" { + value = module.vpc.azs +} +output "name" { + value = module.vpc.name +} \ No newline at end of file diff --git a/infra/sg.tf b/infra/sg.tf new file mode 100644 index 0000000..b2f4e8a --- /dev/null +++ b/infra/sg.tf @@ -0,0 +1,33 @@ + +locals { + ports = [80, 22, 443] +} +resource "aws_security_group" "bastion-instance" { + name = "webserver" + vpc_id = module.vpc.vpc_id + description = "Inbound Rules for WebServer" + + dynamic "ingress" { + iterator = port + for_each = local.ports + content { + description = "description ${port.key}" + from_port = port.value + to_port = port.value + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + dynamic "egress" { + iterator = port + for_each = local.ports + content { + description = "description ${port.key}" + from_port = port.value + to_port = port.value + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + +} \ No newline at end of file diff --git a/infra/user_data.sh b/infra/user_data.sh new file mode 100644 index 0000000..b43f2d0 --- /dev/null +++ b/infra/user_data.sh @@ -0,0 +1,6 @@ +#! /bin/bash +curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644 +curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--tls-san your_server_ip" sh - +sudo apt update -y && sudo apt install docker.io -y +sudo usermod -aG docker $USER +newgrp docker \ No newline at end of file diff --git a/infra/var.tf b/infra/var.tf new file mode 100644 index 0000000..d0b4daa --- /dev/null +++ b/infra/var.tf @@ -0,0 +1,23 @@ +variable "aws_region" { + description = "The AWS region" + type = string + default = "us-east-1" +} +variable "instance_type" { + description = "instance type" + default = "t2.micro" + type = string +} +variable "vpc_availability_zones" { + description = "value" + type = list(string) + default = ["us-east-1a", "us-east-1b", "us-east-1c"] +} +variable "business_division" { + type = string + default = "li-fi" +} +variable "environment" { + type = string + default = "dev" +} \ No newline at end of file diff --git a/infra/vpc.tf b/infra/vpc.tf new file mode 100644 index 0000000..6d203c5 --- /dev/null +++ b/infra/vpc.tf @@ -0,0 +1,50 @@ +data "aws_availability_zones" "available" { + state = "available" +} + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + + name = "${local.name}-vpc" + cidr = "10.0.0.0/16" + + azs = ["us-east-1a", "us-east-1b", "us-east-1c"] + private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] + public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] + database_subnets = ["10.0.201.0/24", "10.0.202.0/24", "10.0.203.0/24"] + + create_database_subnet_group = true + create_database_subnet_route_table = true + enable_vpn_gateway = true + + #NAT Gateways - outbound communications + + enable_nat_gateway = true + single_nat_gateway = true + + #VPC DNS Parametrers + enable_dns_hostnames = true + enable_dns_support = true + + public_subnet_tags = { + Name = "public-subnets" + } + + private_subnet_tags = { + Name = "private-subnets" + } + + database_subnet_tags = { + Name = "database-subnets" + } + + tags = { + owner = "Ochuko" + Terraform = "true" + Environment = "dev" + } + + vpc_tags = { + Name = "vpc-dev" + } +} diff --git a/k8/README.md b/k8/README.md new file mode 100644 index 0000000..cf4d2ab --- /dev/null +++ b/k8/README.md @@ -0,0 +1,50 @@ +About: +The application was deployed using helm where I essentially built all the k8s resources from the ground up + +Steps to reproduce: +1. Build the docker image and push it to ECR(already created using iac): + + Retrieve an authentication token and authenticate your Docker client to your registry. Use the AWS CLI: + +aws ecr get-login-password --region | docker login --username AWS --password-stdin .dkr.ecr..amazonaws.com + +Build your Docker image using the following command. + +docker build -t . + +After the build completes, tag your image so you can push the image to this repository: + +docker tag : .dkr.ecr..amazonaws.com/: + +Run the following command to push this image to your newly created AWS repository: + +docker push .dkr.ecr..amazonaws.com/: + +NB: I added health check to each of the api and then built/pushed a new docker image to the ECR + +2. create a k8 bird namespace using the manifest file or using the command : + kubectl create ns + +3. create a registry secret in the namespace using the command + kubectl create secret docker-registry regcred \ + --docker-server=.dkr.ecr..amazonaws.com \ + --docker-username=AWS \ + --docker-password=$(aws ecr get-login-password) \ + --namespace= + + ensure that the 2 resources (namespace and docker registry secret) have already been created before deploying the helm chart + +4. install the application : + helm install -n + + Note- k8s resources deployed using this helm chart include - deployment, service, hpa + To test if the helm chart YAML syntax is corrct, we can render the helm chart locally using: + helm template + +5. Health checks are done on each of the api and liveness probe added to each of the containers in order to monitor the health + +The goal essentially is to build a CICD pipeline that ensues the build and deploy runs automatically rather than do it manually as it is(and it works). My first approach would be to integrate a github action and define the jobs/steps. Already began the process of integrating that but I am almost out of time.Beyond this task, I will ensure that is integrated and demonstrate that it works when we reconvene (hopefully). + +in order to test that the api works use + command +and then enter localhost:4201 into the browser \ No newline at end of file diff --git a/k8/bird-release/Chart.yaml b/k8/bird-release/Chart.yaml new file mode 100644 index 0000000..b310fc2 --- /dev/null +++ b/k8/bird-release/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: bird-release +description: A Helm chart for bird deployment +version: 0.1.0 +appVersion: "1.0" diff --git a/k8/bird-release/templates/deployment.yaml b/k8/bird-release/templates/deployment.yaml new file mode 100644 index 0000000..013a2df --- /dev/null +++ b/k8/bird-release/templates/deployment.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bird-deployment + namespace: bird + labels: + app: bird +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: bird + template: + metadata: + labels: + app: bird + spec: + volumes: + - name: bird-release-pv + persistentVolumeClaim: + claimName: bird-release-pvc + containers: + - name: bird-container + image: "{{ .Values.image.repository }}:{{ .Values.image.birdTag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - mountPath: "/var/www/html" + name: bird-release-pv + ports: + - name: bird-web + containerPort: {{ .Values.ports.birdContainerPort }} + livenessProbe: + httpGet: + path: /healthz + port: 4201 + scheme: HTTP + periodSeconds: 5 + initialDelaySeconds: 15 + failureThreshold: 10 + resources: + limits: + cpu: {{ .Values.resources.limits.cpu }} + memory: {{ .Values.resources.limits.memory }} + requests: + cpu: {{ .Values.resources.requests.cpu }} + memory: {{ .Values.resources.requests.memory }} + - name: birdimage-container + image: "{{ .Values.image.repository }}:{{ .Values.image.birdImageTag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - mountPath: "/var/www/html" + name: bird-release-pv + ports: + - name: birdimage-web + containerPort: {{ .Values.ports.birdImageContainerPort }} + livenessProbe: + httpGet: + path: /healthz + port: 4200 + scheme: HTTP + periodSeconds: 5 + initialDelaySeconds: 15 + failureThreshold: 10 + resources: + limits: + cpu: {{ .Values.resources.limits.cpu }} + memory: {{ .Values.resources.limits.memory }} + requests: + cpu: {{ .Values.resources.requests.cpu }} + memory: {{ .Values.resources.requests.memory }} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ .name }} + {{- end }} diff --git a/k8/bird-release/templates/helper.tpl b/k8/bird-release/templates/helper.tpl new file mode 100644 index 0000000..2516677 --- /dev/null +++ b/k8/bird-release/templates/helper.tpl @@ -0,0 +1,6 @@ +{{/* +Create a default chart label. +*/}} +{{- define "bird-chart.labels" -}} +app: bird +{{- end }} diff --git a/k8/bird-release/templates/hpa.yaml b/k8/bird-release/templates/hpa.yaml new file mode 100644 index 0000000..86d877b --- /dev/null +++ b/k8/bird-release/templates/hpa.yaml @@ -0,0 +1,38 @@ + +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: bird-webui-hpa + namespace: bird +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: bird-release-deployment + minReplicas: 1 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 50 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 70 +status: + observedGeneration: 1 + #lastScaleTime: 05:00 + currentReplicas: 1 + desiredReplicas: 1 + currentMetrics: + - type: Resource + resource: + name: memory + current: + averageUtilization: 70 + averageValue: 10 \ No newline at end of file diff --git a/k8/bird-release/templates/pv.yaml b/k8/bird-release/templates/pv.yaml new file mode 100644 index 0000000..b819cb0 --- /dev/null +++ b/k8/bird-release/templates/pv.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: bird-release-pv + namespace: bird + labels: + type: local +spec: + storageClassName: manual + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + hostPath: + path: "/mnt/data" + + diff --git a/k8/bird-release/templates/pvc.yaml b/k8/bird-release/templates/pvc.yaml new file mode 100644 index 0000000..5af9d0a --- /dev/null +++ b/k8/bird-release/templates/pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: bird-release-pvc + namespace: bird +spec: + storageClassName: manual + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi \ No newline at end of file diff --git a/k8/bird-release/templates/svc.yaml b/k8/bird-release/templates/svc.yaml new file mode 100644 index 0000000..b64af71 --- /dev/null +++ b/k8/bird-release/templates/svc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: bird-service + namespace: bird +spec: + selector: + app: bird + ports: + - name: bird-service-port + protocol: TCP + port: 4201 + targetPort: bird-web \ No newline at end of file diff --git a/k8/bird-release/values.yaml b/k8/bird-release/values.yaml new file mode 100644 index 0000000..a2e8e56 --- /dev/null +++ b/k8/bird-release/values.yaml @@ -0,0 +1,25 @@ +namespace: bird +replicaCount: 1 + +dockerSecret: "" + +image: + repository: 891376975226.dkr.ecr.us-east-1.amazonaws.com/private-example + birdTag: bird2.0 + birdImageTag: birdimage1.0 + pullPolicy: Always + +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 200m + memory: 256Mi + +imagePullSecrets: + - name: regcred + +ports: + birdContainerPort: 4201 + birdImageContainerPort: 4200