github.com/abayer/test-infra@v0.0.5/prow/getting_started.md (about)

     1  # How to turn up a new cluster
     2  
     3  Prow should run anywhere that Kubernetes runs. Here are the steps required to
     4  set up a basic prow cluster on [GKE](https://cloud.google.com/container-engine/).
     5  Prow will work on any Kubernetes cluster, so feel free to turn up a cluster
     6  some other way and skip the first step. You can set up a project on GCP using
     7  the [cloud console](https://console.cloud.google.com/).
     8  
     9  ## Create the cluster
    10  
    11  I'm assuming that `PROJECT` and `ZONE` environment variables are set.
    12  
    13  ```sh
    14  export PROJECT=your-project
    15  export ZONE=us-west1-a
    16  ```
    17  
    18  Run the following to create the cluster. This will also set up `kubectl` to
    19  point to the new cluster.
    20  
    21  ```sh
    22  gcloud container --project "${PROJECT}" clusters create prow \
    23    --zone "${ZONE}" --machine-type n1-standard-4 --num-nodes 2
    24  ```
    25  
    26  ## Create cluster role bindings
    27  As of 1.8 Kubernetes uses [Role-Based Access Control (“RBAC”)](https://kubernetes.io/docs/admin/authorization/rbac/) to drive authorization decisions, allowing `cluster-admin` to dynamically configure policies.
    28  To create cluster resources you need to grant a user `cluster-admin` role in all namespaces for the cluster.
    29  
    30  For Prow on GCP, you can use the following command.
    31  ```sh
    32  kubectl create clusterrolebinding cluster-admin-binding \
    33    --clusterrole cluster-admin --user $(gcloud config get-value account)
    34  ```
    35  
    36  For Prow on other platforms, the following command will likely work.
    37  ```sh
    38  kubectl create clusterrolebinding cluster-admin-binding-"${USER}" \
    39    --clusterrole=cluster-admin --user="${USER}"
    40  ```
    41  On some platforms the `USER` variable may not map correctly to the user
    42  in-cluster. If you see an error of the following form, this is likely the case.
    43  
    44  ```console
    45  Error from server (Forbidden): error when creating
    46  "prow/cluster/starter.yaml": roles.rbac.authorization.k8s.io "<account>" is
    47  forbidden: attempt to grant extra privileges:
    48  [PolicyRule{Resources:["pods/log"], APIGroups:[""], Verbs:["get"]}
    49  PolicyRule{Resources:["prowjobs"], APIGroups:["prow.k8s.io"], Verbs:["get"]}
    50  APIGroups:["prow.k8s.io"], Verbs:["list"]}] user=&{<CLUSTER_USER>
    51  [system:authenticated] map[]}...
    52  ```
    53  
    54  Run the previous command substituting `USER` with `CLUSTER_USER` from the error
    55  message above to solve this issue.
    56  ```sh
    57  kubectl create clusterrolebinding cluster-admin-binding-"<CLUSTER_USER>" \
    58    --clusterrole=cluster-admin --user="<CLUSTER_USER>"
    59  ```
    60  
    61  There are [relevant docs on Kubernetes Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authentication-strategies) that may help if neither of the above work.
    62  
    63  
    64  
    65  ## Create the GitHub secrets
    66  
    67  You will need two secrets to talk to GitHub. The `hmac-token` is the token that
    68  you give to GitHub for validating webhooks. Generate it using any reasonable
    69  randomness-generator, eg `openssl rand -hex 20`. The `oauth-token` is an OAuth2 token
    70  that has read and write access to the bot account. Generate it from the
    71  [account's settings -> Personal access tokens -> Generate new token][1].
    72  
    73  ```sh
    74  kubectl create secret generic hmac-token --from-file=hmac=/path/to/hook/secret
    75  kubectl create secret generic oauth-token --from-file=oauth=/path/to/oauth/secret
    76  ```
    77  
    78  #### Bot account
    79  
    80  The bot account used by prow must be granted owner level access to the Github
    81  orgs that prow will operate on. Note that events triggered by this account are
    82  ignored by some prow plugins. It is prudent to use a different bot account for
    83  other Github automation that prow should interact with to prevent events from
    84  being ignored unjustly.
    85  
    86  ## Run the prow components in the cluster
    87  
    88  Run the following command to start up a basic set of prow components.
    89  
    90  ```sh
    91  kubectl apply -f cluster/starter.yaml
    92  ```
    93  
    94  After a moment, the cluster components will be running.
    95  
    96  ```console
    97  $ kubectl get deployments
    98  NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    99  deck         2         2         2            2           1m
   100  hook         2         2         2            2           1m
   101  horologium   1         1         1            1           1m
   102  plank        1         1         1            1           1m
   103  sinker       1         1         1            1           1m
   104  ```
   105  
   106  Find out your external address. It might take a couple minutes for the IP to
   107  show up.
   108  
   109  ```console
   110  $ kubectl get ingress ing
   111  NAME      HOSTS     ADDRESS          PORTS     AGE
   112  ing       *         an.ip.addr.ess   80        3m
   113  ```
   114  
   115  Go to that address in a web browser and verify that the "echo-test" job has a
   116  green check-mark next to it. At this point you have a prow cluster that is ready
   117  to start receiving GitHub events!
   118  
   119  ## Add the webhook to GitHub
   120  
   121  On the GitHub repo you would like to use, go to Settings -> Webhooks -> Add
   122  webhook. You can also add org-level webhooks.
   123  
   124  Set the payload URL to `http://<IP-FROM-INGRESS>/hook`, the content type to
   125  `application/json`, the secret to your HMAC secret, and ask it to send everything.
   126  After you've created your webhook, GitHub will indicate that it successfully
   127  sent an event by putting a green checkmark under "Recent Deliveries."
   128  
   129  # Next steps
   130  
   131  ## Enable some plugins by modifying `plugins.yaml`
   132  
   133  Create a file called `plugins.yaml` and add the following to it:
   134  
   135  ```yaml
   136  plugins:
   137    YOUR_ORG/YOUR_REPO:
   138    - size
   139  ```
   140  
   141  Replace `YOUR_ORG/YOUR_REPO:` with the appropriate values. If you want, you can
   142  instead just say `YOUR_ORG:` and the plugin will run for every repo in the org.
   143  
   144  Run the following to test the file, replacing the path as necessary:
   145  
   146  ```sh
   147  bazel run //prow/cmd/config -- --plugin-config=path/to/plugins.yaml
   148  ```
   149  
   150  There should be no errors. You can run this as a part of your presubmit testing
   151  so that any errors are caught before you try to update.
   152  
   153  Now run the following to update the configmap, replacing the path as necessary:
   154  
   155  ```sh
   156  kubectl create configmap plugins \
   157    --from-file=plugins.yaml=path/to/plugins.yaml --dry-run -o yaml \
   158    | kubectl replace configmap plugins -f -
   159  ```
   160  
   161  We added a make rule to do this for us:
   162  
   163  ```Make
   164  get-cluster-credentials:
   165      gcloud container clusters get-credentials "$(CLUSTER)" --project="$(PROJECT)" --zone="$(ZONE)"
   166  
   167  update-plugins: get-cluster-credentials
   168      kubectl create configmap plugins --from-file=plugins.yaml=plugins.yaml --dry-run -o yaml | kubectl replace configmap plugins -f -
   169  ```
   170  
   171  Now when you open a PR, it will automatically be labelled with a `size/*`
   172  label. When you make a change to the plugin config and push it with `make
   173  update-plugins`, you do not need to redeploy any of your cluster components.
   174  They will pick up the change within a few minutes.
   175  
   176  ## Add more jobs by modifying `config.yaml`
   177  
   178  Create a file called `config.yaml`, and add the following to it:
   179  
   180  ```yaml
   181  periodics:
   182  - interval: 10m
   183    agent: kubernetes
   184    name: echo-test
   185    spec:
   186      containers:
   187      - image: alpine
   188        command: ["/bin/date"]
   189  postsubmits:
   190    YOUR_ORG/YOUR_REPO:
   191    - name: test-postsubmit
   192      agent: kubernetes
   193      spec:
   194        containers:
   195        - image: alpine
   196          command: ["/bin/printenv"]
   197  presubmits:
   198    YOUR_ORG/YOUR_REPO:
   199    - name: test-presubmit
   200      trigger: "(?m)^/test this"
   201      rerun_command: "/test this"
   202      context: test-presubmit
   203      always_run: true
   204      skip_report: true
   205      agent: kubernetes
   206      spec:
   207        containers:
   208        - image: alpine
   209          command: ["/bin/printenv"]
   210  ```
   211  
   212  Run the following to test the file, replacing the path as necessary:
   213  
   214  ```sh
   215  bazel run //prow/cmd/config -- --config-path=path/to/config.yaml
   216  ```
   217  
   218  Now run the following to update the configmap.
   219  
   220  ```sh
   221  kubectl create configmap config \
   222    --from-file=config.yaml=path/to/config.yaml --dry-run -o yaml | kubectl replace configmap config -f -
   223  ```
   224  
   225  We use a make rule:
   226  
   227  ```Make
   228  update-config: get-cluster-credentials
   229      kubectl create configmap config --from-file=config.yaml=config.yaml --dry-run -o yaml | kubectl replace configmap config -f -
   230  ```
   231  
   232  Presubmits and postsubmits are triggered by the `trigger` plugin. Be sure to
   233  enable that plugin by adding it to the list you created in the last section.
   234  
   235  Now when you open a PR it will automatically run the presubmit that you added
   236  to this file. You can see it on your prow dashboard. Once you are happy that it
   237  is stable, switch `skip_report` to `false`. Then, it will post a status on the
   238  PR. When you make a change to the config and push it with `make update-config`,
   239  you do not need to redeploy any of your cluster components. They will pick up
   240  the change within a few minutes.
   241  
   242  When you push a new change, the postsubmit job will run.
   243  
   244  For more information on the job environment, see [How to add new jobs][2].
   245  
   246  ## Run test pods in a different namespace
   247  
   248  You may choose to keep prowjobs or run tests in a different namespace. First
   249  create the namespace by `kubectl create -f`ing this:
   250  
   251  ```yaml
   252  apiVersion: v1
   253  kind: Namespace
   254  metadata:
   255    name: prow
   256  ```
   257  
   258  Now, in `config.yaml`, set `prowjob_namespace` or `pod_namespace` to the
   259  name from the YAML file. You can then use RBAC roles to limit what test pods
   260  can do.
   261  
   262  
   263  ## Run test pods in different clusters
   264  
   265  You may choose to run test pods in a separate cluster entirely. Create a secret
   266  containing a `{"cluster-name": {cluster-details}}` map like this:
   267  
   268  ```yaml
   269  default:
   270    endpoint: https://<master-ip>
   271    clientCertificate: <base64-encoded cert>
   272    clientKey: <base64-encoded key>
   273    clusterCaCertificate: <base64-encoded cert>
   274  other:
   275    endpoint: https://<master-ip>
   276    clientCertificate: <base64-encoded cert>
   277    clientKey: <base64-encoded key>
   278    clusterCaCertificate: <base64-encoded cert>
   279  ```
   280  
   281  Use [mkbuild-cluster][5] to determine these values:
   282  ```sh
   283  bazel run //prow/cmd/mkbuild-cluster -- \
   284    --project=P --zone=Z --cluster=C \
   285    --alias=A \
   286    --print-entry | tee cluster.yaml
   287  kubectl create secret generic build-cluster --from-file=cluster.yaml
   288  ```
   289  
   290  Mount this secret into the prow components that need it and set
   291  the `--build-cluster` flag to the location you mount it at. For instance, you
   292  will need to merge the following into the plank deployment:
   293  
   294  ```yaml
   295  spec:
   296    containers:
   297    - name: plank
   298      args:
   299      - --build-cluster=/etc/foo/cluster.yaml # basename matches --from-file key
   300      volumeMounts:
   301      - mountPath: /etc/foo
   302        name: cluster
   303        readOnly: true
   304    volumes:
   305    - name: cluster
   306      secret:
   307        defaultMode: 420
   308        secretName: build-cluster # example above contains a cluster.yaml key
   309  ```
   310  
   311  Configure jobs to use the non-default cluster with the `cluster:` field.
   312  The above example `cluster.yaml` defines two clusters: `default` and `other` to schedule jobs, which we can use as follows:
   313  ```yaml
   314  periodics:
   315  - name: cluster-unspecified
   316    # cluster: 
   317    interval: 10m
   318    agent: kubernetes
   319    spec:
   320      containers:
   321      - image: alpine
   322        command: ["/bin/date"]
   323  - name: cluster-default
   324    cluster: default
   325    interval: 10m
   326    agent: kubernetes
   327    spec:
   328      containers:
   329      - image: alpine
   330        command: ["/bin/date"]
   331  - name: cluster-other
   332    cluster: other
   333    interval: 10m
   334    agent: kubernetes
   335    spec:
   336      containers:
   337      - image: alpine
   338        command: ["/bin/date"]
   339  ```
   340  
   341  This results in:
   342  * The `cluster-unspecified` and `default-cluster` jobs run in the `default` cluster.
   343  * The `cluster-other` job runs in the `other` cluster.
   344  
   345  See [mkbuild-cluster][5] for more details about how to create/update `cluster.yaml`.
   346  
   347  ## Configure SSL
   348  
   349  Use [kube-lego][3] for automatic LetsEncrypt integration. If you
   350  already have a cert then follow the [official docs][4] to set up HTTPS
   351  termination. Promote your ingress IP to static IP. On GKE, run:
   352  
   353  ```sh
   354  gcloud compute addresses create [ADDRESS_NAME] --addresses [IP_ADDRESS] --region [REGION]
   355  ```
   356  
   357  Point the DNS record for your domain to point at that ingress IP. The convention
   358  for naming is `prow.org.io`, but of course that's not a requirement.
   359  
   360  Then, install kube-lego as described in its readme. You don't need to run it in
   361  a separate namespace.
   362  
   363  [1]: https://github.com/settings/tokens
   364  [2]: ./README.md##how-to-add-new-jobs
   365  [3]: https://github.com/jetstack/kube-lego
   366  [4]: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls
   367  [5]: /prow/cmd/mkbuild-cluster/