Why projects
On the kubeadm lab you were cluster admin and made namespaces whenever you liked. On a shared OpenShift cluster hundreds of developers need their own namespaces - without anyone giving them cluster-wide rights. Projects are how that works, and they also decide which UID your pods will run as.
What you need to know already: namespaces (15.26); RBAC: Role, ClusterRole, RoleBinding, and the built-in view / edit / admin roles (17.30); ServiceAccounts (17.33); ResourceQuota and LimitRange (17.9); NetworkPolicy (16.29); Pod Security Admission labels (17.39); logging in with oc (30.2).
A Project is a namespace with a front door
Kubernetes has namespaces. OpenShift has namespaces too - and Projects, which are the same objects seen through a second API (project.openshift.io). Two things make them different in practice:
- Who can create them. Creating a namespace needs cluster-level rights. Creating a project goes through a ProjectRequest, which any user in the
self-provisionerrole may make (by default: every OAuth user). The API server then creates the namespace on your behalf and makes you its admin. - What you can see.
oc get projectslists only the projects you have a role in.oc get namespacesas a normal user is simply forbidden.
Making one
oc new-project NAME sends the ProjectRequest. --display-name is a human-friendly title shown in the console and in oc projects; --description is free text. Neither changes the name itself:
$ oc new-project shop --display-name="Shop (dev)" --description="the web shop, dev"
Now using project "shop" on server "https://api.ocp.lab:6443".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.43 -- /agnhost serve-hostname
oc new-project also switched your context to it (shop/api-ocp-lab:6443/developer), so every following command runs in shop unless you pass -n. (The two example commands it suggests are just hints; ignore them.) Common failures - the first says the name must be lowercase letters, digits and - (an "RFC 1123 label", the same rule as DNS names):
$ oc new-project Shop
The ProjectRequest "Shop" is invalid: metadata.name: Invalid value: "Shop": a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')
$ oc new-project openshift-shop
Error from server (Forbidden): cannot request a project starting with "openshift-"
$ oc new-project shop
Error from server (AlreadyExists): project.project.openshift.io "shop" already exists
The last one also happens when someone else owns a project called shop that you cannot see. Project names are cluster-wide; many companies enforce a prefix (teamname-app-env) in the project template for that reason.
On many enterprise clusters self-provisioning is switched off (an admin removes the self-provisioner ClusterRole from the group of all logged-in users with oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth) and projects are requested through a ticket or a GitOps repo (26.1). Then you get:
Error from server (Forbidden): You may not request a new project via this API.
What a project comes with
-o yaml prints the whole object, as in 15.38:
$ oc get project shop -o yaml
apiVersion: project.openshift.io/v1
kind: Project
metadata:
annotations:
openshift.io/description: the web shop, dev
openshift.io/display-name: Shop (dev)
openshift.io/requester: developer
openshift.io/sa.scc.mcs: s0:c27,c14
openshift.io/sa.scc.supplemental-groups: 1000650000/10000
openshift.io/sa.scc.uid-range: 1000650000/10000
labels:
kubernetes.io/metadata.name: shop
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
name: shop
spec:
finalizers:
- kubernetes
status:
phase: Active
Line by line:
openshift.io/requester- who asked for it.openshift.io/sa.scc.uid-range: 1000650000/10000- this project's block of 10,000 UIDs, starting at 1000650000. Every project gets a different block. Pods admitted byrestricted-v2run as the first UID of the block. That is how two teams' pods never share a UID on the same node.openshift.io/sa.scc.supplemental-groups- the same idea for group IDs; the first one becomes the pod'sfsGroup(the group that owns the pod's volumes, 17.37).openshift.io/sa.scc.mcs- SELinux is a second permission system in the kernel, on top of the file permissions of 4.5: every process and file carries a label, and the kernel checks the labels too (Ubuntu uses AppArmor for the same job). MCS categories (s0:c27,c14) are a per-project tag in that label, so two projects' containers cannot read each other's files even if both somehow ran as the same UID.pod-security.kubernetes.io/warn|audit- Pod Security Admission labels, synced from the SCCs this project's ServiceAccounts can use (lesson 30.7). Enforcement stays with SCC; PSA only warns and audits.
Inside it:
$ oc get sa
NAME SECRETS AGE
builder 0 20s
default 0 20s
deployer 0 20s
$ oc get rolebindings
NAME ROLE AGE
admin ClusterRole/admin 20s
system:deployers ClusterRole/system:deployer 20s
system:image-builders ClusterRole/system:image-builder 20s
system:image-pullers ClusterRole/system:image-puller 20s
adminbinds you (the requester) to theadminClusterRole in this namespace. You can do anything inside it, including granting roles to others - but not change its quota or its SCC ranges.builderanddeployerare the ServiceAccounts that Builds (image builds run by the cluster, 30.18) and DeploymentConfigs (OpenShift's older Deployment, 30.21) run as.system:image-buildersletsbuilderpush to this project's image streams (the cluster's own record of image tags, 30.18).system:image-pullerslets every ServiceAccount of the project pull images from the project's image streams. To let project B pull A's images you add B's group:oc policy add-role-to-group system:image-puller system:serviceaccounts:b -n a.
Moving around
oc projects lists yours (* marks the current one); oc project NAME switches to one (it rewrites your kubeconfig context); oc project alone says where you are; -q (quiet) prints just the name, handy in scripts:
# shop-test and payments = the projects of the next mission
oc projects
You have access to the following projects and can switch between them with ' project <projectname>':
* shop - Shop (dev)
shop-test
Using project "shop" on server "https://api.ocp.lab:6443".
oc project shop-test
Now using project "shop-test" on server "https://api.ocp.lab:6443".
oc project
Using project "shop-test" on server "https://api.ocp.lab:6443".
oc project -q
shop-test
Asking for a project you cannot see:
$ oc project payments
error: You are not a member of project "payments".
Your projects are:
* shop
* shop-test
Note: that is the same message whether payments exists or not. Projects you are not a member of are invisible.
Sharing a project
You are admin in your project, so you manage its RBAC yourself:
$ oc policy add-role-to-user view alice -n shop
clusterrole.rbac.authorization.k8s.io/view added: "alice"
$ oc get rolebinding view -n shop -o wide
NAME ROLE AGE USERS GROUPS SERVICEACCOUNTS
view ClusterRole/view 9s alice
oc policy add-role-to-user ROLE USER creates (or extends) a RoleBinding in the current project (-n picks another one). -o wide adds the USERS / GROUPS / SERVICEACCOUNTS columns, so you see who the binding is for. The built-in roles are the Kubernetes ones - view, edit, admin - extended by OpenShift to cover Routes, Builds, ImageStreams and so on. Now alice sees shop in oc get projects and can read everything but Secrets. She still cannot change anything:
$ oc delete pod web-6d9f7c-abcde -n shop # as alice
Error from server (Forbidden): pods "web-6d9f7c-abcde" is forbidden: User "alice" cannot delete resource "pods" in API group "" in the namespace "shop"
Undo with oc policy remove-role-from-user view alice -n shop.
Deleting
oc delete project shop-test
project.project.openshift.io "shop-test" deleted
The namespace goes to Terminating and everything in it is deleted - the same as kubectl delete ns. There is no undo; on shared clusters this is why the admin role is not given lightly.
Admin side: the template and quotas
Cluster admins shape every new project through a project request template (oc adm create-bootstrap-project-template -o yaml prints the default; point projects.config.openshift.io/cluster .spec.projectRequestTemplate at your own). A typical bank template adds a ResourceQuota, a LimitRange, default NetworkPolicies (deny from other projects) and labels for cost centres. oc adm new-project bypasses the template and the requester binding - it is the admin's raw "make a namespace with ranges".
What you can now do
- Create, list, switch and delete projects, and read the errors you get on the way.
- Read a project's annotations: the UID range, the groups, the SELinux MCS level.
- Share a project with a colleague with
oc policy add-role-to-user.