|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8" /> |
|
<title>Intro to Containers Fact or Fiction (2025)</title> |
|
<link rel="preconnect" href="https://fonts.gstatic.com" /> |
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;600&display=swap" rel="stylesheet"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|
<style> |
|
* { margin: 0; padding: 0; box-sizing: border-box; } |
|
:root { |
|
--bg1:#c9e8ff; --bg2:#fde2ff; --ink:#222; --ink-sub:#555; |
|
--brand:#2563eb; --brand-2:#22c55e; --good:#16a34a; --bad:#dc2626; |
|
--card:#ffffffcc; |
|
} |
|
body { |
|
font-family: 'Poppins', sans-serif; |
|
background: radial-gradient(1200px 600px at 20% 0%, var(--bg1), transparent 60%), |
|
radial-gradient(1200px 600px at 80% 0%, var(--bg2), transparent 60%), |
|
#f6f7fb; |
|
min-height: 100vh; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
justify-content: flex-start; |
|
padding: 2rem 1rem; |
|
color: var(--ink); |
|
} |
|
h1 { text-align: center; margin-bottom: .25rem; font-weight: 600; font-size: 2.2rem; } |
|
#subtitle { text-align:center; margin-bottom:1rem; color: var(--ink-sub); } |
|
#source-link { text-align: center; margin-bottom: 1.25rem; font-size: .95rem; } |
|
#source-link a { color: var(--ink); text-decoration: underline; } |
|
#game-container { |
|
background: var(--card); |
|
width: 100%; max-width: 820px; |
|
padding: 2rem; border-radius: 16px; |
|
box-shadow: 0 10px 24px rgba(0,0,0,.15); |
|
display: flex; flex-direction: column; align-items: center; |
|
} |
|
.progress-container { |
|
width: 100%; background:#ececec; border-radius: 999px; overflow: hidden; margin-bottom: 1rem; |
|
} |
|
.progress-bar { height: 14px; width:0%; background: linear-gradient(90deg,var(--brand),var(--brand-2)); transition: width .3s ease; } |
|
#statement { |
|
font-size: 1.25rem; line-height: 1.5; text-align: center; color: #333; |
|
min-height: 90px; margin: .75rem 0 1rem; |
|
} |
|
.btn-group { display:flex; gap:.75rem; flex-wrap:wrap; justify-content:center; margin: .25rem 0 1rem; } |
|
button { |
|
padding: .75rem 1.25rem; border: none; border-radius: 999px; cursor: pointer; |
|
background: var(--brand); color: #fff; font-weight: 600; letter-spacing:.2px; |
|
transition: transform .15s ease, box-shadow .15s ease, background .2s ease; |
|
} |
|
button.secondary { background:#111827; } |
|
button:hover { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(0,0,0,.15); } |
|
#result { |
|
margin-top: .5rem; padding: .75rem 1rem; border-radius: 10px; font-weight: 700; text-align: center; display:none; |
|
} |
|
#result.correct { display:block; background:#dcfce7; color:#14532d; } |
|
#result.incorrect { display:block; background:#fee2e2; color:#7f1d1d; } |
|
#explanation { |
|
margin-top: .75rem; padding: 1rem; background:#f9fafb; color:#374151; border-radius:12px; display:none; |
|
} |
|
#score { margin-top: .75rem; font-weight: 700; } |
|
#controls { display:flex; gap:.5rem; margin-top:.5rem; } |
|
#controls button { background:#0f766e; } |
|
#restart-btn { background:#6b21a8; } |
|
</style> |
|
</head> |
|
<body> |
|
<h1>Intro to Containers Fact or Fiction</h1> |
|
<div id="subtitle">Test your 2025 knowledge of Containers, Docker, and Kubernetes</div> |
|
<div id="source-link"> |
|
Source: <a href="https://www.linkedin.com/pulse/concept-containers-michael-lively-n1rae/" target="_blank" rel="noopener"> |
|
Introduction to Containers, Docker, and Kubernetes (LinkedIn) |
|
</a> |
|
</div> |
|
|
|
<div id="game-container" role="region" aria-label="Fact or Fiction game"> |
|
<div class="progress-container" aria-hidden="true"><div class="progress-bar" id="progress-bar"></div></div> |
|
<div id="statement" aria-live="polite">Loading statement...</div> |
|
|
|
<div class="btn-group"> |
|
<button onclick="guess(true)" aria-label="Choose Fact">Fact</button> |
|
<button class="secondary" onclick="guess(false)" aria-label="Choose Fiction">Fiction</button> |
|
</div> |
|
|
|
<div id="result" role="status" aria-live="polite"></div> |
|
<div id="explanation"></div> |
|
|
|
<div id="controls"> |
|
<button id="next-btn" style="display:none;" onclick="nextStatement()">Next</button> |
|
<button id="restart-btn" style="display:none;" onclick="startGame()">Restart</button> |
|
</div> |
|
|
|
<div id="score" aria-live="polite"></div> |
|
</div> |
|
|
|
<script> |
|
|
|
const statements = [ |
|
|
|
{ |
|
text: "Containers share the host operating system kernel instead of bundling a full guest OS.", |
|
isFact: true, |
|
explanation: "Fact. Containers virtualize at the OS layer, which keeps them lightweight and fast to start." |
|
}, |
|
{ |
|
text: "Docker’s 2013 release popularized containerization by standardizing images and registries for developers.", |
|
isFact: true, |
|
explanation: "Fact. Docker democratized packaging and distribution via images and registries." |
|
}, |
|
{ |
|
text: "Kubernetes (introduced in 2014) is the de facto standard for orchestrating containers at scale.", |
|
isFact: true, |
|
explanation: "Fact. K8s handles scheduling, scaling, rollouts, and self-healing across clusters." |
|
}, |
|
{ |
|
text: "Modern Kubernetes clusters run with OCI-compatible runtimes like containerd or CRI-O, not Docker Engine.", |
|
isFact: true, |
|
explanation: "Fact. Dockershim was removed; K8s uses CRI runtimes such as containerd/CRI-O." |
|
}, |
|
{ |
|
text: "OCI standards improve interoperability for images and artifacts, including SBOMs and signatures.", |
|
isFact: true, |
|
explanation: "Fact. OCI Image/Artifact specs let registries store images, SBOMs, and signatures consistently." |
|
}, |
|
{ |
|
text: "Rootless options like Podman, plus strong policies and signing (e.g., cosign), are common 2025 security practices.", |
|
isFact: true, |
|
explanation: "Fact. Least privilege, rootless, SBOMs, and signing are part of modern supply-chain security." |
|
}, |
|
|
|
|
|
{ |
|
text: "Containers always include a complete guest operating system, just like virtual machines.", |
|
isFact: false, |
|
explanation: "Fiction. Containers share the host kernel; VMs package a full OS per instance." |
|
}, |
|
{ |
|
text: "Kubernetes is itself a container runtime, so you don’t need containerd or CRI-O anymore.", |
|
isFact: false, |
|
explanation: "Fiction. Kubernetes is an orchestrator and relies on a CRI-compatible runtime underneath." |
|
}, |
|
{ |
|
text: "In 2025, Docker Engine is the default runtime under Kubernetes for production clusters.", |
|
isFact: false, |
|
explanation: "Fiction. Since the dockershim removal, production K8s uses containerd or CRI-O." |
|
}, |
|
{ |
|
text: "OpenTelemetry has fully replaced all observability tools and is already a graduated CNCF project.", |
|
isFact: false, |
|
explanation: "Fiction. OTel is the de facto standard for telemetry formats, but it has not replaced all tools and has not historically been fully graduated." |
|
}, |
|
{ |
|
text: "WebAssembly (Wasm) has completely replaced containers for cloud workloads.", |
|
isFact: false, |
|
explanation: "Fiction. Wasm is growing and complementary; it hasn’t replaced containers." |
|
}, |
|
{ |
|
text: "Containers are a poor fit for hybrid or multi-cloud because they lack portability.", |
|
isFact: false, |
|
explanation: "Fiction. Portability is one of containers’ biggest strengths across on-prem, cloud, and edge." |
|
} |
|
]; |
|
|
|
|
|
let currentIndex = 0, score = 0, answered = false; |
|
|
|
function shuffle(arr) { |
|
for (let i = arr.length - 1; i > 0; i--) { |
|
const j = Math.floor(Math.random() * (i + 1)); |
|
[arr[i], arr[j]] = [arr[j], arr[i]]; |
|
} |
|
} |
|
|
|
function startGame() { |
|
shuffle(statements); |
|
currentIndex = 0; score = 0; answered = false; |
|
document.getElementById('restart-btn').style.display = 'none'; |
|
loadStatement(); updateScore(); |
|
} |
|
|
|
function loadStatement() { |
|
if (currentIndex >= statements.length) return endGame(); |
|
const s = statements[currentIndex]; |
|
document.getElementById('statement').textContent = s.text; |
|
const resultEl = document.getElementById('result'); |
|
resultEl.style.display = 'none'; |
|
resultEl.textContent = ''; |
|
resultEl.className = ''; |
|
document.getElementById('explanation').style.display = 'none'; |
|
document.getElementById('next-btn').style.display = 'none'; |
|
answered = false; updateProgress(); |
|
} |
|
|
|
function guess(isFactGuess) { |
|
if (answered) return; |
|
answered = true; |
|
const correct = statements[currentIndex].isFact; |
|
const resultEl = document.getElementById('result'); |
|
|
|
if (isFactGuess === correct) { |
|
resultEl.textContent = 'Correct!'; |
|
resultEl.className = 'correct'; |
|
score++; |
|
} else { |
|
resultEl.textContent = 'Incorrect!'; |
|
resultEl.className = 'incorrect'; |
|
} |
|
resultEl.style.display = 'block'; |
|
|
|
const expEl = document.getElementById('explanation'); |
|
expEl.textContent = statements[currentIndex].explanation + " (See source link above.)"; |
|
expEl.style.display = 'block'; |
|
document.getElementById('next-btn').style.display = 'inline-block'; |
|
updateScore(); |
|
} |
|
|
|
function nextStatement() { |
|
currentIndex++; |
|
if (currentIndex < statements.length) loadStatement(); |
|
else endGame(); |
|
} |
|
|
|
function updateScore() { |
|
document.getElementById('score').textContent = `Score: ${score} / ${statements.length}`; |
|
} |
|
|
|
function updateProgress() { |
|
const pct = Math.round((currentIndex / statements.length) * 100); |
|
document.getElementById('progress-bar').style.width = pct + '%'; |
|
} |
|
|
|
function endGame() { |
|
const pct = Math.round((score / statements.length) * 100); |
|
document.getElementById('statement').textContent = |
|
`Game Over! You scored ${score} of ${statements.length} (${pct}%).`; |
|
document.getElementById('result').style.display = 'none'; |
|
document.getElementById('explanation').style.display = 'none'; |
|
document.getElementById('next-btn').style.display = 'none'; |
|
document.getElementById('restart-btn').style.display = 'inline-block'; |
|
document.getElementById('progress-bar').style.width = '100%'; |
|
} |
|
|
|
startGame(); |
|
</script> |
|
</body> |
|
</html> |
|
|