⌨️ Placeholder convention
Values inside angle brackets are examples that you must replace. Do not type the brackets themselves.
<server-ip>→ the server's actual address<container>→ a container name or ID<region>→ an AWS Region such asus-east-1
🧭 Know where you are
Before changing a system, confirm the current user, host, directory, and active tool context. Many lab errors come from running the right command on the wrong server.
whoami
hostname
pwd
⚠️ Destructive commands
Inspect targets before using recursive deletion, forced container cleanup, namespace-wide deletion, or EKS teardown. Cloud resources may also incur costs until deleted.
ls -la <target>
docker ps -a
kubectl get all
🐧 Linux, Bash, SSH, and system administration
Identity and system information
Confirm who you are, group membership, operating system, date, and recent command history.
date
whoami
groups $(whoami)
cat /etc/os-release
history
Use when: you have just entered a VM or EC2 instance.
Navigate and inspect directories
Move around the filesystem and include hidden files or detailed permissions when needed.
pwd
ls
ls -la
cd /path/to/project
cd ~
cd ..
Remember: ~ is your home directory and .. is the parent.
Create, copy, move, and remove
Use explicit paths and inspect them before recursive removal.
mkdir -p app/templates
touch app/app.py
cp source.txt backup.txt
mv old.txt archive/new.txt
rm file.txt
rm -rf old-directory
Tip: mv renames when source and destination are in the same directory.
Read and edit text files
Inspect a full file, sample its beginning or end, or edit interactively with Nano.
cat application.log
head -n 20 application.log
tail -n 20 application.log
nano configuration.yml
Nano: save with Ctrl+O, confirm with Enter, and exit with Ctrl+X.
Redirect and append output
One greater-than sign replaces a file; two append to the end.
echo "first line" > report.txt
echo "next line" >> report.txt
command > output.log 2> error.log
Use when: creating configuration, reports, or captured command output.
Search, find, count, and pipe
Connect small commands so each stage filters or summarises the previous result.
find ~ -name "*.txt"
grep -R "ERROR" .
grep "friends" file.txt | wc -l
cat access.log | grep " 500 " | head
Pipeline: | sends standard output into the next command.
Permissions and ownership
Control read, write, and execute permissions symbolically or numerically.
chmod u+x script.sh
chmod g-w report.txt
chmod 755 script.sh
sudo chown user:group report.txt
ls -l report.txt
755: owner can read/write/execute; group and others can read/execute.
Install packages
Use the package manager that matches the Linux distribution.
# Debian / Ubuntu
sudo apt update
sudo apt install tree unzip curl
# Fedora / RHEL / Amazon Linux
sudo yum install git -y
sudo dnf install nano -y
Use when: a required command reports “command not found”.
Services with systemd
Inspect, start, restart, enable, or stop long-running services.
sudo systemctl status sshd
sudo systemctl start sshd
sudo systemctl restart sshd
sudo systemctl enable sshd
sudo systemctl stop sshd
Enable vs start: enable affects future boots; start affects the current session.
Connect with SSH
Use port forwarding for a local VM or a private key for an EC2 instance.
ssh <vm-user>@127.0.0.1 -p 2222
chmod 400 devops_project_key.pem
ssh -i devops_project_key.pem ec2-user@<public-ip>
Check first: port 22 must be reachable and the SSH service must be running.
Bash script skeleton
Make repeated setup steps executable and stop the script when a command fails.
#!/usr/bin/env bash
set -euo pipefail
project_dir="${1:-my-project}"
mkdir -p "$project_dir"
echo "Created $project_dir"
chmod u+x setup.sh
./setup.sh demo-project
Use when: the same manual sequence must run reliably more than once.
🌿 Git collaboration and AWS access
Configure and initialise Git
Set your commit identity once, create a repository, and standardise the primary branch.
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git init
git branch -m main
Use when: preparing Git on a new laptop or server.
Inspect, stage, and commit
Review changes before creating a meaningful repository checkpoint.
git status
git diff
git add .
git commit -m "Describe the change"
git log --oneline
Habit: check git status before and after each commit.
Branches and merging
Isolate work on a feature branch, then integrate it into main.
git checkout -b feature-login
# edit, add, and commit
git checkout main
git merge feature-login
git log --graph --decorate --oneline --all
Use when: developing features without destabilising the shared branch.
Connect and synchronise a remote
Add a GitHub repository, inspect the mapping, and exchange commits.
git remote add origin git@github.com:<user>/<repo>.git
git remote -v
git fetch origin
git pull --no-rebase
git push -u origin main
Fetch vs pull: fetch downloads history; pull downloads and integrates it.
GitHub SSH key setup
Create a key pair, load the private key, and copy the public key into GitHub.
ssh-keygen -t rsa -b 4096 -C "you@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub
ssh -T git@github.com
Never share: the private key file without .pub.
Resolve a merge conflict
Pull the remote history, edit conflict markers, then commit the resolved file.
git pull origin main --no-rebase
git status
nano conflicted-file.txt
git add conflicted-file.txt
git commit -m "Resolve merge conflict"
git push
Do not commit: files that still contain <<<<<<< conflict markers.
Confirm the AWS CLI identity
Before operating AWS resources, confirm the client and authenticated principal.
aws --version
aws sts get-caller-identity
Use when: a cloud command fails with an authentication or permissions error.
☕ Java, Maven, and Tomcat delivery
Verify Java and Maven
Confirm both tools are installed and visible through PATH.
java -version
mvn -v
which java
which mvn
Troubleshoot: if Maven exists but is not found, check M2_HOME and PATH.
Generate a Maven web application
Create the same archetype-based web project introduced in Week 4.
mvn archetype:generate \
-DgroupId=vn.edu.rmit \
-DartifactId=helloWorld \
-DarchetypeArtifactId=maven-archetype-webapp \
-DinteractiveMode=false
Result: a project containing pom.xml and src/main/webapp.
Build and test with Maven
Run the lifecycle from a clean working directory and package the application as a WAR.
cd helloWorld
mvn clean
mvn test
mvn package
ls -la target/
Artifact: target/helloWorld.war.
Start and stop Tomcat
Operate Tomcat directly from its binary directory or through course-created symbolic links.
cd /opt/tomcat/bin
./startup.sh
./shutdown.sh
tomcatup
tomcatdown
Verify: check the configured HTTP port in a browser or with curl.
Deploy a WAR to Tomcat
Copy the packaged artifact into the webapps directory and restart the server.
cp target/helloWorld.war /opt/tomcat/webapps/
tomcatdown && tomcatup
ls -la /opt/tomcat/webapps/
Application URL: http://<server-ip>:8080/helloWorld/.
🔁 Jenkins continuous integration and delivery
Operate the Jenkins service
Reload systemd after installation, then start and inspect Jenkins.
sudo systemctl daemon-reload
sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
Web interface: normally available on port 8080.
Retrieve the initial password
Use this only during first-time setup, then create a normal administrator account.
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Security: do not place this value in Git, screenshots, or shared logs.
Check build-agent tools
Verify that the Jenkins node can access the same tools used by the build job.
git --version
java -version
mvn -v
docker --version
ansible --version
Use when: a job works manually but fails under the Jenkins user or agent.
Fail a build when validation fails
Return a non-zero status so Jenkins stops before deployment.
#!/usr/bin/env bash
set -e
cd "$WORKSPACE"
if ! grep -q "<title>Hello DevOps Students!</title>" \
src/main/webapp/index.jsp; then
echo "Expected title was not found"
exit 1
fi
Pipeline rule: build and test successfully before copying artifacts or deploying containers.
🐳 Docker images, containers, storage, and registries
Inspect Docker state
List local images and running or stopped containers before making changes.
docker images
docker ps
docker ps -a
docker --help
Use when: checking names, IDs, status, ports, or existing resources.
Pull and run an image
Start a detached container and map a host port to the application's container port.
docker pull tomcat
docker run -d \
--name tomcat-container \
-p 8081:8080 \
tomcat:latest
Port order: host:container.
Enter and inspect a container
Open an interactive shell inside a running container.
docker exec -it tomcat-container /bin/bash
pwd
ls -la
exit
Use when: inspecting files, environment variables, or processes inside the container.
Stop and remove containers
Stop gracefully, remove explicitly, or prune all stopped containers.
docker stop tomcat-container
docker rm tomcat-container
docker container prune
Caution: pruning affects every stopped container on the host.
Build from a Dockerfile
Build and tag an image using the Dockerfile in the current directory.
docker build -t myapp:v1 .
docker images
FROM tomcat:latest
RUN cp -R /usr/local/tomcat/webapps.dist/* /usr/local/tomcat/webapps
COPY ./*.war /usr/local/tomcat/webapps
Build context: the final dot sends the current directory to Docker.
Persist data with a volume
Keep logs or application data when a container is replaced.
docker volume create my-app-logs
docker run -d \
--name myapp-container \
-p 8088:8080 \
-v my-app-logs:/usr/local/tomcat/logs \
myapp:v3
Benefit: the named volume survives the container lifecycle.
Tag and publish an image
Associate the local image with your Docker Hub namespace, authenticate, and push.
docker tag myapp:latest <dockerhub-user>/myapp:latest
docker login
docker push <dockerhub-user>/myapp:latest
Naming: the registry namespace must match your Docker Hub user or organisation.
Clean unused Docker data
Review resources first, then remove unused containers, networks, and images.
docker ps -a
docker images
docker system df
docker system prune
Caution: read Docker's confirmation prompt before accepting.
⚙️ Ansible inventories, ad-hoc commands, and playbooks
Inventory groups
Group managed server addresses in the inventory used by the controller.
[dockerserver]
<docker-private-ip>
[ansibleserver]
<ansible-private-ip>
Check: use ansible-config dump | grep DEFAULT_HOST_LIST to find the active inventory path.
Prepare passwordless access
Copy the controller user's public key to each managed node.
ssh-keygen
ssh-copy-id <managed-node-ip>
ssh <managed-node-ip>
Ansible requirement: the control node must be able to reach managed nodes over SSH.
Test managed nodes
Validate connectivity, Python availability, and ad-hoc command execution.
ansible all -m ping
ansible all -m command -a uptime
ansible dockerserver -a "docker ps"
Start here: do not debug a playbook until the ping module succeeds.
Run a playbook
Apply the ordered tasks in a YAML playbook to its target hosts.
ansible-playbook buildAndPush.yml
ansible-playbook pullToCreateContainer.yml
Repeatability: design tasks so rerunning the playbook converges safely.
Build and push with a playbook
This course pattern delegates Docker build and registry publishing to Ansible.
---
- hosts: ansibleserver
tasks:
- name: Build application image
command: docker build -t myapp:latest .
- name: Tag image for Docker Hub
command: docker tag myapp:latest <user>/myapp:latest
- name: Push image
command: docker push <user>/myapp:latest
Before running: authenticate once with docker login.
🧩 Docker Compose and Docker Swarm
Compose service definition
Describe related containers, ports, environment values, and dependencies in one YAML file.
services:
redis:
image: redis:latest
db:
image: postgres:9.4
environment:
POSTGRES_PASSWORD: postgres
vote:
build: ./vote
ports:
- "8080:80"
depends_on:
- redis
Course application: expand the same file with worker and result services.
Compose lifecycle
Create the whole application, inspect it, view logs, and remove its resources.
docker compose up -d
docker compose ps
docker compose logs -f
docker compose down
Course note: older installations use the equivalent docker-compose command.
Create and join a swarm
Initialise the manager, then run the generated join command on each worker.
# Manager
docker swarm init
# Worker
docker swarm join --token <token> <manager-ip>:2377
# Manager
docker node ls
Network: allow the required Swarm management and overlay ports between nodes.
Create and inspect a service
Publish Nginx through the routing mesh and maintain two replicas.
docker service create \
--name nginx \
--replicas 2 \
--publish published=8080,target=80 \
nginx
docker service ls
docker service ps nginx
Service vs task: the service is desired state; each replica runs as a task.
Drain a manager or remove a service
Prevent workload scheduling on the manager and observe Swarm replace its tasks.
docker node update --availability drain docker-master
docker service ps nginx
docker service rm nginx
Self-healing: Swarm reschedules tasks to maintain the requested replica count.
☸️ Kubernetes, Minikube, and Amazon EKS
Minikube lifecycle
Start a learning cluster, check its components, open the dashboard, and clean up.
minikube start --force
minikube status
kubectl get nodes
minikube dashboard --url
minikube stop
minikube delete
Use when: practising Kubernetes on a single EC2 learning node.
Create and inspect a pod
Run an image directly, then inspect status, placement, and detailed events.
kubectl run todolistapp --image=<image>
kubectl get pods
kubectl get pod -o wide
kubectl describe pod todolistapp
kubectl get events --sort-by=.metadata.creationTimestamp
Debug order: get → describe → events → logs.
Expose and forward a service
Create a NodePort service or temporarily forward a local port to it.
kubectl expose pod todolistapp \
--type=NodePort \
--port=80 \
--name=todolistapp-service
kubectl get svc
kubectl port-forward svc/todolistapp-service \
3000:80 --address 0.0.0.0
Security: only expose ports required by the lab and close them after use.
Apply and remove manifests
Prefer declarative files when resources must be repeatable and version controlled.
kubectl apply -f pod.yml
kubectl apply -f service.yml
kubectl get all
kubectl delete -f service.yml
kubectl delete -f pod.yml
Folder workflow: kubectl apply -f . applies every manifest in the directory.
Minimal Pod manifest
Labels connect this pod to a service selector.
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: demo-app
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Key relationship: service selectors must match pod labels exactly.
Minimal Service manifest
Route traffic on port 80 to pods labelled app: demo-app.
apiVersion: v1
kind: Service
metadata:
name: demo-service
spec:
type: LoadBalancer
selector:
app: demo-app
ports:
- port: 80
targetPort: 80
Cloud behaviour: a LoadBalancer service requests an external load balancer from the provider.
Deployment and replicas
Create a managed workload instead of a standalone pod.
kubectl create deployment demo-nginx \
--image=nginx \
--replicas=2 \
--port=80
kubectl get deployment
kubectl get replicaset
kubectl get pods
Benefit: the Deployment maintains replica count and supports updates.
Connect kubectl to Amazon EKS
Check the clients, write the EKS cluster context into kubeconfig, and inspect worker nodes.
aws --version
kubectl version --client
eksctl version
aws eks update-kubeconfig \
--name <cluster-name> \
--region <region>
kubectl get nodes
Authentication: the AWS identity needs permission to access the EKS cluster.
Inspect and clean a namespace
Review the default namespace before removing its lab workloads.
kubectl get all --namespace=default
kubectl get deployments,svc
kubectl delete pods,services --all --namespace=default
Caution: namespace-wide deletion removes every matching resource, not only the current exercise.