Loading... ### 今天久爱问我会不会docker, 给我纯气笑了,不知道是狗爱装傻还是断网了几年导致脑子不好使了 ### 所以弄了一个html在线快速入门教程给他 ##### tips: 久爱/狗爱 = 一个人 = 我好大儿  ### 希望未来能提供给有用的人吧 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>交互式 Docker 教程</title> <script src="https://cdn.tailwindcss.com"></script> <style> body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } .nav-link { transition: all 0.3s ease; } .nav-link.active { color: #3b82f6; /* blue-500 */ border-bottom-color: #3b82f6; } .content-section { display: none; } .content-section.active { display: block; } .concept-card { transition: transform 0.3s ease, box-shadow 0.3s ease; } .concept-card:hover { transform: translateY(-5px); box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); } .command-card { transition: opacity 0.3s ease; } .practice-step { display: none; } .practice-step.active { display: block; } .copy-btn { position: absolute; top: 0.5rem; right: 0.5rem; background-color: #4b5563; color: white; padding: 0.25rem 0.5rem; border-radius: 0.375rem; font-size: 0.75rem; opacity: 0; transition: opacity 0.3s ease; cursor: pointer; } pre:hover .copy-btn { opacity: 1; } </style> </head> <body class="bg-gray-50 text-gray-800"> <div class="container mx-auto px-4 py-8"> <header class="text-center mb-10"> <h1 class="text-4xl md:text-5xl font-bold text-gray-900">交互式 Docker 教程</h1> <p class="mt-4 text-lg text-gray-600">从入门到实践,轻松掌握容器化技术。</p> </header> <nav class="bg-white rounded-lg shadow-md mb-8 sticky top-4 z-10"> <ul class="flex items-center justify-center space-x-2 sm:space-x-8 p-4 border-b border-gray-200"> <li><a href="#" class="nav-link text-gray-600 hover:text-blue-500 font-medium pb-2 border-b-2 border-transparent active" data-target="intro">介绍</a></li> <li><a href="#" class="nav-link text-gray-600 hover:text-blue-500 font-medium pb-2 border-b-2 border-transparent" data-target="concepts">核心概念</a></li> <li><a href="#" class="nav-link text-gray-600 hover:text-blue-500 font-medium pb-2 border-b-2 border-transparent" data-target="commands">命令速查</a></li> <li><a href="#" class="nav-link text-gray-600 hover:text-blue-500 font-medium pb-2 border-b-2 border-transparent" data-target="practice">动手实践</a></li> </ul> </nav> <main> <!-- 介绍 Section --> <section id="intro" class="content-section active"> <div class="bg-white p-8 rounded-lg shadow-lg animate-fade-in"> <h2 class="text-3xl font-bold mb-6 text-gray-900">1. 什么是 Docker?</h2> <p class="text-lg mb-6 leading-relaxed"> 想象一下,你在电脑上开发了一个应用,运行完美。但当你把它交给同事或部署到服务器时,却出现各种问题:“缺少依赖”、“环境配置不对”、“我的电脑上跑不起来!”。 </p> <div class="bg-blue-50 border-l-4 border-blue-500 p-6 rounded-r-lg"> <p class="text-xl font-semibold text-blue-800"> Docker 就是解决这个问题的“集装箱”。它是一种开源的**容器化**平台,能将你的应用及其所有依赖打包到一个轻量、可移植的**容器**中。这个容器可以在任何安装了 Docker 的机器上运行,保证环境绝对一致。 </p> </div> <h3 class="text-2xl font-bold mt-10 mb-6 text-gray-900">Docker vs. 虚拟机 (VM)</h3> <p class="mb-6">简单来说,虚拟机是在操作系统里虚拟出一整套硬件,再安装一个完整的操作系统;而 Docker 容器则直接运行在宿主机的操作系统内核之上,更加轻量和高效。</p> <div class="overflow-x-auto"> <table class="w-full min-w-full text-left border-collapse"> <thead class="bg-gray-100"> <tr> <th class="p-4 border border-gray-300 font-semibold">特性</th> <th class="p-4 border border-gray-300 font-semibold text-blue-600">Docker 容器 (Container)</th> <th class="p-4 border border-gray-300 font-semibold">虚拟机 (Virtual Machine)</th> </tr> </thead> <tbody> <tr class="hover:bg-gray-50"> <td class="p-4 border border-gray-300 font-medium">隔离级别</td> <td class="p-4 border border-gray-300">进程级别隔离</td> <td class="p-4 border border-gray-300">完整的操作系统隔离</td> </tr> <tr class="hover:bg-gray-50"> <td class="p-4 border border-gray-300 font-medium">启动速度</td> <td class="p-4 border border-gray-300">秒级</td> <td class="p-4 border border-gray-300">分钟级</td> </tr> <tr class="hover:bg-gray-50"> <td class="p-4 border border-gray-300 font-medium">资源占用</td> <td class="p-4 border border-gray-300">轻量,占用资源少</td> <td class="p-4 border border-gray-300">重量级,占用资源多</td> </tr> <tr class="hover:bg-gray-50"> <td class="p-4 border border-gray-300 font-medium">核心</td> <td class="p-4 border border-gray-300">共享宿主机的操作系统内核</td> <td class="p-4 border border-gray-300">拥有自己独立的操作系统内核</td> </tr> <tr class="hover:bg-gray-50"> <td class="p-4 border border-gray-300 font-medium">本质</td> <td class="p-4 border border-gray-300">一个被隔离的进程</td> <td class="p-4 border border-gray-300">一台完整的虚拟电脑</td> </tr> </tbody> </table> </div> </div> </section> <!-- 核心概念 Section --> <section id="concepts" class="content-section"> <div class="bg-white p-8 rounded-lg shadow-lg"> <h2 class="text-3xl font-bold mb-2 text-gray-900">2. 核心概念</h2> <p class="text-lg text-gray-600 mb-8">要掌握 Docker,理解这四个核心概念至关重要。它们共同构成了 Docker 的工作流程。点击下方的卡片来查看每个概念的详细解释。</p> <div class="grid md:grid-cols-2 gap-8"> <div class="concept-card bg-gray-50 p-6 rounded-lg border border-gray-200 cursor-pointer" onclick="toggleConcept(this)"> <h3 class="text-2xl font-bold text-blue-600">镜像 (Image) ?️</h3> <p class="mt-2 text-gray-700">一个只读的模板,包含了运行应用所需的所有内容。</p> <div class="details hidden mt-4 text-gray-600 space-y-2"> <p><strong>好比是:</strong> 安装操作系统的<code>.iso</code>文件,或者是“软件安装包”。</p> <p>镜像是创建容器的基础,你可以基于一个基础镜像(如 Ubuntu),在上面添加你的应用和配置,来构建一个新的镜像。</p> </div> </div> <div class="concept-card bg-gray-50 p-6 rounded-lg border border-gray-200 cursor-pointer" onclick="toggleConcept(this)"> <h3 class="text-2xl font-bold text-green-600">容器 (Container) ?</h3> <p class="mt-2 text-gray-700">镜像的运行实例,是真正运行应用的地方。</p> <div class="details hidden mt-4 text-gray-600 space-y-2"> <p><strong>好比是:</strong> 运行起来的软件程序。你可以把镜像看作是“类”,容器就是这个“类”的“实例”。</p> <p>容器之间相互隔离,拥有自己的文件系统、网络和进程空间,可以被创建、启动、停止和删除。</p> </div> </div> <div class="concept-card bg-gray-50 p-6 rounded-lg border border-gray-200 cursor-pointer" onclick="toggleConcept(this)"> <h3 class="text-2xl font-bold text-purple-600">仓库 (Repository) ?</h3> <p class="mt-2 text-gray-700">集中存放和分发镜像的地方。</p> <div class="details hidden mt-4 text-gray-600 space-y-2"> <p><strong>好比是:</strong> GitHub/Gitee 用来存代码,Docker 仓库就是用来存镜像的。</p> <p>最著名的公共仓库是 <strong>Docker Hub</strong>。你也可以搭建自己的私有仓库来管理公司的镜像。</p> </div> </div> <div class="concept-card bg-gray-50 p-6 rounded-lg border border-gray-200 cursor-pointer" onclick="toggleConcept(this)"> <h3 class="text-2xl font-bold text-yellow-600">Dockerfile ?</h3> <p class="mt-2 text-gray-700">一个用来构建镜像的文本文件,包含了一系列指令。</p> <div class="details hidden mt-4 text-gray-600 space-y-2"> <p><strong>好比是:</strong> 一份“菜谱”,详细描述了制作一道菜(镜像)需要哪些原材料和操作步骤。</p> <p>通过执行<code>docker build</code>命令,Docker 引擎会读取 Dockerfile 的内容,并自动构建出镜像。</p> </div> </div> </div> <div class="mt-8 text-center bg-gray-100 p-6 rounded-lg"> <h4 class="text-xl font-semibold mb-2">它们的关系是:</h4> <p class="text-lg text-gray-700">你通过 <strong class="text-yellow-600">Dockerfile</strong> 定义如何构建一个<strong class="text-blue-600">镜像</strong>,然后将镜像上传到<strong class="text-purple-600">仓库</strong>分享,最后从仓库拉取镜像并运行为一个<strong class="text-green-600">容器</strong>。</p> </div> </div> </section> <!-- 命令速查 Section --> <section id="commands" class="content-section"> <div class="bg-white p-8 rounded-lg shadow-lg"> <h2 class="text-3xl font-bold mb-2 text-gray-900">3. 命令速查</h2> <p class="text-lg text-gray-600 mb-6">这里是一些最常用的 Docker 命令。你可以使用下方的搜索框快速过滤,并点击复制按钮复制代码。</p> <input type="text" id="command-search" placeholder="? 搜索命令,例如: run, ps, images..." class="w-full p-3 border border-gray-300 rounded-lg mb-8 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> <div id="command-list" class="grid md:grid-cols-2 gap-6"> <!-- Command cards will be injected here by JS --> </div> </div> </section> <!-- 动手实践 Section --> <section id="practice" class="content-section"> <div class="bg-white p-8 rounded-lg shadow-lg"> <h2 class="text-3xl font-bold mb-6 text-gray-900">4. 动手实践</h2> <div class="flex border-b mb-6"> <button class="practice-tab active px-6 py-3 font-semibold text-blue-600 border-b-2 border-blue-600" onclick="switchPractice(event, 'nginx')">案例一:运行 Nginx 服务器</button> <button class="practice-tab px-6 py-3 font-semibold text-gray-500" onclick="switchPractice(event, 'node')">案例二:构建 Node.js 应用</button> </div> <!-- Nginx Practice --> <div id="nginx" class="practice-content active"> <p class="text-lg text-gray-600 mb-6">光说不练假把式,让我们来动手运行一个 Nginx Web 服务器。请按照以下步骤操作。</p> <div class="practice-stepper" data-practice="nginx"> <div class="practice-step active" data-step="1"> <h4 class="text-xl font-bold mb-2">步骤 1: 拉取 Nginx 镜像</h4> <p class="mb-4">Nginx 是一个非常流行的开源 Web 服务器。我们先从 Docker Hub 上把它拉取到本地。</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-bash">docker pull nginx</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="practice-step" data-step="2"> <h4 class="text-xl font-bold mb-2">步骤 2: 运行 Nginx 容器</h4> <p class="mb-4">使用 `docker run` 命令来启动一个 Nginx 容器。我们通过 `-p` 参数将本机的 `8080` 端口映射到容器的 `80` 端口。</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-bash">docker run --name my-nginx-server -p 8080:80 -d nginx</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="practice-step" data-step="3"> <h4 class="text-xl font-bold mb-2">步骤 3: 验证结果</h4> <p class="mb-4">打开你的浏览器,访问 <a href="http://localhost:8080" target="_blank" class="text-blue-500 hover:underline">http://localhost:8080</a>。如果一切顺利,你应该能看到 Nginx 的欢迎页面!</p> </div> <div class="practice-step" data-step="4"> <h4 class="text-xl font-bold mb-2">步骤 4: 查看和清理</h4> <p class="mb-4">完成实验后,你可以使用以下命令来停止并删除容器。</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-bash"># 查看正在运行的容器 docker ps # 停止容器 docker stop my-nginx-server # 删除容器 docker rm my-nginx-server</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="mt-8 flex justify-between items-center"> <button class="prev-btn bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded" onclick="navigateStep('nginx', -1)" disabled>上一步</button> <span class="step-indicator text-gray-600">步骤 1 / 4</span> <button class="next-btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onclick="navigateStep('nginx', 1)">下一步</button> </div> </div> </div> <!-- Node.js Practice --> <div id="node" class="practice-content" style="display: none;"> <p class="text-lg text-gray-600 mb-6">现在,我们来尝试为自己的 Node.js 应用程序构建一个镜像。</p> <div class="practice-stepper" data-practice="node"> <div class="practice-step active" data-step="1"> <h4 class="text-xl font-bold mb-2">步骤 1: 准备应用程序文件</h4> <p class="mb-4">创建一个新文件夹,并在其中创建 `app.js` 和 `package.json` 两个文件。</p> <p class="mb-2 font-semibold">app.js</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-javascript">const http = require('http'); const os = require('os'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(`Hello from Docker! I'm running on host: ${os.hostname()}\\n`); }); server.listen(3000, () => { console.log('Server is running on http://localhost:3000'); });</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> <p class="mt-4 mb-2 font-semibold">package.json</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-json">{ "name": "my-node-app", "version": "1.0.0", "description": "A simple Node.js app for Docker tutorial", "main": "app.js", "scripts": { "start": "node app.js" } }</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="practice-step" data-step="2"> <h4 class="text-xl font-bold mb-2">步骤 2: 编写 Dockerfile</h4> <p class="mb-4">在应用文件夹中,创建一个名为 `Dockerfile` 的文件,并写入以下内容。这份文件描述了如何一步步构建你的应用镜像。</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-dockerfile"># 1. 选择一个基础镜像 FROM node:18-alpine # 2. 设置工作目录 WORKDIR /app # 3. 复制 package.json 并安装依赖 COPY package*.json ./ RUN npm install # 4. 复制应用程序的其余代码 COPY . . # 5. 暴露端口 EXPOSE 3000 # 6. 定义容器启动时执行的命令 CMD [ "npm", "start" ]</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="practice-step" data-step="3"> <h4 class="text-xl font-bold mb-2">步骤 3: 构建镜像</h4> <p class="mb-4">在你的终端中,确保路径位于应用文件夹内,然后运行构建命令。这会根据 Dockerfile 创建一个名为 `my-node-app:1.0` 的镜像。</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-bash">docker build -t my-node-app:1.0 .</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="practice-step" data-step="4"> <h4 class="text-xl font-bold mb-2">步骤 4: 运行我们自己的镜像</h4> <p class="mb-4">构建成功后,就可以运行我们自己的应用了!访问 <a href="http://localhost:3000" target="_blank" class="text-blue-500 hover:underline">http://localhost:3000</a> 查看结果。</p> <pre class="bg-gray-900 text-white p-4 rounded-lg relative"><code class="language-bash">docker run --name my-app-instance -p 3000:3000 -d my-node-app:1.0</code><button class="copy-btn" onclick="copyCode(this)">复制</button></pre> </div> <div class="mt-8 flex justify-between items-center"> <button class="prev-btn bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded" onclick="navigateStep('node', -1)" disabled>上一步</button> <span class="step-indicator text-gray-600">步骤 1 / 4</span> <button class="next-btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" onclick="navigateStep('node', 1)">下一步</button> </div> </div> </div> </div> </section> </main> </div> <script> const navLinks = document.querySelectorAll('.nav-link'); const contentSections = document.querySelectorAll('.content-section'); navLinks.forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const targetId = link.getAttribute('data-target'); navLinks.forEach(l => l.classList.remove('active')); link.classList.add('active'); contentSections.forEach(section => { section.classList.remove('active'); if (section.id === targetId) { section.classList.add('active'); } }); }); }); function toggleConcept (card) { const details = card.querySelector('.details'); details.classList.toggle('hidden'); } const commands = [ { cmd: 'docker run', desc: '从一个镜像创建一个新的容器并运行它。', example: 'docker run hello-world' }, { cmd: 'docker ps', desc: '列出当前正在运行的容器。使用 -a 查看所有容器。', example: 'docker ps -a' }, { cmd: 'docker images', desc: '列出本地已经下载或构建的镜像。', example: 'docker images' }, { cmd: 'docker pull', desc: '从仓库(默认是 Docker Hub)拉取一个镜像。', example: 'docker pull nginx:latest' }, { cmd: 'docker build', desc: '根据当前目录下的 Dockerfile 构建一个镜像。', example: 'docker build -t my-app .' }, { cmd: 'docker stop', desc: '停止一个正在运行的容器。', example: 'docker stop my-container' }, { cmd: 'docker start', desc: '启动一个已停止的容器。', example: 'docker start my-container' }, { cmd: 'docker rm', desc: '删除一个或多个容器。', example: 'docker rm my-container' }, { cmd: 'docker rmi', desc: '删除一个或多个本地镜像。', example: 'docker rmi my-image' }, { cmd: 'docker logs', desc: '获取容器的日志。', example: 'docker logs my-container' }, { cmd: 'docker exec', desc: '在运行的容器中执行命令。', example: 'docker exec -it my-container bash' }, ]; const commandList = document.getElementById('command-list'); const commandSearch = document.getElementById('command-search'); function renderCommands (filter = '') { commandList.innerHTML = ''; const filteredCommands = commands.filter(c => c.cmd.includes(filter.toLowerCase()) || c.desc.includes(filter.toLowerCase())); if (filteredCommands.length === 0) { commandList.innerHTML = `<p class="text-gray-500 md:col-span-2 text-center">未找到匹配的命令。</p>`; return; } filteredCommands.forEach(c => { const card = document.createElement('div'); card.className = 'command-card bg-gray-50 p-6 rounded-lg border border-gray-200'; card.innerHTML = ` <div class="flex justify-between items-center"> <h4 class="text-xl font-bold font-mono text-blue-600">${c.cmd}</h4> <button class="bg-gray-200 hover:bg-gray-300 text-gray-700 text-sm font-semibold py-1 px-3 rounded-md" onclick="copyToClipboard('${c.example}')">复制示例</button> </div> <p class="mt-2 text-gray-700">${c.desc}</p> <pre class="mt-4 bg-gray-200 text-gray-800 p-2 rounded-md text-sm font-mono">${c.example}</pre> `; commandList.appendChild(card); }); } commandSearch.addEventListener('keyup', (e) => { renderCommands(e.target.value); }); function copyToClipboard (text) { navigator.clipboard.writeText(text).then(() => { alert('示例命令已复制到剪贴板!'); }).catch(err => { console.error('无法复制文本: ', err); }); } function copyCode (button) { const pre = button.parentElement; const code = pre.querySelector('code').innerText; navigator.clipboard.writeText(code).then(() => { const originalText = button.innerText; button.innerText = '已复制!'; button.style.backgroundColor = '#10B981'; // green-500 setTimeout(() => { button.innerText = originalText; button.style.backgroundColor = '#4B5563'; // gray-600 }, 2000); }).catch(err => { console.error('无法复制: ', err); }); } renderCommands(); const practiceState = { nginx: { current: 1, total: 4 }, node: { current: 1, total: 4 } }; function switchPractice (event, practiceName) { document.querySelectorAll('.practice-tab').forEach(tab => tab.classList.remove('active', 'text-blue-600', 'border-blue-600')); event.target.classList.add('active', 'text-blue-600', 'border-blue-600'); document.querySelectorAll('.practice-content').forEach(content => content.style.display = 'none'); document.getElementById(practiceName).style.display = 'block'; } function navigateStep (practice, direction) { const state = practiceState[practice]; const newStep = state.current + direction; if (newStep >= 1 && newStep <= state.total) { state.current = newStep; updateStepUI(practice); } } function updateStepUI (practice) { const state = practiceState[practice]; const stepper = document.querySelector(`.practice-stepper[data-practice="${practice}"]`); stepper.querySelectorAll('.practice-step').forEach(step => step.classList.remove('active')); stepper.querySelector(`.practice-step[data-step="${state.current}"]`).classList.add('active'); stepper.querySelector('.step-indicator').textContent = `步骤 ${state.current} / ${state.total}`; const prevBtn = stepper.querySelector('.prev-btn'); const nextBtn = stepper.querySelector('.next-btn'); prevBtn.disabled = state.current === 1; nextBtn.disabled = state.current === state.total; } </script> </body> </html> ``` 最后修改:2025 年 08 月 27 日 © 允许规范转载 打赏 赞赏作者 微信 赞 0 如果觉得我的文章对你有用,请随意赞赏
此处评论已关闭