├── .gitignore ├── LICENSE ├── README.md ├── apps ├── argocd │ └── fastapi-service-development.yaml └── fastapi-service │ ├── base │ ├── deployment.yaml │ ├── kustomization.yaml │ └── service.yaml │ └── overlays │ └── development │ ├── ingress.yaml │ ├── kustomization.yaml │ ├── kustomize │ ├── replica-count.yaml │ └── sealed-secret.yaml └── projects └── fastapi-app.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Valon Januzaj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kuberntes-demo-gitops 2 | See the application source code: [kubernetes-demo-app](https://github.com/vjanz/kubernetes-demo-app) 3 | 4 | ## Project sturcture 5 | ``` 6 | ├── apps 7 | │   ├── argocd - Declarative ArgoCD applications 8 | │   │   └── fastapi...yaml 9 | │   └── fastapi-service - One of the apps in GitOps 10 | │   ├── base - Base of kustomization (common resources) 11 | │   │   ├── deployment.yaml 12 | │   │   ├── kustomization.yaml 13 | │   │   └── service.yaml 14 | │   └── overlays - Overlays of kustomization 15 | │   ├── development - Environment specific resources 16 | │   │   ├── ingress.yaml 17 | │   │   ├── kustomization.yaml 18 | │   │   ├── replica-count.yaml 19 | │   │   └── sealed-secret.yaml 20 | │   └── production 21 | └── projects - Separation of projects in ArgoCD 22 | └── fastapi-app.yaml 23 | 24 | ``` 25 | 26 | ### Definition of GitOps Repository 27 | A GitOps repository is supposed to hold files that are used to deploy applications. It is not supposed to hold application code. The application code is supposed to be in a separate repository. The GitOps repository is supposed to hold the following files: 28 | 29 | - ArgoCD applications 30 | - Kustomization files 31 | - Environment specific resources 32 | - Secrets 33 | - ConfigMaps 34 | - Helm charts 35 | - Terraform files, etc. 36 | 37 | Aside of adding new application to this repository, or updating existing application, the manifests should be modified by the CI/CD pipeline. The CI/CD pipeline should be responsible for building and pushing the application image, and updating the manifests with the new image tag on this repository -------------------------------------------------------------------------------- /apps/argocd/fastapi-service-development.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: fastapi-service-development 5 | namespace: argocd 6 | spec: 7 | project: fastapi-project 8 | source: 9 | repoURL: git@github.com:vjanz/kubernetes-demo-gitops.git 10 | targetRevision: main 11 | path: apps/fastapi-service/overlays/development 12 | destination: 13 | server: https://kubernetes.default.svc 14 | namespace: kubernetes-demo-dev 15 | syncPolicy: 16 | automated: # automated sync by default retries failed attempts 5 times with following delays between attempts ( 5s, 10s, 20s, 40s, 80s ); retry controlled using `retry` field. 17 | prune: true # Specifies if resources should be pruned during auto-syncing ( false by default ). 18 | selfHeal: true # Specifies if partial app sync should be executed when resources are changed only in target Kubernetes cluster and no git change detected ( false by default ). 19 | allowEmpty: true # Allows deleting all application resources during automatic syncing ( false by default ). 20 | syncOptions: # Sync options which modifies sync behavior 21 | - Validate=false # disables resource validation (equivalent to 'kubectl apply --validate=false') ( true by default ). 22 | - CreateNamespace=true # Namespace Auto-Creation ensures that namespace specified as the application destination exists in the destination cluster. 23 | - PrunePropagationPolicy=foreground # Supported policies are background, foreground and orphan. 24 | - PruneLast=true # Allow the ability for resource pruning to happen as a final, implicit wave of a sync operation 25 | # The retry feature is available since v1.7 26 | retry: 27 | limit: 5 # number of failed sync attempt retries; unlimited number of attempts if less than 0 28 | backoff: 29 | duration: 5s # the amount to back off. Default unit is seconds, but could also be a duration (e.g. "2m", "1h") 30 | factor: 2 # a factor to multiply the base duration after each failed retry 31 | maxDuration: 3m # the maximum amount of time allowed for the backoff strategy 32 | -------------------------------------------------------------------------------- /apps/fastapi-service/base/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kubernetes-demo 5 | spec: 6 | replicas: 2 7 | selector: 8 | matchLabels: 9 | app: kubernetes-demo 10 | template: 11 | metadata: 12 | labels: 13 | app: kubernetes-demo 14 | spec: 15 | containers: 16 | - name: kubernetes-demo 17 | image: example-image 18 | ports: 19 | - containerPort: 8000 20 | envFrom: 21 | - secretRef: 22 | name: demo-secrets 23 | -------------------------------------------------------------------------------- /apps/fastapi-service/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - deployment.yaml 5 | - service.yaml 6 | -------------------------------------------------------------------------------- /apps/fastapi-service/base/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: kubernetes-demo 5 | namespace: kubernetes-demo 6 | spec: 7 | ports: 8 | - name: http 9 | protocol: TCP 10 | port: 80 11 | targetPort: 8000 12 | selector: 13 | app: kubernetes-demo -------------------------------------------------------------------------------- /apps/fastapi-service/overlays/development/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: kubernetes-demo-ingress 5 | annotations: 6 | cert-manager.io/cluster-issuer: letsencrypt-cluster-issuer 7 | spec: 8 | # Add tls section 9 | tls: 10 | - hosts: 11 | - "demo.vjanztutorials.tech" 12 | secretName: kubernetes-demo-tls 13 | ingressClassName: nginx 14 | rules: 15 | - host: "demo.vjanztutorials.tech" 16 | http: 17 | paths: 18 | - backend: 19 | service: 20 | name: kubernetes-demo 21 | port: 22 | number: 80 23 | path: / 24 | pathType: Prefix 25 | 26 | -------------------------------------------------------------------------------- /apps/fastapi-service/overlays/development/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../../base 3 | - ingress.yaml 4 | - sealed-secret.yaml 5 | patchesStrategicMerge: 6 | - replica-count.yaml 7 | apiVersion: kustomize.config.k8s.io/v1beta1 8 | kind: Kustomization 9 | namespace: kubernetes-demo-dev 10 | images: 11 | - name: example-image 12 | newName: valonjanuzaj/kubernetes-demo 13 | newTag: 2124c9bdb610feca25eeffb442f1423507767753 14 | -------------------------------------------------------------------------------- /apps/fastapi-service/overlays/development/kustomize: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vjanz/kubernetes-demo-gitops/89e82746a2ffd3d471ccefddf588d5b934764450/apps/fastapi-service/overlays/development/kustomize -------------------------------------------------------------------------------- /apps/fastapi-service/overlays/development/replica-count.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kubernetes-demo 5 | spec: 6 | replicas: 1 -------------------------------------------------------------------------------- /apps/fastapi-service/overlays/development/sealed-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bitnami.com/v1alpha1 2 | kind: SealedSecret 3 | metadata: 4 | annotations: 5 | sealedsecrets.bitnami.com/cluster-wide: "true" 6 | creationTimestamp: null 7 | name: demo-secrets 8 | spec: 9 | encryptedData: 10 | POSTGRES_DB: AgBLjgBM7CIlaEnxTWVedkmhd5HgO+Ep9HUNfwGNLe4K7tFS540xoVvvwV9g7UZJM547dcn3F5thfKal4ilah4UixQ1Y5w9ZG38jf4zo1AwiXaV+1YdvXjC7NLRAQhh3Ya8bwJT7QOJRS0vGioJRWkB9BY5JUHlgTJHvVcuMdwoD0vR34M3Z5XswrMr+uBBLyasrDSKtrhhIOxGTsMHtYWzfWm2UiJRp/s6hnsZG4N5IAFDB8HYcMCWGkTtZ3DGsX6XD30JrK6txpGmRb4PjYIFiKtFgp3uKWHS4XN2rgiK0VdpvgdZbgLVclX24NK+o/P+75cwHyVP6aGY9DIWFmovj3afaEfVYcnO91EC0l0V716HE6q3lKB204hpsZ3ioTPV+9MSzW6YixafX2t+J2wQiUd8q996v5lNWomRPdyjw0P2lXzJUbjkQjHeMK2UBu7xLz/ODb7QDhQpOnKGm/Wz1Tj/brd6vpDWVdntY8+9KDW1n3e6E4po8P2P09ihP4OtkFbD2jKC/56FUvV5y3wlP5XJxn9jqoZJBcq4PGS3cpngjUSimOfc9WpvG3wLhpXSFLlVXrWxoPeklBcX++sy4blFQ34JHXiD+48qk5GY7ceW45PcJOQv6REUUo2OCdWt9KUqrWiC6WgM1STJ7sScWNHL0ito9N3eNm+T8nwaI/jNwSLNCQNHkIUId8t86w9NqclSUsda1xQuGUqj/JU8= 11 | POSTGRES_PASSWORD: AgCBdPMRPxax/teLQw9fzLiYnXcDOZY+6Ly+eqem2qIePzg65guoTkqnMaQnCi3veUIi4RlimiMBoLxhMe6sHBX2LrEESfbtf2nRtZrs69QNG1lvOKMylXNpNHYISEKh6D3GWApcdYM/phXr0QbMZY6+CP0dMAn3tPTXBj1HZ3MJgwZYMKnKdAQbY49FprHwO0N28te96IvqagdlEIWKkYXBtazHG7lAIJDKfleHDyWa1FLjbtrjb+oXbx3eBd/scKagYdZc/I7EkelbMKNuzGgMRnKjaN/fez1dvwnzPWqRKgiAMQP05jfO15bjOWGqlwU2UFd1RQuB1gzrJViDo3tWI7vYXpegIWbBPes1jCC3y5hybxprGoWMkiMRXmj+anVbLRl1ZH+SRcZldCUOTzhUFI9J/vc2rb6kOj+aetR0eJKrhZ6/SkR5Sa9kHzakUDROmdC9cIzSVfZ3RA1aBSs56JCX7gLvDndPGpT/BFfMMt41DiA6O7TtM3CEM/qB+YDs9XFJVPsDlHkdMziv0bAR5jRNQTa5xCTSMt6VU/ef0+415pv1iJqau85TK5hSptSq/3Fn6ARhTtcw1RpvY3USd8PDVHMbQkdLW5SnEAFp37WUrjjqi7VcrGcVNGwQZbAzzyg4ns3EQ3p3TU4uXzbcTHeLHfzA/NKDRAzqMV1d3PWPlMuDfVqfQaXBPv8LKeFMWNt75URrUov4 12 | POSTGRES_PORT: AgCLN36HvCVsCc+7MT8IwP9bpcTJcoqh80USdqsUmhwEFYhzAo8Kux3/gwxnghDDvEya9WCQSAEbuAD6hX4Yo7T+sbSD5+oxDRZAU+YFPdYjAJs0tOhMAM2AwAmj1cJLoGFRUqqCFI2uFRExB1nJkr1e0QOgingnnLWPPvUIP0v/Gj3Bh/+FC925LppZcjJxuJ9xyRYuj1bqLoqAmw9YtXPYOArlAYn1t1+xDseSxvAYo7UU1+QCx82zBZVyXnEpyPaGjKsqIE9O4MaV4g62W7VbBNtRbK7lCinggjFzQLv/T8s0IVgmqGMtou4oPamtlZN8OThUZF2W5B+PBBBHsKXIiOAoWVCF27x3mEC7OLlpRwwVpic4y9nDHkLLg2V0Wpcnu8m41voyjQywT8fDP2ogl3sDHeUpouG2UduumWz4PZpDyNBriJ9cZUwa+de00mLftA170scDBqqw3hTkmvnbwoy/+L6mYjJn1/yl1lUUMd4ezYm1Ki7dwRzrXfvy/zIpHHQt2T1Av2JHpCEhlW8DoBPAP5C0nobUUSRxNqvBgeN81GRORohsfKjs76wwSJyyOXuU4Y9eLD0JDZuJ9aei6T/jAd8nubcef7jw2pwIuAQ5RrCGot8mHWQwXjd52/XWqyVUzcksqnMcsuK7u93/SKcKZb9tr2wMzLw75PjYRXYrTblyH5DAmOAhNVjLzculWGDZ 13 | POSTGRES_SERVER: AgBTTiwCjdNsETS/9aoJzvSVtPsUWfY5ZSnHmsDxQxgaPR1TWbZx1iNuZjOIw0XZm6T3OBnGoVKq09kQdMS0DOvOtZ+XNoP7S+88Ee82lyymMZyCBDlMcAUyHxR6Xa/RpqE1IFtZB5m/aubN23A9vevZkH73cwWTwl/CTVmsb9x0dY6W3NExOG5FQ7HaOsTrnyirDZSyLRYGnYNCeqzY1OFPiPQLcyYJoFwDfATQ7e7x0O3S6vhnj/KeUCxunsMpSsIavjdo/t8DgFtkUhNaWfCr3LWB4WdL2uIeCs8gebyzO7xaxR+/XKCHSrH9WeLHkQknwwfVdWFidGMtUXLvUvOM26EsrmIcAnioD6rxpRtIszWuDYNAl7qdk+s4WsXJFWuiUzALNioWuwUGDlICb6ViWGdlbTXI2W8PYQFHiuCTByGk93hc46T+jdsiM+gxzik5FdhFMAnsqZLzkvfqJfeBT5Sr/+AGfjke/SH5ses/KB+61NtCRiBwaL10S73KwKmzk6wC/zBv1sEICWJhf08Z+VU2q76HcJJXu9Ll66uvo/YWViNPR1W7Rt881QGzof1/MEf3Rc1xy0Ni65Z87mQEMs68wzjLb2eLpPk5x3AAPgjGVQw1CVgnutoOlwZevwayCP/5kNIE5Bzhm4pgx41sjeBItqZxvkXqgNpBIfcxKPs6rECgLRws1tRNId0xLhkkvfma5ckpC0M4UlagplpnfuriNzOnZv3MZ+q2 14 | POSTGRES_USER: AgCTJA1LSrYSdLn/3IrGyxjbI3LXIu5sN+Swt84RsLDgOvqAuqJ9aL8YHotWwumUBpxxdm3MdCUoTcWqnTgUSst9hRvgrO72YQr9ej2YBe5CBbPXbO6Y7PQNbm0rz73AKo7HAI5GOP77Kd/o2ovos9f1dWLayI7+6HDvl4FjBCHTQ8B+e2kJnBHSB8/P6PdGAOks5qMBK8hCMu9gUjpxygGgZDAiW+ITInbzKABh+6AbMgXSl7WRGZVgwGZ1Mlezh13rDOmMhy/68j2s5HaOlgnvGmJYqyS3k5NegO7nhTwvlqzQCI/zuca8e+PpoedIa6XG3c6Y91psrIwZn2e7KT2z5sXUSRq/IX+PnH+Qx+SJIJP/0UL2cuVal+DXyr1jA2lZSizFBW5ZpLteDVRMFcjwVj0gaz5EUkpeGJPRJa/yQVi/KnB/KHRx8VxxE6k2fDY3NKb9hsx6E0Mjwsc9fdHC5W18pbwc/QGiN7bO9WSCusoibletolLS9eS7YBEORG+4LiYyhzI9KAzp3a9FZu15R4CZW6QNvxjo7sOAMkH71U8JNpz1h77bpKelEgPpVPtS9WCFQ8acGsJn+kVpxV28TdOPX4CKBdiuv/pSKvfyZ54nxZToJZuQ8hwjjUf2LXcqYIqvIR7Oe5wO7JFobKIXHUVcPndhY5SPGjShH9+HhaTvAL1h6DkkeYsPMtoJ47vLgMDDgtnqdA== 15 | template: 16 | metadata: 17 | annotations: 18 | sealedsecrets.bitnami.com/cluster-wide: "true" 19 | creationTimestamp: null 20 | name: demo-secrets 21 | type: Opaque 22 | 23 | -------------------------------------------------------------------------------- /projects/fastapi-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: AppProject 3 | metadata: 4 | name: fastapi-project 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | description: FastAPI demo project 10 | sourceRepos: 11 | - '*' 12 | destinations: 13 | - namespace: '*' 14 | server: '*' 15 | clusterResourceWhitelist: 16 | - group: '*' 17 | kind: '*' 18 | namespaceResourceWhitelist: 19 | - group: '*' 20 | kind: '*' --------------------------------------------------------------------------------