From 0d8e30b5d24bf208266648692c799d101090d206 Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 14:36:41 +0300 Subject: [PATCH 01/14] Added Dockerfile --- Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0cb896 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM python:3.6.1-alpine +WORKDIR /project +ADD . /project +RUN pip install -r requirements.txt +CMD ["python","app.py"] \ No newline at end of file From d0edc91213ec71e74076084cf9d166b98667496a Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 14:40:30 +0300 Subject: [PATCH 02/14] Added requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..89b3ba3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask +mysqlclient \ No newline at end of file From fe9aa2d952ee1c2c1c51c3e5b1c9478b90ecd3bd Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 14:57:59 +0300 Subject: [PATCH 03/14] Modifyied the Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a0cb896..d484803 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM python:3.6.1-alpine -WORKDIR /project -ADD . /project +WORKDIR /app +ADD . /app RUN pip install -r requirements.txt CMD ["python","app.py"] \ No newline at end of file From ccac6f59a0745f0a6611688152ab01573760b4be Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 20:12:20 +0300 Subject: [PATCH 04/14] Updated environment variables --- .vscode/extensions.json | 5 +++++ Dockerfile | 11 ++++++----- app.py | 10 +++++----- 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..e389642 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "formulahendry.vscode-mysql" + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d484803..510fcb3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,6 @@ -FROM python:3.6.1-alpine -WORKDIR /app -ADD . /app -RUN pip install -r requirements.txt -CMD ["python","app.py"] \ No newline at end of file +FROM alpine +FROM python:3.7 +COPY requirements.txt /tmp +WORKDIR /tmp +RUN pip install --upgrade pip && \ + pip install -r requirements.txt \ No newline at end of file diff --git a/app.py b/app.py index eeb17e1..ee10d9b 100644 --- a/app.py +++ b/app.py @@ -15,11 +15,11 @@ def hello_world(): class Storage(): def __init__(self): self.db = MySQLdb.connect( - user = os.getenv('MYSQL_USERNAME'), - passwd = os.getenv('MYSQL_PASSWORD'), - db = os.getenv('MYSQL_INSTANCE_NAME'), - host = os.getenv('MYSQL_PORT_3306_TCP_ADDR'), - port = int(os.getenv('MYSQL_PORT_3306_TCP_PORT')) + user = os.getenv('db_user'), + passwd = os.getenv('Mytest123**'), + db = os.getenv('test_db'), + host = os.getenv('localhost'), + port = int(os.getenv('3306')) ) cur = self.db.cursor() From 00196a5b448748ea1d10a83fd1bb5043b8c90ffc Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 20:51:58 +0300 Subject: [PATCH 05/14] last update --- Dockerfile | 7 ++++++- app.py | 28 +--------------------------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/Dockerfile b/Dockerfile index 510fcb3..f190c45 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,4 +3,9 @@ FROM python:3.7 COPY requirements.txt /tmp WORKDIR /tmp RUN pip install --upgrade pip && \ - pip install -r requirements.txt \ No newline at end of file + pip install -r requirements.txt +RUN mkdir /app +WORKDIR /app +COPY app.py . +ENTRYPOINT [ "python" ] +CMD [ "app.py" ] \ No newline at end of file diff --git a/app.py b/app.py index ee10d9b..dd38666 100644 --- a/app.py +++ b/app.py @@ -7,33 +7,7 @@ @application.route('/') def hello_world(): - storage = Storage() - storage.populate() - score = storage.score() - return "Hello Devops 123, %d!" % score - -class Storage(): - def __init__(self): - self.db = MySQLdb.connect( - user = os.getenv('db_user'), - passwd = os.getenv('Mytest123**'), - db = os.getenv('test_db'), - host = os.getenv('localhost'), - port = int(os.getenv('3306')) - ) - - cur = self.db.cursor() - cur.execute("CREATE TABLE IF NOT EXISTS scores(score INT)") - - def populate(self): - cur = self.db.cursor() - cur.execute("INSERT INTO scores(score) VALUES(1234)") - - def score(self): - cur = self.db.cursor() - cur.execute("SELECT * FROM scores") - row = cur.fetchone() - return row[0] + return "Hello Devops 123" if __name__ == "__main__": application.run(host='0.0.0.0', port=3000) From 375d9965a9b78d5898ed6448b6222f34c6b6c4ff Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 21:05:29 +0300 Subject: [PATCH 06/14] app get from master --- app.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index dd38666..eeb17e1 100644 --- a/app.py +++ b/app.py @@ -7,7 +7,33 @@ @application.route('/') def hello_world(): - return "Hello Devops 123" + storage = Storage() + storage.populate() + score = storage.score() + return "Hello Devops 123, %d!" % score + +class Storage(): + def __init__(self): + self.db = MySQLdb.connect( + user = os.getenv('MYSQL_USERNAME'), + passwd = os.getenv('MYSQL_PASSWORD'), + db = os.getenv('MYSQL_INSTANCE_NAME'), + host = os.getenv('MYSQL_PORT_3306_TCP_ADDR'), + port = int(os.getenv('MYSQL_PORT_3306_TCP_PORT')) + ) + + cur = self.db.cursor() + cur.execute("CREATE TABLE IF NOT EXISTS scores(score INT)") + + def populate(self): + cur = self.db.cursor() + cur.execute("INSERT INTO scores(score) VALUES(1234)") + + def score(self): + cur = self.db.cursor() + cur.execute("SELECT * FROM scores") + row = cur.fetchone() + return row[0] if __name__ == "__main__": application.run(host='0.0.0.0', port=3000) From 11ae84e5053ccccdfaec090daa4bd4eabed17d6d Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 22:49:38 +0300 Subject: [PATCH 07/14] Updated Dockerfile --- Dockerfile | 4 ++-- app.py | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index f190c45..9e14766 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -FROM alpine -FROM python:3.7 +FROM python:3.8-alpine +RUN apk add gcc musl-dev mariadb-connector-c-dev COPY requirements.txt /tmp WORKDIR /tmp RUN pip install --upgrade pip && \ diff --git a/app.py b/app.py index eeb17e1..7ffb32b 100644 --- a/app.py +++ b/app.py @@ -14,13 +14,7 @@ def hello_world(): class Storage(): def __init__(self): - self.db = MySQLdb.connect( - user = os.getenv('MYSQL_USERNAME'), - passwd = os.getenv('MYSQL_PASSWORD'), - db = os.getenv('MYSQL_INSTANCE_NAME'), - host = os.getenv('MYSQL_PORT_3306_TCP_ADDR'), - port = int(os.getenv('MYSQL_PORT_3306_TCP_PORT')) - ) + self.db = MySQLdb.connect("192.168.2.106","db_user","Mytest123**","test_db" ) cur = self.db.cursor() cur.execute("CREATE TABLE IF NOT EXISTS scores(score INT)") From 65eb754ca9221c16ac6f7e81d583d12b5590d43d Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Sun, 10 Oct 2021 23:38:38 +0300 Subject: [PATCH 08/14] change environment variables --- app.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index 7ffb32b..eeb17e1 100644 --- a/app.py +++ b/app.py @@ -14,7 +14,13 @@ def hello_world(): class Storage(): def __init__(self): - self.db = MySQLdb.connect("192.168.2.106","db_user","Mytest123**","test_db" ) + self.db = MySQLdb.connect( + user = os.getenv('MYSQL_USERNAME'), + passwd = os.getenv('MYSQL_PASSWORD'), + db = os.getenv('MYSQL_INSTANCE_NAME'), + host = os.getenv('MYSQL_PORT_3306_TCP_ADDR'), + port = int(os.getenv('MYSQL_PORT_3306_TCP_PORT')) + ) cur = self.db.cursor() cur.execute("CREATE TABLE IF NOT EXISTS scores(score INT)") From c68825e4d81f5e57dc98c98d5c7de7539b630bff Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Mon, 11 Oct 2021 07:04:49 +0300 Subject: [PATCH 09/14] Updated README file. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 677121e..42eebc1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # devops-python-app -Simple Python app code for DevOps challenges +This application is a simple web application that keeps the scores of devops and prints it to the screen. The application was developed with python and was used flask web framework. Mysql is used as database. The libraries required for the application are also available in requirement.txt. + +The application contains docker container. The Docker image runs on Alpine Linux. Kubernetes engine is used for container orchestration. + +Two separate branches were created for the application. One of them is the local branch and the other is the main branch. The application developer develops and tests the code on its own environment. It then merges the changes into the main branch. The change on the main branch is automatically detected and deployment is made to the product environment. From f88b7d8449f072d2cbbcb54a5937ae0c2470d03c Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Mon, 11 Oct 2021 07:08:40 +0300 Subject: [PATCH 10/14] Updated README.md file --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 42eebc1..cd238bd 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,5 @@ This application is a simple web application that keeps the scores of devops and The application contains docker container. The Docker image runs on Alpine Linux. Kubernetes engine is used for container orchestration. Two separate branches were created for the application. One of them is the local branch and the other is the main branch. The application developer develops and tests the code on its own environment. It then merges the changes into the main branch. The change on the main branch is automatically detected and deployment is made to the product environment. + +Kubernetes secrets are used for application variables on product environment. In the local development environment, the variables are kept on the OS environment variable. From fa66f3dea0c96f293c4ef4900d8974a8999fb397 Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Wed, 13 Oct 2021 02:03:57 +0300 Subject: [PATCH 11/14] added kubernetes configuration files --- k8s/secret.yaml | 9 +++++++++ k8s/service.yaml | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 k8s/secret.yaml create mode 100644 k8s/service.yaml diff --git a/k8s/secret.yaml b/k8s/secret.yaml new file mode 100644 index 0000000..4eafea5 --- /dev/null +++ b/k8s/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +data: + MYSQL_PASSWORD: none + MYSQL_USERNAME: none +kind: Secret +metadata: + name: credentials + namespace: default +type: Opaque \ No newline at end of file diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..b1493ad --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: python-app + env: prod + name: python-app-76rl8 + namespace: default +spec: + externalTrafficPolicy: Cluster + ports: + - nodePort: 32346 + port: 80 + protocol: TCP + targetPort: 3000 + selector: + app: python-app + env: prod + sessionAffinity: None + type: LoadBalancer \ No newline at end of file From 6621ed22cb1dbb812cc5739a92bdd2ba28b2bde0 Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Wed, 13 Oct 2021 02:05:14 +0300 Subject: [PATCH 12/14] added kubernetes files --- k8s/configMap.yaml | 12 +++++++++++ k8s/deployment.yaml | 50 +++++++++++++++++++++++++++++++++++++++++++++ k8s/hpa.yaml | 21 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 k8s/configMap.yaml create mode 100644 k8s/deployment.yaml create mode 100644 k8s/hpa.yaml diff --git a/k8s/configMap.yaml b/k8s/configMap.yaml new file mode 100644 index 0000000..69962a7 --- /dev/null +++ b/k8s/configMap.yaml @@ -0,0 +1,12 @@ +apiVersion: "v1" +kind: "ConfigMap" +metadata: + name: "python-app-config-mrqi" + namespace: "default" + labels: + app: "python-app" + env: "prod" +data: + MYSQL_INSTANCE_NAME: "db_vngrs" + MYSQL_PORT_3306_TCP_ADDR: "10.69.32.3" + MYSQL_PORT_3306_TCP_PORT: "3306" \ No newline at end of file diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..336a89b --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: "apps/v1" +kind: "Deployment" +metadata: + name: "python-app" + namespace: "default" + labels: + app: "python-app" + env: "prod" +spec: + replicas: 1 + selector: + matchLabels: + app: "python-app" + env: "prod" + template: + metadata: + labels: + app: "python-app" + env: "prod" + spec: + containers: + - name: "vngrs-sha256-1" + image: "gcr.io/kubernetesproject-328818/vngrs@sha256:71440017a605152d99328ee78b264268327d4b7efb0c8eb0255901232616b2dd" + env: + - name: "MYSQL_INSTANCE_NAME" + valueFrom: + configMapKeyRef: + key: "MYSQL_INSTANCE_NAME" + name: "python-app-config-mrqi" + - name: "MYSQL_PORT_3306_TCP_ADDR" + valueFrom: + configMapKeyRef: + key: "MYSQL_PORT_3306_TCP_ADDR" + name: "python-app-config-mrqi" + - name: "MYSQL_PORT_3306_TCP_PORT" + valueFrom: + configMapKeyRef: + key: "MYSQL_PORT_3306_TCP_PORT" + name: "python-app-config-mrqi" + - name: "MYSQL_USERNAME" + valueFrom: + secretKeyRef: + key: "MYSQL_USERNAME" + name: "credentials" + - name: "MYSQL_PASSWORD" + valueFrom: + secretKeyRef: + key: "MYSQL_PASSWORD" + name: "credentials" \ No newline at end of file diff --git a/k8s/hpa.yaml b/k8s/hpa.yaml new file mode 100644 index 0000000..5f4b048 --- /dev/null +++ b/k8s/hpa.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: "autoscaling/v2beta1" +kind: "HorizontalPodAutoscaler" +metadata: + name: "python-app-hpa-vc7c" + namespace: "default" + labels: + app: "python-app" + env: "prod" +spec: + scaleTargetRef: + kind: "Deployment" + name: "python-app" + apiVersion: "apps/v1" + minReplicas: 1 + maxReplicas: 2 + metrics: + - type: "Resource" + resource: + name: "cpu" + targetAverageUtilization: 80 \ No newline at end of file From da6addf219e8b6a3b2625a2de043771d5a2a7333 Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Wed, 13 Oct 2021 02:20:31 +0300 Subject: [PATCH 13/14] added automatic deployment configuration file --- kubernetes/autodeployment.yaml | 177 +++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 kubernetes/autodeployment.yaml diff --git a/kubernetes/autodeployment.yaml b/kubernetes/autodeployment.yaml new file mode 100644 index 0000000..e58f444 --- /dev/null +++ b/kubernetes/autodeployment.yaml @@ -0,0 +1,177 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: python-app + env: prod + name: python-app + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: python-app + env: prod + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: python-app + env: prod + spec: + containers: + - env: + - name: MYSQL_INSTANCE_NAME + valueFrom: + configMapKeyRef: + key: MYSQL_INSTANCE_NAME + name: python-app-config-mrqi + - name: MYSQL_PORT_3306_TCP_ADDR + valueFrom: + configMapKeyRef: + key: MYSQL_PORT_3306_TCP_ADDR + name: python-app-config-mrqi + - name: MYSQL_PORT_3306_TCP_PORT + valueFrom: + configMapKeyRef: + key: MYSQL_PORT_3306_TCP_PORT + name: python-app-config-mrqi + - name: MYSQL_USERNAME + valueFrom: + secretKeyRef: + key: MYSQL_USERNAME + name: credentials + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + key: MYSQL_PASSWORD + name: credentials + image: >- + gcr.io/kubernetesproject-328818/github.com/emrahbickingc/devops-python-app + imagePullPolicy: IfNotPresent + name: vngrs-sha256-1 +--- +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + labels: + app: python-app + env: prod + managedFields: + - apiVersion: autoscaling/v2beta1 + fieldsType: FieldsV1 + fieldsV1: + 'f:metadata': + 'f:annotations': + .: {} + 'f:kubectl.kubernetes.io/last-applied-configuration': {} + 'f:labels': + .: {} + 'f:app': {} + 'f:env': {} + 'f:spec': + 'f:maxReplicas': {} + 'f:metrics': {} + 'f:minReplicas': {} + 'f:scaleTargetRef': + 'f:apiVersion': {} + 'f:kind': {} + 'f:name': {} + manager: kubectl-client-side-apply + operation: Update + time: '2021-10-12T21:40:24Z' + - apiVersion: autoscaling/v1 + fieldsType: FieldsV1 + fieldsV1: + 'f:metadata': + 'f:annotations': + 'f:autoscaling.alpha.kubernetes.io/conditions': {} + 'f:status': + 'f:currentReplicas': {} + manager: vpa-recommender + operation: Update + time: '2021-10-12T21:40:40Z' + name: python-app-hpa-vc7c + namespace: default +spec: + maxReplicas: 2 + metrics: + - resource: + name: cpu + targetAverageUtilization: 80 + type: Resource + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: python-app +--- +apiVersion: v1 +kind: Service +metadata: + finalizers: + - service.kubernetes.io/load-balancer-cleanup + generateName: python-app- + labels: + app: python-app + env: prod + managedFields: + - apiVersion: v1 + fieldsType: FieldsV1 + fieldsV1: + 'f:metadata': + 'f:generateName': {} + 'f:labels': + .: {} + 'f:app': {} + 'f:env': {} + 'f:spec': + 'f:externalTrafficPolicy': {} + 'f:ports': + .: {} + 'k:{"port":80,"protocol":"TCP"}': + .: {} + 'f:port': {} + 'f:protocol': {} + 'f:targetPort': {} + 'f:selector': + .: {} + 'f:app': {} + 'f:env': {} + 'f:sessionAffinity': {} + 'f:type': {} + manager: GoogleCloudConsole + operation: Update + time: '2021-10-12T22:47:29Z' + - apiVersion: v1 + fieldsType: FieldsV1 + fieldsV1: + 'f:metadata': + 'f:finalizers': + .: {} + 'v:"service.kubernetes.io/load-balancer-cleanup"': {} + 'f:status': + 'f:loadBalancer': + 'f:ingress': {} + manager: kube-controller-manager + operation: Update + time: '2021-10-12T22:48:23Z' + name: python-app-76rl8 + namespace: default +spec: + clusterIP: 10.44.12.96 + externalTrafficPolicy: Cluster + ports: + - nodePort: 32346 + port: 80 + protocol: TCP + targetPort: 3000 + selector: + app: python-app + env: prod + sessionAffinity: None + type: LoadBalancer \ No newline at end of file From d7da9ff2837cf298e99b2e414b8add3bd2847590 Mon Sep 17 00:00:00 2001 From: emrahbickingc Date: Wed, 13 Oct 2021 02:30:41 +0300 Subject: [PATCH 14/14] updated README file --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd238bd..402110e 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,6 @@ The application contains docker container. The Docker image runs on Alpine Linux Two separate branches were created for the application. One of them is the local branch and the other is the main branch. The application developer develops and tests the code on its own environment. It then merges the changes into the main branch. The change on the main branch is automatically detected and deployment is made to the product environment. -Kubernetes secrets are used for application variables on product environment. In the local development environment, the variables are kept on the OS environment variable. +Kubernetes secrets and configMaps are used for application variables on product environment. In the local development environment, the variables are kept on the OS environment variable. + +Google cloud build is used for CI/CD pipeline process. When a change is detected in the main branch, cloud build creates a new docker image and deploys the new image to kubernetes.