## Task 61 There are some applications that need to be deployed on Kubernetes cluster and these apps have some pre-requisites where some configurations need to be changed before deploying the app container. Some of these changes cannot be made inside the images so the DevOps team has come up with a solution to use init containers to perform these tasks during deployment. Below is a sample scenario that the team is going to test first. Create a Deployment named as ic-deploy-xfusion. Configure spec as replicas should be 1, labels app should be ic-xfusion, template's metadata lables app should be the same ic-xfusion. The initContainers should be named as ic-msg-xfusion, use image fedora with latest tag and use command '/bin/bash', '-c' and 'echo Init Done - Welcome to xFusionCorp Industries > /ic/blog'. The volume mount should be named as ic-volume-xfusion and mount path should be /ic. Main container should be named as ic-main-xfusion, use image fedora with latest tag and use command '/bin/bash', '-c' and 'while true; do cat /ic/blog; sleep 5; done'. The volume mount should be named as ic-volume-xfusion and mount path should be /ic. Volume to be named as ic-volume-xfusion and it should be an emptyDir type. Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster. ### Solution # Create ic-deploy-xfusion deployment ```bash kubectl apply -f - <<'EOF' apiVersion: apps/v1 kind: Deployment metadata: name: ic-deploy-xfusion labels: app: ic-xfusion spec: replicas: 1 selector: matchLabels: app: ic-xfusion template: metadata: labels: app: ic-xfusion spec: initContainers: - name: ic-msg-xfusion image: fedora:latest command: ["/bin/bash", "-c", "echo Init Done - Welcome to xFusionCorp Industries > /ic/blog"] volumeMounts: - name: ic-volume-xfusion mountPath: /ic containers: - name: ic-main-xfusion image: fedora:latest command: ["/bin/bash", "-c", "while true; do cat /ic/blog; sleep 5; done"] volumeMounts: - name: ic-volume-xfusion mountPath: /ic volumes: - name: ic-volume-xfusion emptyDir: {} EOF ``` ## Verify ```bash kubectl get deployment ic-deploy-xfusion kubectl get pods -l app=ic-xfusion kubectl logs -l app=ic-xfusion -c ic-main-xfusion ``` Want: deployment `1/1` ready, pod Running, and the main container's logs printing `Init Done - Welcome to xFusionCorp Industries` every 5s. ## Task 62 The Nautilus DevOps team is working to deploy some tools in Kubernetes cluster. Some of the tools are licence based so that licence information needs to be stored securely within Kubernetes cluster. Therefore, the team wants to utilize Kubernetes secrets to store those secrets. Below you can find more details about the requirements: We already have a secret key file ecommerce.txt under the /opt/ directory. Create a generic secret named ecommerce, it should contain the password/license-number present in ecommerce.txt file. Also create a pod named secret-nautilus. Configure pod's spec as container name should be secret-container-nautilus, image should be debian with latest tag (remember to mention the tag with image). Use sleep command for container so that it remains in running state. Consume the created secret and mount it under /opt/games within the container. To verify you can exec into the container secret-container-nautilus, to check the secret key under the mounted path /opt/games. Before hitting the Check button please make sure pod/pods are in running state, also validation can take some time to complete so keep patience. Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster. ### Solution # Create secret + pod that mounts it ## Step 1 — create the generic secret from the file ```bash kubectl create secret generic ecommerce --from-file=/opt/ecommerce.txt ``` ## Step 2 — create the pod mounting the secret at /opt/games ```bash kubectl apply -f - <<'EOF' apiVersion: v1 kind: Pod metadata: name: secret-nautilus spec: containers: - name: secret-container-nautilus image: debian:latest command: ["sleep", "infinity"] volumeMounts: - name: secret-volume mountPath: /opt/games volumes: - name: secret-volume secret: secretName: ecommerce EOF ``` ## Verify ```bash kubectl get secret ecommerce kubectl get pod secret-nautilus kubectl exec secret-nautilus -- ls -l /opt/games kubectl exec secret-nautilus -- cat /opt/games/ecommerce.txt ``` Want: secret `ecommerce` exists, pod `Running`, and `/opt/games/ecommerce.txt` present with the license content inside the container. ## Task 63 There is an iron gallery app that the Nautilus DevOps team was developing. They have recently customized the app and are going to deploy the same on the Kubernetes cluster. Below you can find more details: Create a namespace iron-namespace-nautilus Create a deployment iron-gallery-deployment-nautilus for iron gallery under the same namespace you created. :- Labels run should be iron-gallery. :- Replicas count should be 1. :- Selector's matchLabels run should be iron-gallery. :- Template labels run should be iron-gallery under metadata. :- The container should be named as iron-gallery-container-nautilus, use kodekloud/irongallery:2.0 image ( use exact image name / tag ). :- Resources limits for memory should be 100Mi and for CPU should be 50m. :- First volumeMount name should be config, its mountPath should be /usr/share/nginx/html/data. :- Second volumeMount name should be images, its mountPath should be /usr/share/nginx/html/uploads. :- First volume name should be config and give it emptyDir and second volume name should be images, also give it emptyDir. Create a deployment iron-db-deployment-nautilus for iron db under the same namespace. :- Labels db should be mariadb. :- Replicas count should be 1. :- Selector's matchLabels db should be mariadb. :- Template labels db should be mariadb under metadata. :- The container name should be iron-db-container-nautilus, use kodekloud/irondb:2.0 image ( use exact image name / tag ). :- Define environment, set MYSQL_DATABASE its value should be database_apache, set MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD value should be with some complex passwords for DB connections, and MYSQL_USER value should be any custom user ( except root ). :- Volume mount name should be db and its mountPath should be /var/lib/mysql. Volume name should be db and give it an emptyDir. Create a service for iron db which should be named iron-db-service-nautilus under the same namespace. Configure spec as selector's db should be mariadb. Protocol should be TCP, port and targetPort should be 3306 and its type should be ClusterIP. Create a service for iron gallery which should be named iron-gallery-service-nautilus under the same namespace. Configure spec as selector's run should be iron-gallery. Protocol should be TCP, port and targetPort should be 80, nodePort should be 32678 and its type should be NodePort. Note: We don't need to make connection b/w database and front-end now, if the installation page is coming up it should be enough for now. The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster. ### Solution # Iron Gallery app — namespace, deployments, services ```bash kubectl apply -f - <<'EOF' apiVersion: v1 kind: Namespace metadata: name: iron-namespace-nautilus --- apiVersion: apps/v1 kind: Deployment metadata: name: iron-gallery-deployment-nautilus namespace: iron-namespace-nautilus labels: run: iron-gallery spec: replicas: 1 selector: matchLabels: run: iron-gallery template: metadata: labels: run: iron-gallery spec: containers: - name: iron-gallery-container-nautilus image: kodekloud/irongallery:2.0 resources: limits: memory: "100Mi" cpu: "50m" volumeMounts: - name: config mountPath: /usr/share/nginx/html/data - name: images mountPath: /usr/share/nginx/html/uploads volumes: - name: config emptyDir: {} - name: images emptyDir: {} --- apiVersion: apps/v1 kind: Deployment metadata: name: iron-db-deployment-nautilus namespace: iron-namespace-nautilus labels: db: mariadb spec: replicas: 1 selector: matchLabels: db: mariadb template: metadata: labels: db: mariadb spec: containers: - name: iron-db-container-nautilus image: kodekloud/irondb:2.0 env: - name: MYSQL_DATABASE value: "database_apache" - name: MYSQL_ROOT_PASSWORD value: "R00t_C0mpl3x_P@ss" - name: MYSQL_PASSWORD value: "Us3r_C0mpl3x_P@ss" - name: MYSQL_USER value: "iron_user" volumeMounts: - name: db mountPath: /var/lib/mysql volumes: - name: db emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: iron-db-service-nautilus namespace: iron-namespace-nautilus spec: type: ClusterIP selector: db: mariadb ports: - protocol: TCP port: 3306 targetPort: 3306 --- apiVersion: v1 kind: Service metadata: name: iron-gallery-service-nautilus namespace: iron-namespace-nautilus spec: type: NodePort selector: run: iron-gallery ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 32678 EOF ``` ## Verify ```bash kubectl get all -n iron-namespace-nautilus kubectl get pods -n iron-namespace-nautilus kubectl get svc -n iron-namespace-nautilus ``` Want: both deployments `1/1`, both pods Running, db service ClusterIP on 3306, gallery service NodePort on 32678. Then the iron gallery install page should load via the nodePort. ## Task 64 One of the DevOps engineers was trying to deploy a python app on Kubernetes cluster. Unfortunately, due to some mis-configuration, the application is not coming up. Please take a look into it and fix the issues. Application should be accessible on the specified nodePort. The deployment name is python-deployment-devops, its using poroko/flask-demo-app image. The deployment and service of this app is already deployed. nodePort should be 32345 and targetPort should be python flask app's default port. Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster. ### Solution ```bash kubectl set image deployment/python-deployment-devops python-container-devops=poroko/flask-demo-app kubectl patch svc python-service-devops --type=json -p='[ {"op":"replace","path":"/spec/ports/0/targetPort","value":5000}, {"op":"replace","path":"/spec/ports/0/nodePort","value":32345} ]' ``` ## Task 65 The Nautilus application development team observed some performance issues with one of the application that is deployed in Kubernetes cluster. After looking into number of factors, the team has suggested to use some in-memory caching utility for DB service. After number of discussions, they have decided to use Redis. Initially they would like to deploy Redis on kubernetes cluster for testing and later they will move it to production. Please find below more details about the task: Create a redis deployment with following parameters: Create a config map called my-redis-config having maxmemory 2mb in redis-config. Name of the deployment should be redis-deployment, it should use redis:alpine image and container name should be redis-container. Also make sure it has only 1 replica. The container should request for 1 CPU. Mount 2 volumes: a. An Empty directory volume called data at path /redis-master-data. b. A configmap volume called redis-config at path /redis-master. c. The container should expose the port 6379. Finally, redis-deployment should be up and running. ### Solution # Redis deployment with configmap ```bash kubectl apply -f - <<'EOF' apiVersion: v1 kind: ConfigMap metadata: name: my-redis-config data: redis-config: | maxmemory 2mb --- apiVersion: apps/v1 kind: Deployment metadata: name: redis-deployment labels: app: redis spec: replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis-container image: redis:alpine resources: requests: cpu: "1" ports: - containerPort: 6379 volumeMounts: - name: data mountPath: /redis-master-data - name: redis-config mountPath: /redis-master volumes: - name: data emptyDir: {} - name: redis-config configMap: name: my-redis-config EOF ``` ## Verify ```bash kubectl get configmap my-redis-config kubectl get deployment redis-deployment kubectl get pods -l app=redis kubectl describe pod -l app=redis | grep -A3 -i "requests\|mounts" ``` Want: configmap exists, deployment `1/1` ready, pod Running, CPU request 1, both volumes mounted. ## Task 66 A new MySQL server needs to be deployed on Kubernetes cluster. The Nautilus DevOps team was working on to gather the requirements. Recently they were able to finalize the requirements and shared them with the team members to start working on it. Below you can find the details: 1.) Create a PersistentVolume mysql-pv, its capacity should be 250Mi, set other parameters as per your preference. 2.) Create a PersistentVolumeClaim to request this PersistentVolume storage. Name it as mysql-pv-claim and request a 250Mi of storage. Set other parameters as per your preference. 3.) Create a deployment named mysql-deployment, use any mysql image as per your preference. Mount the PersistentVolume at mount path /var/lib/mysql. 4.) Create a NodePort type service named mysql and set nodePort to 30007. 5.) Create a secret named mysql-root-pass having a key pair value, where key is password and its value is YUIidhb667, create another secret named mysql-user-pass having some key pair values, where first key is username and its value is kodekloud_pop, second key is password and value is BruCStnMT5, create one more secret named mysql-db-url, key name is database and value is kodekloud_db10 6.) Define some environment variables within the container: a.) name: MYSQL_ROOT_PASSWORD, should pick value from secretKeyRef name: mysql-root-pass and key: password b.) name: MYSQL_DATABASE, should pick value from secretKeyRef name: mysql-db-url and key: database c.) name: MYSQL_USER, should pick value from secretKeyRef name: mysql-user-pass key key: username d.) name: MYSQL_PASSWORD, should pick value from secretKeyRef name: mysql-user-pass and key: password ### Solution # MySQL deployment with secrets, PV/PVC, service ```bash kubectl apply -f - <<'EOF' apiVersion: v1 kind: Secret metadata: name: mysql-root-pass type: Opaque stringData: password: YUIidhb667 --- apiVersion: v1 kind: Secret metadata: name: mysql-user-pass type: Opaque stringData: username: kodekloud_pop password: BruCStnMT5 --- apiVersion: v1 kind: Secret metadata: name: mysql-db-url type: Opaque stringData: database: kodekloud_db10 --- apiVersion: v1 kind: PersistentVolume metadata: name: mysql-pv spec: storageClassName: manual capacity: storage: 250Mi accessModes: - ReadWriteOnce hostPath: path: /mnt/mysql-data --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pv-claim spec: storageClassName: manual accessModes: - ReadWriteOnce resources: requests: storage: 250Mi --- apiVersion: apps/v1 kind: Deployment metadata: name: mysql-deployment labels: app: mysql spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-root-pass key: password - name: MYSQL_DATABASE valueFrom: secretKeyRef: name: mysql-db-url key: database - name: MYSQL_USER valueFrom: secretKeyRef: name: mysql-user-pass key: username - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: mysql-user-pass key: password volumeMounts: - name: mysql-storage mountPath: /var/lib/mysql volumes: - name: mysql-storage persistentVolumeClaim: claimName: mysql-pv-claim --- apiVersion: v1 kind: Service metadata: name: mysql spec: type: NodePort selector: app: mysql ports: - port: 3306 targetPort: 3306 nodePort: 30007 EOF ``` ## Verify ```bash kubectl get secrets kubectl get pv mysql-pv kubectl get pvc mysql-pv-claim kubectl get deployment mysql-deployment kubectl get pods -l app=mysql kubectl get svc mysql ``` Want: 3 secrets, PV+PVC `Bound`, deployment `1/1`, pod Running, service NodePort 30007. ## Task 67 The Nautilus Application development team has finished development of one of the applications and it is ready for deployment. It is a guestbook application that will be used to manage entries for guests/visitors. As per discussion with the DevOps team, they have finalized the infrastructure that will be deployed on Kubernetes cluster. Below you can find more details about it. BACK-END TIER Create a deployment named redis-master for Redis master. a.) Replicas count should be 1. b.) Container name should be master-redis-devops and it should use image redis. c.) Request resources as CPU should be 100m and Memory should be 100Mi. d.) Container port should be redis default port i.e 6379. Create a service named redis-master for Redis master. Port and targetPort should be Redis default port i.e 6379. Create another deployment named redis-slave for Redis slave. a.) Replicas count should be 2. b.) Container name should be slave-redis-devops and it should use gcr.io/google_samples/gb-redisslave:v3 image. c.) Requests resources as CPU should be 100m and Memory should be 100Mi. d.) Define an environment variable named GET_HOSTS_FROM and its value should be dns. e.) Container port should be Redis default port i.e 6379. Create another service named redis-slave. It should use Redis default port i.e 6379. Create another service named redis-follower. Port and targetPort should be Redis default port i.e 6379. Its selector app should be redis-slave. FRONT END TIER Create a deployment named frontend. a.) Replicas count should be 3. b.) Container name should be php-redis-devops and it should use gcr.io/google-samples/gb-frontend@sha256:a908df8486ff66f2c4daa0d3d8a2fa09846a1fc8efd65649c0109695c7c5cbff image. c.) Request resources as CPU should be 100m and Memory should be 100Mi. d.) Define an environment variable named as GET_HOSTS_FROM and its value should be dns. e.) Container port should be 80. Create a service named frontend. Its type should be NodePort, port should be 80 and its nodePort should be 30009. Finally, you can check the guestbook app by clicking on App button. You can use any labels as per your choice. ### Solution # Guestbook app — full stack ```bash kubectl apply -f - <<'EOF' # ===== BACK-END: redis-master ===== apiVersion: apps/v1 kind: Deployment metadata: name: redis-master labels: app: redis-master spec: replicas: 1 selector: matchLabels: app: redis-master template: metadata: labels: app: redis-master spec: containers: - name: master-redis-devops image: redis resources: requests: cpu: "100m" memory: "100Mi" ports: - containerPort: 6379 --- apiVersion: v1 kind: Service metadata: name: redis-master spec: selector: app: redis-master ports: - port: 6379 targetPort: 6379 --- # ===== BACK-END: redis-slave ===== apiVersion: apps/v1 kind: Deployment metadata: name: redis-slave labels: app: redis-slave spec: replicas: 2 selector: matchLabels: app: redis-slave template: metadata: labels: app: redis-slave spec: containers: - name: slave-redis-devops image: gcr.io/google_samples/gb-redisslave:v3 resources: requests: cpu: "100m" memory: "100Mi" env: - name: GET_HOSTS_FROM value: dns ports: - containerPort: 6379 --- apiVersion: v1 kind: Service metadata: name: redis-slave spec: selector: app: redis-slave ports: - port: 6379 targetPort: 6379 --- apiVersion: v1 kind: Service metadata: name: redis-follower spec: selector: app: redis-slave ports: - port: 6379 targetPort: 6379 --- # ===== FRONT-END ===== apiVersion: apps/v1 kind: Deployment metadata: name: frontend labels: app: frontend spec: replicas: 3 selector: matchLabels: app: frontend template: metadata: labels: app: frontend spec: containers: - name: php-redis-devops image: gcr.io/google-samples/gb-frontend@sha256:a908df8486ff66f2c4daa0d3d8a2fa09846a1fc8efd65649c0109695c7c5cbff resources: requests: cpu: "100m" memory: "100Mi" env: - name: GET_HOSTS_FROM value: dns ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: frontend spec: type: NodePort selector: app: frontend ports: - port: 80 targetPort: 80 nodePort: 30009 EOF ``` ## Verify ```bash kubectl get deployments kubectl get pods kubectl get svc kubectl get pods -o wide | grep -E "redis|frontend" ``` Want: redis-master `1/1`, redis-slave `2/2`, frontend `3/3`, all four services present, frontend NodePort 30009. Then the App button loads the guestbook. ## Task 68 The DevOps team at xFusionCorp Industries is initiating the setup of CI/CD pipelines and has decided to utilize Jenkins as their server. Execute the task according to the provided requirements: 1. Install Jenkins on the jenkins server using the apt utility only, and start it using the service command. If you face a timeout issue while starting the Jenkins service, first check the service status with service jenkins status Then review the logs in /var/log/jenkins/jenkins.log to identify the cause. 2. Jenkin's admin user name should be theadmin, password should be Adm!n321, full name should be Mariyam and email should be mariyam@jenkins.stratos.xfusioncorp.com. Note: 1. To access the jenkins server, connect from the jump host using the root user with the password S3curePass. 2. After Jenkins server installation, click the Jenkins button on the top bar to access the Jenkins UI and follow on-screen instructions to create an admin user. ### Solution # Install Jenkins on jenkins server + create admin user ## Access the server From the jump host, SSH in as root: ```bash ssh root@jenkins # password: S3curePass ``` --- ## Part 1 — Install Jenkins (CLI) ### Step 1: Install Java (Jenkins prerequisite) ```bash apt update apt install -y fontconfig openjdk-17-jre java -version apt update apt install -y openjdk-21-jre # make Java 21 the default (in case 17 is still selected) update-alternatives --config java ``` ### Step 2: Add the Jenkins apt repository + signing key ```bash wget -O /usr/share/keyrings/jenkins-keyring.asc \ https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \ "https://pkg.jenkins.io/debian-stable binary/" | \ tee /etc/apt/sources.list.d/jenkins.list > /dev/null ``` ### Step 3: Install Jenkins ```bash apt update apt install -y jenkins ``` ### Step 4: Start Jenkins using the service command ```bash service jenkins start service jenkins status ``` ### If you hit a startup timeout ```bash service jenkins status cat /var/log/jenkins/jenkins.log ``` The log identifies the cause — most commonly a missing/wrong Java version. Ensure `openjdk-17-jre` is installed and set as default (`update-alternatives --config java`), then restart: ```bash service jenkins restart ``` Jenkins can take 60–90s on first start; a first-attempt timeout doesn't always mean failure — re-check status after waiting. --- ## Part 2 — Create the admin user (Web UI) ### Step 1: Get the initial unlock password ```bash cat /var/lib/jenkins/secrets/initialAdminPassword ``` Copy the output. ### Step 2: Open the Jenkins UI Click the **Jenkins** button on the top bar. ### Step 3: Unlock Jenkins Paste the initial admin password from Step 1 → **Continue**. ### Step 4: Install plugins Choose **"Install suggested plugins"** and wait for completion. ### Step 5: Create the First Admin User Fill in exactly: | Field | Value | |-------|-------| | Username | `theadmin` | | Password | `Adm!n321` | | Full name | `Mariyam` | | Email | `mariyam@jenkins.stratos.xfusioncorp.com` | Click **Save and Continue** → **Save and Finish** → **Start using Jenkins**. --- ## Verify - `service jenkins status` shows Jenkins active/running. - You can log into the Jenkins UI as `theadmin` / `Adm!n321`. - The dashboard loads with `theadmin` as the logged-in user. --- ## Key points - **Java first** — Jenkins is a Java app; without a JRE it won't start (the exact timeout the task warns about). Java 17 is the safe LTS-compatible choice. - **Repo + keyring required** — Jenkins isn't in Ubuntu base repos; add `pkg.jenkins.io` with its signing key before `apt install jenkins`. - **`debian-stable`** = Jenkins LTS line (more stable than weekly). - **`service jenkins start`** per the task (not `systemctl`). - **`initialAdminPassword`** unlocks the first UI screen before you can create `theadmin`. - **Admin user is created via the web wizard**, not CLI — the four field values must be exact for the grader. - Take a screenshot of the finished admin-user setup / dashboard for review. ## Task 69 The Nautilus DevOps team has recently setup a Jenkins server, which they want to use for some CI/CD jobs. Before that they want to install some plugins which will be used in most of the jobs. Please find below more details about the task 1. Click on the Jenkins button on the top bar to access the Jenkins UI. Login using username admin and password Adm!n321. 2. Once logged in, install the Git and GitLab plugins. You may need to restart Jenkins to complete the plugin installation; if required, opt to Restart Jenkins when installation is complete and no jobs are running on the plugin installation/update page (Update Centre). Note: 1. After restarting Jenkins, wait for the login page to reappear before proceeding. 2. For tasks involving web UI changes, capture screenshots to share for review or consider using screen recording software like loom.com for documentation and sharing. ### Solution # Install Git + GitLab plugins in Jenkins ## Step 1 — Log in Click the **Jenkins** button on the top bar. Log in with: - Username: `admin` - Password: `Adm!n321` ## Step 2 — Navigate to Plugin Manager **Manage Jenkins** → **Plugins** (under System Configuration; older versions: **Manage Plugins**). ## Step 3 — Find and select the plugins Go to the **Available plugins** tab. In the search box, search and check each: - Search `Git` → check the **Git** plugin - Search `GitLab` → check the **GitLab** plugin ## Step 4 — Install Click **Install** (or **Download now and install after restart**). ## Step 5 — Restart Jenkins On the installation progress page, check the box: **"Restart Jenkins when installation is complete and no jobs are running"** Jenkins restarts. **Wait for the login page to reappear** before doing anything else. ## Step 6 — Verify After restart, log back in and check: **Manage Jenkins** → **Plugins** → **Installed plugins** tab → search `Git` and `GitLab` — both should be listed. ## Task 70 The Nautilus team is integrating Jenkins into their CI/CD pipelines. After setting up a new Jenkins server, they're now configuring user access for the development team, Follow these steps: 1. Click on the Jenkins button on the top bar to access the Jenkins UI. Login with username admin and password Adm!n321. 2. Create a jenkins user named rose with the password TmPcZjtRQx. Their full name should match Rose. 3. Utilize the Project-based Matrix Authorization Strategy to assign overall read permission to the rose user. 4. Remove all permissions for Anonymous users (if any) ensuring that the admin user retains overall Administer permissions. 5. For the existing job, grant rose user only read permissions, disregarding other permissions such as Agent, SCM etc. Note: 1. You may need to install plugins and restart Jenkins service. After plugins installation, select Restart Jenkins when installation is complete and no jobs are running on plugin installation/update page. 2. After restarting the Jenkins service, wait for the Jenkins login page to reappear before proceeding. Avoid clicking Finish immediately after restarting the service. 3. Capture screenshots of your configuration for review purposes. Consider using screen recording software like loom.com for documentation and sharing. ### Solution: # Configure Jenkins user access for rose ## Step 1 — Log in Click **Jenkins** button → login `admin` / `Adm!n321`. ## Step 2 — Install Matrix Authorization Strategy plugin (if not present) **Manage Jenkins → Plugins → Available plugins** → search **"Matrix Authorization Strategy"** → check it → **Download now and install after restart**. Wait for Jenkins to fully restart, wait for the **login page** to reappear, log back in. ## Step 3 — Create user rose **Manage Jenkins → Users → Create User**: - Username: `rose` - Password: `TmPcZjtRQx` - Full name: `Rose` - (email can be left blank or any value) Click **Create User**. ## Step 4 — Switch to Project-based Matrix Authorization Strategy **Manage Jenkins → Security** (or **Configure Global Security**): - Under **Authorization**, select **"Project-based Matrix Authorization Strategy"** - A permission matrix appears. ## Step 5 — Set global permissions In the matrix: - **Add user** `admin` → grant **Overall / Administer** (full row, or at minimum Administer). **Do this FIRST — critical.** - **Add user** `rose` → grant **Overall / Read** only. - **Anonymous** row → **uncheck ALL permissions** (remove everything). Click **Save**. ## Step 6 — Grant rose read-only on the existing job Go to the existing job → **Configure** → enable **"Enable project-based security"** (checkbox in the job config): - **Add user** `rose` - Grant **only Read** (under Job → Read). Leave Agent, SCM, Build, etc. **unchecked**. Click **Save**. ## Verify - `admin` retains Administer (you can still access everything). - `rose` can log in, sees the job (read), can't configure/build. - Anonymous has no permissions.