├── concourse-web-service.yaml ├── concourse-db-service.yaml ├── concourse-worker-service.yaml ├── concourse-db-deployment.yaml ├── concourse-worker-deployment.yaml ├── pipeline └── pipeline │ └── pipeline.yml ├── concourse-web-deployment.yaml └── README.md /concourse-web-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | service: concourse-web 6 | name: concourse-web 7 | spec: 8 | # clusterIP: None 9 | ports: 10 | type: NodePort 11 | ports: 12 | - name: "8080" 13 | port: 8080 14 | nodePort: 32080 15 | selector: 16 | service: concourse-web 17 | -------------------------------------------------------------------------------- /concourse-db-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | service: concourse-db 7 | name: concourse-db 8 | spec: 9 | clusterIP: None 10 | ports: 11 | - name: headless 12 | port: 55555 13 | targetPort: 0 14 | selector: 15 | service: concourse-db 16 | status: 17 | loadBalancer: {} 18 | -------------------------------------------------------------------------------- /concourse-worker-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | service: concourse-worker 7 | name: concourse-worker 8 | spec: 9 | clusterIP: None 10 | ports: 11 | - name: headless 12 | port: 55555 13 | targetPort: 0 14 | selector: 15 | service: concourse-worker 16 | status: 17 | loadBalancer: {} 18 | -------------------------------------------------------------------------------- /concourse-db-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | service: concourse-db 7 | name: concourse-db 8 | spec: 9 | replicas: 1 10 | strategy: {} 11 | template: 12 | metadata: 13 | creationTimestamp: null 14 | labels: 15 | service: concourse-db 16 | spec: 17 | containers: 18 | - env: 19 | - name: PGDATA 20 | value: /database 21 | - name: POSTGRES_DB 22 | value: concourse 23 | - name: POSTGRES_PASSWORD 24 | value: ops 25 | - name: POSTGRES_USER 26 | value: dev 27 | image: postgres:9.5 28 | name: concourse-db 29 | resources: {} 30 | restartPolicy: Always 31 | status: {} 32 | -------------------------------------------------------------------------------- /concourse-worker-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | service: concourse-worker 7 | name: concourse-worker 8 | spec: 9 | replicas: 1 10 | strategy: 11 | type: Recreate 12 | template: 13 | metadata: 14 | creationTimestamp: null 15 | labels: 16 | service: concourse-worker 17 | spec: 18 | containers: 19 | - args: 20 | - worker 21 | env: 22 | - name: CONCOURSE_TSA_HOST 23 | value: concourse-web 24 | image: concourse/concourse 25 | name: concourse-worker 26 | resources: {} 27 | securityContext: 28 | privileged: true 29 | volumeMounts: 30 | - mountPath: /concourse-keys 31 | name: cache-volume 32 | restartPolicy: Always 33 | volumes: 34 | - name: cache-volume 35 | secret: 36 | secretName: concourse-worker-keys 37 | status: {} 38 | -------------------------------------------------------------------------------- /pipeline/pipeline/pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | resources: 3 | - name: tic-toc 4 | type: time 5 | source: {interval: 30m} 6 | 7 | jobs: 8 | - name: hello-world 9 | plan: 10 | - get: tic-toc 11 | trigger: true 12 | - task: say-hello 13 | config: 14 | platform: linux 15 | image_resource: 16 | type: docker-image 17 | source: {repository: ubuntu} 18 | run: 19 | path: echo 20 | args: ["Hello, world!"] 21 | 22 | - name: do-some-cool-stuff 23 | plan: 24 | - get: tic-toc 25 | trigger: true 26 | passed: [hello-world] 27 | - task: lets-do-it 28 | config: 29 | platform: linux 30 | image_resource: 31 | type: docker-image 32 | source: {repository: ubuntu} 33 | run: 34 | # path: echo 35 | # args: ["| for i in {1..5}; do printf "ohh yeah $i \n" ; done"] 36 | path: bash 37 | args: 38 | # - -exc 39 | - -ec 40 | - | 41 | whoami 42 | env 43 | find . 44 | echo -e "lets run a for loop in" "\xE2\x9C\x88" 45 | for i in {1..25}; do printf "ohh yeah, loop run the $i time **** $(date) \n" ; done 46 | echo -e "thanks for your attention" "\xF0\x9F\xA4\x93" 47 | -------------------------------------------------------------------------------- /concourse-web-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | service: concourse-web 6 | name: concourse-web 7 | spec: 8 | replicas: 1 9 | strategy: 10 | type: Recreate 11 | template: 12 | metadata: 13 | creationTimestamp: null 14 | labels: 15 | service: concourse-web 16 | spec: 17 | containers: 18 | - args: 19 | - web 20 | env: 21 | - name: CONCOURSE_BASIC_AUTH_PASSWORD 22 | value: changeme 23 | - name: CONCOURSE_BASIC_AUTH_USERNAME 24 | value: concourse 25 | - name: CONCOURSE_EXTERNAL_URL 26 | value: http://${kubernetes_node_public_ip} 27 | - name: CONCOURSE_POSTGRES_DATABASE 28 | value: concourse 29 | - name: CONCOURSE_POSTGRES_HOST 30 | value: concourse-db 31 | - name: CONCOURSE_POSTGRES_PASSWORD 32 | value: ops 33 | - name: CONCOURSE_POSTGRES_USER 34 | value: dev 35 | image: concourse/concourse 36 | name: concourse-web 37 | ports: 38 | - containerPort: 8080 39 | resources: {} 40 | # restartPolicy: Always 41 | volumeMounts: 42 | - mountPath: /concourse-keys 43 | name: cache-volume 44 | volumes: 45 | - name: cache-volume 46 | secret: 47 | secretName: concourse-web-keys 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The missing kubernetes deployment for Concourse-Ci 2 | 3 | ## Goal 4 | This project was build to bring Concourse-Ci to IBM Cloud Container Service, which is based on kubernetes. 5 | If someone else has the need to deploy Concourse-Ci to kubernetes he/she should also benefit from this project. 6 | 7 | ## Pre Requirements 8 | The only Requirements to follow all this steps is to have running kubernetes cluster on IBM Bluemix Containers. 9 | How to do this, is described on https://console.bluemix.net/containers-kubernetes/launch?env_id=ibm:yp:eu-de 10 | The second requirement is that you have basic knowledge about kubernetes. 11 | 12 | ## Install 13 | 14 | 1. Grab the project 15 | 16 | ```shell 17 | git clone git@github.com:idev4u/concourse-ci-kube.git 18 | cd concourse-ci-kube 19 | ``` 20 | 2. As described in the [Concourse Documentation](http://concourse.ci/binaries.html) generate the keys for TSA and ATC 21 | 22 | ``` 23 | mkdir -p keys/web keys/worker 24 | 25 | ssh-keygen -t rsa -f ./keys/web/tsa_host_key -N '' 26 | ssh-keygen -t rsa -f ./keys/web/session_signing_key -N '' 27 | 28 | ssh-keygen -t rsa -f ./keys/worker/worker_key -N '' 29 | 30 | cp ./keys/worker/worker_key.pub ./keys/web/authorized_worker_keys 31 | cp ./keys/web/tsa_host_key.pub ./keys/worker 32 | ``` 33 | 34 | 3. Generate the secrets volume for your deployments 35 | 36 | This generate the secret volume for the *web* deployment 37 | ``` 38 | $ kubectl create secret generic concourse-web-keys \ 39 | --from-file=./keys/web/authorized_worker_keys \ 40 | --from-file=./keys/web/session_signing_key \ 41 | --from-file=./keys/web/session_signing_key.pub \ 42 | --from-file=./keys/web/tsa_host_key \ 43 | --from-file=./keys/web/tsa_host_key.pub 44 | ``` 45 | If you would verify the generated secrets volume, use this command. 46 | ```shell 47 | kubectl get secret concourse-web-keys -o yaml 48 | ``` 49 | 50 | Here is command that generate the secret volume for the *worker* deployment 51 | ``` 52 | $ kubectl create secret generic concourse-worker-keys \ 53 | --from-file=./keys/worker/tsa_host_key.pub \ 54 | --from-file=./keys/worker/worker_key \ 55 | --from-file=./keys/worker/worker_key.pub 56 | ``` 57 | And here as well the verify command. 58 | ```shell 59 | kubectl get secret concourse-worker-keys -o yaml 60 | ``` 61 | 62 | 4. Deploy the all the 3 components 63 | 64 | This command will deploy the database for your Concourse-Ci 65 | ```shell 66 | kubectl apply -f concourse-db-deployment.yaml && kubectl apply -f concourse-db-service.yaml 67 | ``` 68 | 69 | ```console 70 | deployment "concourse-db" created 71 | service "concourse-db" created 72 | ``` 73 | Before you deploy the Web UI, change the value of the external IP in the *concourse-web-deployment.yaml* file 74 | 75 | ``` 76 | - name: CONCOURSE_EXTERNAL_URL 77 | value: ${kubernetes_node_public_ip} 78 | ``` 79 | This command will deploy the WebUI of your Concourse-Ci 80 | ```shell 81 | kubectl apply -f concourse-web-deployment.yaml && kubectl apply -f concourse-web-service.yaml 82 | ``` 83 | 84 | ```console 85 | deployment "concourse-web" created 86 | service "concourse-web" created 87 | ``` 88 | This command will deploy one worker for your Concourse-Ci 89 | ``` 90 | bash$ kubectl apply -f concourse-worker-deployment.yaml && kubectl apply -f concourse-worker-service.yaml 91 | ``` 92 | 93 | ```console 94 | deployment "concourse-worker" created 95 | service "concourse-worker" created 96 | ``` 97 | 98 | ## Concourse Pipeline 99 | 100 | After the Concourse-Ci deployment is succesfully done, you can login the frist time into Concourse-Ci. Open the url `http://${kubernetes_node_public_ip}:32080` in your favorite browser and login with user __concourse__ and the password __changeme__. If you have changed this values in the deployment manifests, use yours. If this works and you have download the tool fly you can push your first pipeline. 101 | 102 | ```shell 103 | fly -t kube login -c ${kubernetes_node_public_ip} 104 | fly -t kube set-pipeline -p kube-pipe -c pipeline/pipeline.yml 105 | fly -t kube expose-pipeline -p kube-pipe 106 | ``` 107 | 108 | ## Some useful command to be succesful 109 | 110 | ### public IP of your node 111 | How did you find the public IP of your kubernetes node on the Bluemix Container platform? This is the command for getting this information. 112 | 113 | ```sh 114 | bx cs workers concourse-ci 115 | ``` 116 | ```console 117 | ID Public IP Private IP Machine Type State Status 118 | kube-par01-pa747d8ee7d506411aba3f992fc3d3c7a1-w1 x.x.x.x 10.x.x.x free normal Ready 119 | ``` 120 | ### kube context 121 | 122 | If you are not sure, that you aim on the correct context, this command helps you. 123 | ```shell 124 | kubectl config current-context 125 | ``` 126 | ```console 127 | concourse-ci 128 | ``` 129 | 130 | This command provides an overview of your pods you should have 3! 131 | ```shell 132 | kubectl get pods -o wide 133 | ``` 134 | ```console 135 | NAME READY STATUS RESTARTS AGE IP NODE 136 | concourse-db-59888000-1fcv0 1/1 Running 0 6h 172.x.x.x 10.x.x.a 137 | concourse-web-2821356835-npkvb 1/1 Running 0 5h 172.x.x.x 10.x.x.a 138 | concourse-worker-1074565060-nkrm9 1/1 Running 0 13m 172.x.x.x 10.x.x.a 139 | ``` 140 | 141 | This command provides an overview of your service you should also have 3! 142 | ```shell 143 | bash$ kubectl get svc -o wide 144 | ``` 145 | ```console 146 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR 147 | concourse-db None 55555/TCP 28d service=concourse-db 148 | concourse-web None 8080:32080/TCP 10m service=concourse-web 149 | concourse-worker None 55555/TCP 12m service=concourse-worker 150 | ``` 151 | 152 | ## Troubleshooting 153 | 154 | ### TSA Connection 155 | *Problemdescription:* 156 | 157 | I had a problems with the tsa connection from inside of the worker container. 158 | 159 | *Solution:* 160 | I fixed it with 161 | replaceing the service selector name with the endpoint ip. 162 | 163 | Getting the enpoint of the service `concourse-web` 164 | 165 | ``` 166 | kubectl get endpoints | grep web 167 | concourse-web 1.1.1.80:8080 17h 168 | ``` 169 | and here the area which is have to change concourse-worker-deployment.yaml 170 | 171 | ```yml 172 | ... 173 | # use the endpoint ip, because the dns lookup point to the cluster ip and this ip is not reachable from inside the container 174 | # value: concourse-web 175 | value: 1.1.1.80 176 | ... 177 | ``` 178 | --------------------------------------------------------------------------------