In this task, you will learn about container and virtualization in Linux Enterprise.
What you should learn are in below:
Write your learning activity to HackMD
Playing with Image Repository
Pull nginx docker images
As you can see from here, we've created the linux namespace.
Listing podman images
As you can see from here, we've created the linux namespace.
Run the nginx container
Listing podman container
As you can see from here, we've created the linux namespace.
Setup Local Repository
Set Local Repo (With Volume)
ββββββββpodman container run -dt -p 5000:5000 --name rafli-regis --volume rafli-volume:/var/lib/registry:Z docker.io/library/registry:2
As you can see from here the output from the creation.
ββββββββCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ββββββββ01c9b2bfa441 docker.io/library/registry:2 /etc/docker/regis... 37 seconds ago Up 37 seconds ago 0.0.0.0:5000->5000/tcp rafli-regis
Check The volume inspect output
ββββββββ[
ββββββββ {
ββββββββ "Name": "rafli-volume",
ββββββββ "Driver": "local",
ββββββββ "Mountpoint": "/var/lib/containers/storage/volumes/rafli-volume/_data",
ββββββββ "CreatedAt": "2023-12-05T06:40:56.539301178Z",
ββββββββ "Labels": {},
ββββββββ "Scope": "local",
ββββββββ "Options": {}
ββββββββ }
ββββββββ]
Test if the local repo is properly configured
Test with the alpine image
ββββββββpodman image pull docker.io/library/alpine
ββββββββ[root@rafli]# podman image pull docker.io/library/alpine
ββββββββTrying to pull docker.io/library/alpine:latest...
ββββββββGetting image source signatures
ββββββββCopying blob c926b61bad3b skipped: already exists
ββββββββCopying config b541f20801 done
ββββββββWriting manifest to image destination
ββββββββStoring signatures
ββββββ
βββββββb541f2080109ab7b6bf2c06b28184fb750cdd17836c809211127717f48809858
Change the label name to the local repo with the port
ββββββββpodman image tag docker.io/library/alpine:latest localhost:5000/alpine:latest
ββββββββREPOSITORY TAG IMAGE ID CREATED SIZE
ββββββββdocker.io/library/registry 2 909c3ff012b7 4 days ago 26 MB
ββββββββdocker.io/library/alpine latest b541f2080109 4 days ago 7.63 MB
ββββββββlocalhost:5000/alpine latest b541f2080109 4 days ago 7.63 MB
Upload to the local registry
ββββββββpodman image push localhost:5000/alpine:latest --tls-verify=false
ββββββββGetting image source signatures
ββββββββCopying blob 9fe9a137fd00 done
ββββββββCopying config b541f20801 done
ββββββββWriting manifest to image destination
ββββββββStoring signatures
Containerized Existing App with Dockerfile
Clone the repository in my case wheater app
ββββββββgit clone https://github.com/Sameerk22/City-Weather-App
ββββββββcd City-Weather-App
Create a Containerfile
ββββββββ#Build a weather app
ββββββββFROM node:lts-alpine
ββββββββWORKDIR /usr/local/app
ββββββββCOPY package.json package-lock.json ./
ββββββββRUN npm install
ββββββββCOPY public ./public
ββββββββCOPY src ./src
ββββββββ# RUN npm run build
ββββββββCMD ["npm", "run"]
Build the Containerfile with custom name
ββββββββpodman build -t localhost:5000/wheather-app:1.0 .
Push the image to the local registry
ββββββββpodman image push localhost:5000/wheather-app:1.0 --tls-verify=false
Verify if the image is being uploaded to local registry
ββββββββpodman image search localhost:5000/
ββββββββINDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ββββββββlocalhost:5000 localhost:5000/alpine 0
ββββββββlocalhost:5000 localhost:5000/wheather-app 0
Managed Storage
By default all files created inside a container are stored on a writable container layer. This means that:
Using podman - bind mounts
Create a directory with files innit
ββββββββββββsudo mkdir /bindhost
ββββββββββββsudo sh -c "echo Hello from the HOST! > /bindhost/hello"
Create a container with bind mount to the /bindhost
ββββββββββββpodman run -d -it --name bindtest --mount type=bind,source=/bindhost,target=/shared nginx
Checks whether the contents of the container are the same as the bind mount path of the host
ββββββββββββpodman exec -it bindtest cat /shared/hello
Host Storage related with Container Storage
ββββββββββββsudo sh -c "echo Hello from the HOST the second time! > /bindhost/hello2"
ββββββββββββdocker exec -it bindtest cat /shared/hello2
Share the Host Storage to Other Container Storage
ββββββββββββpodman run -d -it --name bindtest-2 --mount type=bind,source=/bindhost,target=/bersama nginx
ββββββββββββdocker inspect bindtest-2 -f '{{json .Mounts }}'| python3 -m json.tool
ββββββββββββdocker exec -it bindtest-2 ls -l /bersama
Using podman - volumes
Create Volume with custom name
ββββββββββββββββpodman volume create volume-1
Build the Container with Docker Volume RO Configuration
ββββββββββββββββpodman run -d -it --name volumetest-2 --mount source=volume-1,target=/app,readonly nginx
Inspect if the configuration is done
ββββββββββββββββdocker inspect voltest3 -f '{{json .Mounts }}' | python3 -m json.tool
Priviledge Container
Executing container engines with the βprivileged flag tells the engine to launch the container process without any further "security" lockdown. But it comes with the risk:
Container Escalation: Privileged containers can escalate their access to the host system, potentially gaining unauthorized control.
Resource Exhaustion: Privileged containers can consume host resources without any restrictions, potentially causing resource exhaustion or denial-of-service attacks.
Data Exposure: Privileged containers can access sensitive data on the host system, potentially leading to data breaches or exposure.
There are serveral impact to the list down system:
Read-only kernel file systems
Without Priviledge
ββββββββββββpodman run fedora mount | grep /proc.*tmpfs
ββββββββββββResolved "fedora" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
ββββββββββββTrying to pull registry.fedoraproject.org/fedora:latest...
ββββββββββββGetting image source signatures
ββββββββββββCopying blob 718a00fe3212 done
ββββββββββββCopying config 368a084ba1 done
ββββββββββββWriting manifest to image destination
ββββββββββββStoring signatures
ββββββββββββsysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime)
ββββββββββββcgroup2 on /sys/fs/cgroup type cgroup2 (ro,nosuid,nodev,noexec,relatime)
ββββββββββββtmpfs on /proc/acpi type tmpfs (ro,relatime,size=0k,uid=1002,gid=1002,inode64)
ββββββββββββtmpfs on /proc/scsi type tmpfs (ro,relatime,size=0k,uid=1002,gid=1002,inode64)
ββββββββββββtmpfs on /sys/firmware type tmpfs (ro,relatime,size=0k,uid=1002,gid=1002,inode64)
ββββββββββββtmpfs on /sys/dev/block type tmpfs (ro,relatime,size=0k,uid=1002,gid=1002,inode64)
ββββββββββββproc on /proc/bus type proc (ro,relatime)
ββββββββββββproc on /proc/fs type proc (ro,relatime)
ββββββββββββproc on /proc/irq type proc (ro,relatime)
ββββββββββββproc on /proc/sys type proc (ro,relatime)
ββββββββββββproc on /proc/sysrq-trigger type proc (ro,relatime)
With Priviledge
ββββββββββββpodman run --privileged fedora mount | grep /proc.*tmpfs
None of the kernel file systems are mounted read-only in βprivileged mode. Usually, this is required to allow processes inside of the container to actually modify the kernel through the kernel file system.
Linux capabilities
Without Priviledge
ββββββββββββpodman run -d fedora sleep 100
ββββββββββββpodman top -l capeff
ββββββββββββEFFECTIVE CAPS
ββββββββββββCHOWN,DAC_OVERRIDE,FOWNER,FSETID,KILL,NET_BIND_SERVICE,SETFCAP,SETGID,SETPCAP,SETUID,SYS_CHR
With Priviledge
ββββββββββββpodman run --privileged -d fedora sleep 100
ββββββββββββEFFECTIVE CAPS
ββββββββββββAUDIT_CONTROL,AUDIT_READ,AUDIT_WRITE,BLOCK_SUSPEND,CHOWN,DAC_OVERRIDE,DAC_READ_SEARCH,FOWNER,FSETID,IPC_LOCK,IPC_OWNER,KILL,LEASE,LINUX_IMMUTABLE,MAC_ADMIN,MAC_OVERRIDE,MKNOD,NET_ADMIN,NET_BIND_SERVICE,NET_BROADCAST,NET_RAW,SETFCAP,SETGID,SETPCAP,SETUID,SYSLOG,SYS_ADMIN,SYS_BOOT,SYS_CHROOT,SYS_MODULE,SYS_NICE,SYS_PACCT,SYS_PTRACE,SYS_RAWIO,SYS_RESOURCE,SYS_TIME,SYS_TTY_CONFIG,WAKE_ALARM,unknown,unknown,unknown
When you launch a container with βprivileged mode, the container launches with almost of full list capabilities.
Syscall filtering - SECCOMP
Without Priviledge
βββββββββββpodman run -d fedora sleep 100
βββββββββββpodman top -l seccomp
ββββββββββββSECCOMP
ββββββββββββfilter
With Priviledge
ββββββββββββpodman run --privileged -d fedora sleep 100
βββββββββββpodman top -l seccomp
ββββββββββββSECCOMP
ββββββββββββdisabled
Container with Proxy Access
Configuring and deploying Example Webapp
ββββββββpodman pull docker.io/library/httpd
ββββββββpodman pull docker.io/library/nginx
ββββββββmkdir syscom sysorg
Configuring index.html
ββββββββ$ cat << EOF > ./syscom/index.html
ββββββββ<html>
ββββββββ <header>
ββββββββ <title>SysAdmin.com</title>
ββββββββ </header>
ββββββββ <body>
ββββββββ <p>This is the SysAdmin website hosted on the .com domain</p>
ββββββββ </body>
ββββββββ</html>
ββββββββEOF
ββββββββ$ cat << EOF > ./sysorg/index.html
ββββββββ<html>
ββββββββ <header>
ββββββββ <title>SysAdmin.org</title>
ββββββββ </header>
ββββββββ <body>
ββββββββ <p>This is the SysAdmin website hosted on the .org domain</p>
ββββββββ </body>
ββββββββ</html>
ββββββββEOF
Configure the proxy
ββββββββmkdir nginx
ββββββββtouch nginx/default.conf nginx/syscom.conf nginx/sysorg.conf
default.conf
ββββββββserver {
ββββββββ listen 80;
ββββββββ listen [::]:80;
ββββββββ server_name localhost;
ββββββββ location / {
ββββββββ root /usr/share/nginx/html;
ββββββββ index index.html index.htm;
ββββββββ }
ββββββββ error_page 500 502 503 504 /50x.html;
ββββββββ location = /50x.html {
ββββββββ root /usr/share/nginx/html;
ββββββββ }
ββββββββ}
syscom.conf
ββββββββserver {
ββββββββ listen 80;
ββββββββ server_name sysadmin.com;
ββββββββ location / {
ββββββββ proxy_pass http://192.168.1.53:8080;
ββββββββ }
ββββββββ}
sysorg.conf
ββββββββserver {
ββββββββ listen 80;
ββββββββ server_name sysadmin.org;
ββββββββ location / {
ββββββββ proxy_pass http://192.168.1.53:8081;
ββββββββ }
ββββββββ}
Run in proxy configuration in podman
ββββββββpodman run --name=nginx --privileged -p 80:80 -v /home/analyst/nginx:/etc/nginx/conf.d:Z -d docker.io/library/nginx
Validation time with curl
to the domain
Validation time with the browser
Access your Nginx container on VM 1 from Host Machine via browser
Access your Nginx container from Namespace of VM 2 using curl