├── .gitignore ├── test └── index.js ├── Dockerfile ├── index.html ├── release.config.js ├── kubernetes ├── drone-secrets.yaml ├── drone-pvc.yaml └── drone.yaml ├── ci-demo.yaml ├── README.md └── .drone.yml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | node_modules 4 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | console.log('Unit test passed'); 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.15-alpine 2 | 3 | COPY index.html /usr/share/nginx/html/ 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello World 4 | 5 | 6 | Hello World 7 | 8 | 9 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | '@semantic-release/commit-analyzer', 4 | '@semantic-release/release-notes-generator', 5 | '@semantic-release/github' 6 | ] 7 | }; 8 | -------------------------------------------------------------------------------- /kubernetes/drone-secrets.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | type: Opaque 5 | data: 6 | DOCKER_PASSWORD: encoded_password 7 | metadata: 8 | name: drone-secrets 9 | namespace: default 10 | -------------------------------------------------------------------------------- /ci-demo.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: ci-demo-deployment 6 | namespace: default 7 | labels: 8 | app: ci-demo 9 | spec: 10 | replicas: 1 11 | template: 12 | spec: 13 | containers: 14 | - image: allovince/drone-ci-demo 15 | name: ci-demo 16 | restartPolicy: Always 17 | -------------------------------------------------------------------------------- /kubernetes/drone-pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: drone-pv 6 | namespace: default 7 | labels: 8 | alicloud-pvname: drone-pv 9 | spec: 10 | capacity: 11 | storage: 2Gi 12 | accessModes: 13 | - ReadWriteMany 14 | persistentVolumeReclaimPolicy: Retain 15 | nfs: 16 | path: / 17 | server: "your_nas_service" 18 | 19 | --- 20 | kind: PersistentVolumeClaim 21 | apiVersion: v1 22 | metadata: 23 | name: drone-pvc 24 | namespace: default 25 | spec: 26 | accessModes: 27 | - ReadWriteMany 28 | resources: 29 | requests: 30 | storage: 2Gi 31 | selector: 32 | matchLabels: 33 | alicloud-pvname: drone-pv 34 | 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## A Demo to show workflow of Drone CI + GitFlow + Semantic Release + Kubernetes 2 | 3 | [![Build Status](https://cloud.drone.io/api/badges/AlloVince/drone-ci-demo/status.svg)](https://cloud.drone.io/AlloVince/drone-ci-demo) 4 | 5 | Step by step, to show how to build a powerful team development workflow with CI 6 | 7 | - [Github repo](https://github.com/AlloVince/drone-ci-demo) 8 | - [Drone CI of this repo](https://cloud.drone.io/AlloVince/drone-ci-demo) 9 | - [Docker Registry of this repo](https://cloud.docker.com/repository/docker/allovince/drone-ci-demo) 10 | 11 | ## Step 0: Hello world 12 | 13 | 1. Use drone cloud or setup a private drone by k8s 14 | 15 | Kubernetes config files under [./kubernetes](./kubernetes) 16 | 17 | 2. prepare `.drone.yml` 18 | 19 | ```yml 20 | kind: pipeline 21 | name: deploy 22 | 23 | steps: 24 | - name: hello-world 25 | image: docker 26 | commands: 27 | - echo "hello world" 28 | ``` 29 | 30 | ## Step 1: For single person, manually release 31 | 32 | 1. Add a secret in Drone, key is `DOCKER_PASSWORD`, value is your docker registry password 33 | 34 | 2. prepare `.drone.yml` 35 | 36 | ```yml 37 | kind: pipeline 38 | name: deploy 39 | 40 | steps: 41 | - name: unit-test 42 | image: node:10 43 | commands: 44 | - node test/index.js 45 | when: 46 | branch: master 47 | event: push 48 | - name: build-image 49 | image: plugins/docker 50 | settings: 51 | repo: allovince/drone-ci-demo 52 | username: allovince 53 | password: 54 | from_secret: DOCKER_PASSWORD 55 | auto_tag: true 56 | when: 57 | event: tag 58 | ``` 59 | 60 | 3. push to master branch will trigger unit test 61 | 62 | 4. manually release on github will trigger building docker image 63 | 64 | ## Step 2: For team develop, support GitFlow 65 | 66 | Change `.drone.yml` as [this](https://github.com/AlloVince/drone-ci-demo/blob/gitflow/.drone.yml) 67 | 68 | ## Step 3: For team develop, support GitFlow, with semantic-release 69 | 70 | Change `.drone.yml` as [this](https://github.com/AlloVince/drone-ci-demo/blob/semantic-release/.drone.yml) 71 | 72 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: pipeline 3 | name: deploy 4 | 5 | steps: 6 | - name: pre-check 7 | image: docker 8 | environment: 9 | DOCKER_PASSWORD: 10 | from_secret: DOCKER_PASSWORD 11 | MY_TELEGRAM_TOKEN: 12 | from_secret: MY_TELEGRAM_TOKEN 13 | MY_TELEGRAM_ID: 14 | from_secret: MY_TELEGRAM_ID 15 | GITHUB_TOKEN: 16 | from_secret: GITHUB_TOKEN 17 | commands: 18 | - echo $${DOCKER_PASSWORD} 19 | - echo $${MY_TELEGRAM_TOKEN} 20 | - echo $${MY_TELEGRAM_ID} 21 | - echo $${GITHUB_TOKEN} 22 | 23 | - name: unit-test 24 | image: node:10 25 | commands: 26 | - node test/index.js 27 | when: 28 | branch: 29 | include: 30 | - feature/* 31 | - master 32 | - dev 33 | event: 34 | include: 35 | - push 36 | - pull_request 37 | 38 | - name: build-branch-image 39 | image: plugins/docker 40 | settings: 41 | repo: allovince/drone-ci-demo 42 | username: allovince 43 | password: 44 | from_secret: DOCKER_PASSWORD 45 | tag: 46 | - ${DRONE_BRANCH##feature/} 47 | when: 48 | branch: feature/* 49 | event: push 50 | 51 | - name: build-test-image 52 | image: plugins/docker 53 | settings: 54 | repo: allovince/drone-ci-demo 55 | username: allovince 56 | password: 57 | from_secret: DOCKER_PASSWORD 58 | tag: 59 | - test 60 | when: 61 | branch: dev 62 | event: push 63 | 64 | - name: build-staging-image 65 | image: plugins/docker 66 | settings: 67 | repo: allovince/drone-ci-demo 68 | username: allovince 69 | password: 70 | from_secret: DOCKER_PASSWORD 71 | tag: 72 | - latest 73 | when: 74 | branch: master 75 | event: pull_request 76 | 77 | - name: semantic-release 78 | image: gtramontina/semantic-release:15.13.3 79 | environment: 80 | GITHUB_TOKEN: 81 | from_secret: GITHUB_TOKEN 82 | entrypoint: 83 | - semantic-release 84 | when: 85 | branch: master 86 | event: push 87 | 88 | - name: build-production-image 89 | image: plugins/docker 90 | settings: 91 | repo: allovince/drone-ci-demo 92 | username: allovince 93 | password: 94 | from_secret: DOCKER_PASSWORD 95 | tag: 96 | - ${DRONE_TAG} 97 | when: 98 | event: tag 99 | 100 | - name: k8s-deploy 101 | image: quay.io/honestbee/drone-kubernetes 102 | settings: 103 | kubernetes_server: 104 | from_secret: KUBERNETES_SERVER 105 | kubernetes_cert: 106 | from_secret: KUBERNETES_CERT 107 | kubernetes_token: 108 | from_secret: KUBERNETES_TOKEN 109 | namespace: default 110 | deployment: ci-demo-deployment 111 | repo: allovince/drone-ci-demo 112 | container: ci-demo 113 | tag: 114 | - ${DRONE_TAG} 115 | # remove commands in real production env 116 | commands: 117 | - echo "kubectl -n default set image deployment/ci-demo-deployment ci-demo=allovince/drone-ci-demo:${DRONE_TAG}" 118 | when: 119 | event: tag 120 | -------------------------------------------------------------------------------- /kubernetes/drone.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: drone-rbac 6 | subjects: 7 | - kind: ServiceAccount 8 | name: default 9 | namespace: default 10 | roleRef: 11 | kind: ClusterRole 12 | name: cluster-admin 13 | apiGroup: rbac.authorization.k8s.io 14 | 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: drone-secrets 20 | namespace: default 21 | labels: 22 | app: drone-secrets 23 | spec: 24 | replicas: 1 25 | selector: 26 | matchLabels: 27 | app: drone-secrets 28 | template: 29 | metadata: 30 | labels: 31 | app: drone-secrets 32 | spec: 33 | containers: 34 | - name: drone-secrets 35 | image: drone/kubernetes-secrets 36 | imagePullPolicy: Always 37 | env: 38 | - name: SECRET_KEY 39 | value: your_secret_key 40 | ports: 41 | - name: http 42 | containerPort: 3000 43 | restartPolicy: Always 44 | 45 | --- 46 | kind: Service 47 | apiVersion: v1 48 | metadata: 49 | name: drone-secrets-service 50 | namespace: default 51 | spec: 52 | selector: 53 | app: drone-secrets 54 | ports: 55 | - protocol: TCP 56 | port: 80 57 | targetPort: 3000 58 | name: http 59 | 60 | --- 61 | apiVersion: apps/v1 62 | kind: Deployment 63 | metadata: 64 | name: drone-server 65 | namespace: default 66 | labels: 67 | app: drone-server 68 | spec: 69 | replicas: 1 70 | selector: 71 | matchLabels: 72 | app: drone-server 73 | template: 74 | metadata: 75 | labels: 76 | app: drone-server 77 | spec: 78 | containers: 79 | - name: drone-server 80 | image: drone/drone:1.0.0 81 | imagePullPolicy: Always 82 | env: 83 | - name: DRONE_KUBERNETES_ENABLED 84 | value: "true" 85 | - name: DRONE_KUBERNETES_NAMESPACE 86 | value: default 87 | - name: DRONE_GITHUB_SERVER 88 | value: https://github.com 89 | - name: DRONE_GITHUB_CLIENT_ID 90 | value: your_github_client_id 91 | - name: DRONE_GITHUB_CLIENT_SECRET 92 | value: your_github_client_secret 93 | - name: DRONE_SERVER_HOST 94 | value: your_domain 95 | - name: DRONE_SERVER_PROTO 96 | value: https 97 | - name: DRONE_DATABASE_DRIVER 98 | value: sqlite3 99 | - name: DRONE_DATABASE_DATASOURCE 100 | value: "/drone/drone.sqlite" 101 | - name: DRONE_USER_CREATE 102 | value: username:AlloVince,admin:true 103 | - name: DRONE_SECRET_SECRET 104 | value: your_secret_key 105 | - name: DRONE_SECRET_ENDPOINT 106 | value: http://drone-secrets-service 107 | ports: 108 | - name: http 109 | containerPort: 80 110 | - name: https 111 | containerPort: 443 112 | volumeMounts: 113 | - name: drone-pvc 114 | mountPath: "/drone" 115 | volumes: 116 | - name: drone-pvc 117 | persistentVolumeClaim: 118 | claimName: drone-pvc 119 | restartPolicy: Always 120 | 121 | --- 122 | kind: Service 123 | apiVersion: v1 124 | metadata: 125 | name: drone-server-service 126 | namespace: default 127 | spec: 128 | selector: 129 | app: drone-server 130 | ports: 131 | - protocol: TCP 132 | port: 80 133 | name: http 134 | 135 | 136 | --- 137 | apiVersion: extensions/v1beta1 138 | kind: Ingress 139 | metadata: 140 | name: drone-ingress 141 | namespace: default 142 | annotations: 143 | kubernetes.io/ingress.class: traefik 144 | traefik.ingress.kubernetes.io/frontend-entry-points: http,https 145 | spec: 146 | rules: 147 | - host: your_domain 148 | http: 149 | paths: 150 | - path: / 151 | backend: 152 | serviceName: drone-server-service 153 | servicePort: 80 154 | 155 | --------------------------------------------------------------------------------