惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 最新话题
Cloudbric
Cloudbric
N
News and Events Feed by Topic
S
Secure Thoughts
Vercel News
Vercel News
S
Security @ Cisco Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - 聂微东
WordPress大学
WordPress大学
Google Online Security Blog
Google Online Security Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
PCI Perspectives
PCI Perspectives
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
Blog — PlanetScale
Blog — PlanetScale
Apple Machine Learning Research
Apple Machine Learning Research
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
博客园 - 司徒正美
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
A
About on SuperTechFans
P
Proofpoint News Feed
大猫的无限游戏
大猫的无限游戏
V
V2EX
I
Intezer
H
Hacker News: Front Page
www.infosecurity-magazine.com
www.infosecurity-magazine.com
L
Lohrmann on Cybersecurity
F
Fortinet All Blogs
Schneier on Security
Schneier on Security
博客园 - 叶小钗
The Cloudflare Blog
月光博客
月光博客
W
WeLiveSecurity
T
Tenable Blog
P
Proofpoint News Feed
aimingoo的专栏
aimingoo的专栏
Help Net Security
Help Net Security
L
LangChain Blog
C
CERT Recently Published Vulnerability Notes
T
The Exploit Database - CXSecurity.com
美团技术团队
B
Blog

szhshp 的第三边境研究所

假设, AI 把我代替的那一刻真的到来 | szhshp 的第三边境研究所 小傻瓜都能懂的 AstrBot QQ 机器人集成 MCP 功能实战指南 | szhshp 的第三边境研究所 《智人之上: 从石器时代到 AI 时代的信息网络简史》阅读笔记 | szhshp 的第三边境研究所 iPadOS 26 无法设置空间场景图片壁纸的解决方法 | szhshp 的第三边境研究所 《一路云海》(终) | szhshp 的第三边境研究所 《一路云海》(四): 如何不按套路旅行 | szhshp 的第三边境研究所 《一路云海》(三): In Ya Mellow Tone | szhshp 的第三边境研究所 《一路云海》(二): 关西世博参观纪实 | szhshp 的第三边境研究所 《一路云海》(一): 新的征程 | szhshp 的第三边境研究所 2025 大阪世博会 [ 3 天前-先到先得 ] 阶段 场馆预约必中独家攻略 | szhshp 的第三边境研究所 Hackathon 随想 | szhshp 的第三边境研究所 一杯双皮奶 | szhshp 的第三边境研究所 Armbian + CasaOS + NAS 配置指南 | szhshp 的第三边境研究所 Docker 构建镜像报错: error getting credentials - err: exit status 1, out: `` | szhshp 的第三边境研究所 Disqus RIP! 论过高的维护成本如何治疗固执的坏习惯 | szhshp 的第三边境研究所 炸弹猫桌游变体规则 | szhshp 的第三边境研究所 《小岛经济学》阅读笔记 | szhshp 的第三边境研究所 《金钱心理学》阅读笔记 | szhshp 的第三边境研究所 为知笔记 RIP: 迁移剩余的笔记 | szhshp 的第三边境研究所 2025 博客第十年展望 - 再见我的过去 | szhshp 的第三边境研究所 我在独立游戏里面致敬的作品 | szhshp 的第三边境研究所 《How to make thing faster》阅读笔记 | szhshp 的第三边境研究所 《The Art of Clean Code》阅读笔记 | szhshp 的第三边境研究所 《Clean Architecture: A Craftsman Guide to Software Structure and Design》阅读笔记 | szhshp 的第三边境研究所 《How AI Works》阅读笔记 | szhshp 的第三边境研究所 游戏策划废案 - Project Uranus | szhshp 的第三边境研究所 游戏策划废案 - Project X | szhshp 的第三边境研究所 人生第一款独立游戏开发复盘 | szhshp 的第三边境研究所 Trap of Life | szhshp 的第三边境研究所 如果我用手搓了个暗物质雏形 | szhshp 的第三边境研究所 《Rust Programming Language》- EX - Cheatsheet | szhshp 的第三边境研究所 新的播放器上线了 | szhshp 的第三边境研究所 Cypress - End-to-End Testing: OKTA Authentication with MFA | szhshp 的第三边境研究所 VSC x VIM - 反正多学几个快捷键没有坏处 | szhshp 的第三边境研究所 《The Joy of Javascript》- 5 - Data | szhshp 的第三边境研究所 《The Joy of Javascript》- 4 - Meta Programming | szhshp 的第三边境研究所 《The Joy of Javascript》- 3 - ADT(Algebraic Data Type) | szhshp 的第三边境研究所 Web-Automation Testing | szhshp 的第三边境研究所 《The Joy of Javascript》- 2 - Functor/Monad | szhshp 的第三边境研究所 《The Joy of Javascript》- 1 - Object/Function | szhshp 的第三边境研究所 EvalError: Possible side-effect in debug-evaluate | szhshp 的第三边境研究所 前端 QA 工具链指南 - husky,commitlint,commitizen,eslint,typescript,express | szhshp 的第三边境研究所 效率工具 & 软件推荐 | szhshp 的第三边境研究所 站点开源 Project Titan | szhshp 的第三边境研究所 cmd/powershell-命令速查-Cheatsheet | szhshp 的第三边境研究所 Git-命令速查与相关问题解决-Cheatsheet & Troubleshooting | szhshp 的第三边境研究所 Tailwind.css not included in NextJS Production | szhshp 的第三边境研究所 Github GraphQL API - Data Integration | szhshp 的第三边境研究所 尝试 Windows Terminal + z.lua | szhshp 的第三边境研究所 StrokePlus.net - Powerful Hotkey Boost | szhshp 的第三边境研究所 优雅地 Hack 一台黑苹果 | szhshp 的第三边境研究所 一杯关东煮 | szhshp 的第三边境研究所 Gitee x PicGo 管理图床 | szhshp 的第三边境研究所 Create Your Own Redux (Typescript) | szhshp 的第三边境研究所 Getting Started: Ionic + Capacitor + React + Typescript + Android | szhshp 的第三边境研究所 GraphQL: File Upload & Troubleshooting | szhshp 的第三边境研究所 吉祥航空随心飞刷票工具循环查票工具 | szhshp 的第三边境研究所 NVM Windows Portable Installation | szhshp 的第三边境研究所 NextJS x Typescript - Integration & Troubleshooting | szhshp 的第三边境研究所 全站点升级 - Project Titan | szhshp 的第三边境研究所 AWS-EC2-常见问题解决-Troubleshooting | szhshp 的第三边境研究所 Workbox-Getting Started | szhshp 的第三边境研究所 《时间简史》阅读笔记 | szhshp 的第三边境研究所 《时间的秩序》阅读笔记 | szhshp 的第三边境研究所 ESLint-常见问题解决-Troubleshooting | szhshp 的第三边境研究所 站点索引 | szhshp 的第三边境研究所 个人知识库搭建 - Hexo 实现 Github/Coding 持续集成 | szhshp 的第三边境研究所 BMOB-常见问题解决-Troubleshooting | szhshp 的第三边境研究所 React + Typescript: 开启 HMR/Hot Loader | szhshp 的第三边境研究所 Yarn & NPM | szhshp 的第三边境研究所 ESLint: Typescript + React + TSX 集成 | szhshp 的第三边境研究所 《10101》EP15:过年 2020 | szhshp 的第三边境研究所 Cmder-Usage | szhshp 的第三边境研究所 Redux-DOM not refreshed | szhshp 的第三边境研究所 React Semantic UI-CheatSheet | szhshp 的第三边境研究所 Typescript: Getting Started | szhshp 的第三边境研究所 Flutter-Getting Started | szhshp 的第三边境研究所 Typescript: Access window object with type check | szhshp 的第三边境研究所 VSC Extension Development-Create A Code Formatter Extension | szhshp 的第三边境研究所 OneNote Extension-Main API | szhshp 的第三边境研究所 TortoiseGit Win10 Icon not showing correctly | szhshp 的第三边境研究所 Mongoose: aggregate() 方法实现聚合函数 | szhshp 的第三边境研究所 React In Depth - React 源码解析 - render() & Fiber | szhshp 的第三边境研究所 MongoDB x Mongoose: 实现类似 Join 的功能 | szhshp 的第三边境研究所 Disqus 评论框改造工程-实现 Disqus 代理的 Serverless 服务 | szhshp 的第三边境研究所 GUI, CLI, Terminal, Shell, TTY, Console, Bash | szhshp 的第三边境研究所 Jest Async Best Practise: No Nested Async | szhshp 的第三边境研究所 关系型数据库与非关系型数据库优缺点分析 | szhshp 的第三边境研究所 New Edge & Chromium Error - Package is invalid: 'CRX_VERSION_NUMBER_INVALID' | szhshp 的第三边境研究所 选择 GraphQL 的 N 个理由 | szhshp 的第三边境研究所 StrokePlus - 鼠标手势神器的代码编写技巧 | szhshp 的第三边境研究所 嗨,好久不见 | szhshp 的第三边境研究所 Vue + ElementUI 集成 Vue Router | szhshp 的第三边境研究所 IE8 - Unknown Runtime Error Using innerHTML & Ajax | szhshp 的第三边境研究所 React: Handling Events | szhshp 的第三边境研究所 React-Navigation Integration with Redux | szhshp 的第三边境研究所 React: States is tricky | szhshp 的第三边境研究所 《10101》EP14:小剧场 | szhshp 的第三边境研究所 ColdFusion - Basic - arguments in cffunction | szhshp 的第三边境研究所 ColdFusion - Basic - cfset | szhshp 的第三边境研究所
两小时 Docker 速成 - Getting Started | szhshp 的第三边境研究所
2022-08-08 · via szhshp 的第三边境研究所

Meta

目录

Docker: Getting Started

Why Docker?

  • 开发团队与运维团队之间经常互相扯皮, 主要原因是环境和配置有一定的不同
    • 比如公钥秘钥, 各类环境变量
    • 对于多个集群, 运维需要重复安装很多环境, 最麻烦的是有一些项目会用到不同版本的环境
  • Docker 可以将一部分 代码/配置/系统/环境变量/数据 等等一系列东西全部包含进去
    • Docker Image 甚至可以把软件也一起安装
    • 从此以后提交给运维的就是一个完全打包好的镜像
  • 对比以前的虚拟技术
    • 传统虚拟机 (e.g. VirtualBox)
      • 虚拟一套硬件
        • 在宿主机里面还模拟了虚拟机的内核和底层
      • 启动慢, 占用高, 步骤多
    • Docker
      • 一次构建随处运行
      • 使用 Linux 容器虚拟化
      • 更少的抽象层: 容器内没有自己的内核, 直接使用宿主机的内核
      • 容器之间相互隔离

Concept

dockerfile + 源码 是原材料, image 是交付品, container 是运行实例

  • Docker
    • 是运行的载体以及管理引擎, 所有的操作都通过 Docker Daemon 处理
  • Image
    • 实际上就是一个模板, 一般来说是只读的模板
    • 打包好的环境一般就是一个镜像文件
    • 通过这个镜像生成 Docker 容器
  • Container
    • Image 实例化后的一个实例
    • 单个 Container 可以单独启动/关闭/停止/删除
    • 可以把容器看成一个简易版的 Linux 环境 + 运行在其中的应用程序
  • Repository
    • 实际上就是 Image 的内容
    • DockerHub 是最大的公开仓库
    • 国内可以使用阿里云和网易云的镜像

Installation

Install Docker Engine on Ubuntu | Docker Documentation

Ubuntu

基于 EC2, Ubuntu 20.04

sudo apt install docker.io

Cheatsheet

# 手动进入容器
sudo docker run -it [IMAGE] /bin/bash
# 一些情况下 bash 不够用, 改为 sh
sudo docker run -it [IMAGE] /bin/sh

Usage

docker —help 检查所有命令

docker run

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

docker run hello-world

# -i 交互模式运行, -t 分配一个伪输入终端, 一般一起使用
docker run -it centos
docker run -it centos --name mycentos
# 启动终端并执行自定义命令
docker run -it centos npm run dev

# 后台运行, 不弹出交互窗口也不切换
# 后台运行必须有一个持续的进程, 不然就会自动退出
docker run -d

# 打开一个新终端, 运行 tomcat
# -p 将 8080 映射到 8080
# [外部 DOCKER PORT]:[内部 IMAGE PORT]
docker run -it -p 8080:8080 tomcat

# -P 随机分配端口, 启动后可能直接看不到端口, 需要 docker ps 来查看
docker run -P tomcat
docker ps

# 携带环境变量
docker run --env VAR1=value1 --env VAR2=value2 ubuntu

默认会下载 latest 版本, 可以带上特定的 tag: docker run hello-world:latest

  1. 检查本地是否存在这个 hello-world image, 如果有, 实例化产生 container 并运行
  2. 如果没有, 就会去默认 registry 拉取下来, 如果可以找到, 那么拉下来, 实例化产生 container 并运行

docker image

# 列出本地所有镜像
docker images

# 列出本地所有镜像 包括中间层
docker images -a

# 列出本地所有镜像 ID
docker images -aq
# 到 dockerhub 搜索镜像关键字
docker search tomcat

docker rm/rmi

# 删除一个本地的镜像, 但是如果有容器正在使用, 将不会删除
docker rmi hello-world

# 删除多个镜像
docker rmi a:latest b:latest c d e f
docker rmi -f ${docker ps -a -q}

# 删除容器, 注意不带 i 就是删除容器, 带了 i 就是删除镜像
docker rm

# 删除多个容器
docker rm -f ${docker ps -a -q}
docker ps -a -q | xargs docker rm

docker pull

# 下载一个 image
docker pull centos

# 检查已经下载的 images
docker images

docker ps

# 列出当前 docker 所有正在运行的 container, 注意不是 image
docker ps

# 列出当前正在运行的, 以及以前历史运行过的. 这个地方可以通过状态来识别是否已经在运行. 
docker ps -a

# 列出上一次运行的 container
docker ps -l

# 列出最近 50 个 container
docker ps -n 50

exit

# 退出容器, 终止容器并退出
exit

# 不中止容器并退出
(Ctrl+P+Q)

docker start/restart/stop/kill

docker start [CONTAINER/NAME]
docker restart [CONTAINER/NAME]

# 自然关闭
docker stop [CONTAINER/NAME]

# 强制停止
docker kill [CONTAINER/NAME]

docker logs

# 查看日志, -t 包含时间戳, -f 跟随显示, --tail 默认尾部全部
docker logs -f -t --tail [CONTAINER]

docker logs -f -t --tail 3 [CONTAINER]

docker top

# 查看容器内运行的进程
docker top [CONTAINER]

docker inspect

# 查看容器内运行的细节
docker inspect [CONTAINER]

docker exec/attach

# 进入容器
docker attach [CONTAINER]

# 不进入容器就在容器中执行 ls -l /tmp, 并将结果返回宿主机
docker exec [CONTAINER] ls -l /tmp

docker cp

# 将容器内的 /tmp/test.log 拷贝到宿主机的 /root 文件夹
docker cp [CONTAINER]:/tmp/test.log /root

docker build

# 注意结尾有一个点符号
docker build -t [IMAGE_NAME]:TAG .

# -f [DOCKER_FILE] 如果不添加的话就会自动寻找文件名为 Dockerfile 的文件
docker build -f [DOCKER_FILE] -t [IMAGE_NAME]:TAG .

Other commands

# 提交 container 副本令其成为一个新的 image
docker commit

# 列出镜像历史
docker history

Docker Image Architecture

镜像是一个 UnionFS (联合文件系统): 实际上是一种分层的, 高性能的, 轻量级的文件系统, 它支持对文件系统的修改作为一次提交来一层层叠加

一个 Image 可能引用了多个其他的镜像, 并且引用的镜像可以被多个 Image 引用 (类似 npm -g 的模式)

  • 最底层是 bootfs (boot file system): 主要包含 bootloader 和 kernel
  • 上一层是 rootfs (root file system): 在 bootfs 之上, 包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件, rootfs 就是不同操作系统的发行版
    • rootfs 相比其他系统的发布包来说会小很多, 因为只需要包含最基本的命令工具以及程序库就可以. 毕竟底层直接使用 host 的内核.

Data Volume Containers

一般来说, 容器里面产生的内容和数据在容器关闭之后会直接消失. 然后就需要将一些数据保存出来做持久化.

可以使用的方式:

  1. 直接命令添加
  2. dockerfile

docker run -v

# 如果对应的 path 没有会自动生成, 可以让 container 内部的一个 path 和外部 host 的一个 path 建立 binding
docker run -it -v [HOST_PATH]:[CONTAINER_PATH] [IMAGE]

# 添加多个 binding
docker run -it -v [HOST_PATH]:[CONTAINER_PATH] -v [HOST_PATH]:[CONTAINER_PATH] [IMAGE]

# 建立 binding 之后使用 inspect 可以从 HostConfig.Binds 里面找到
docker inspect [CONTAINER]

# 限定权限的模式, :ro 代表 read only
docker run -it -v [HOST_PATH]:[CONTAINER_PATH]:ro [IMAGE]

Volume From

# 首先创建一个容器
docker run -it --name CONTAINER_1 [IMAGE]

# 然后在容器里面创建一些文件

# 根据相同的 Image 但是根据 CONTAINER_1 进行扩展
docker run -it --volumes-from CONTAINER_1 --name CONTAINER_2 [IMAGE]

随后两个 CONTAINER 里面会有相同的文件, 在其中任何一个 CONTAINER 里面修改会影响另一个

数据卷的生命周期持续到所有 CONTAINER 的引用消失为止

比如: 此时创建 CONTAINER_3, 然后做一些修改, 然后删除 CONTAINER_1 和 CONTAINER_2, CONTAINER_3 里面依然可以看到修改

Dockerfile

Usage

使用 dockerfile 的主要步骤:

  1. dockerfile: 编写一个 dockerfile
  2. docker build: 构建的时候引用这个 dockerfile, 生成 image
  3. docker run: image 随后可以构建 container

可以看见在多数情况下, 只有构建的时候会使用到这个 dockerfile

特性:

  • 指令结构: 一段大写的单词后面带上一堆参数
  • 从上到下执行
  • 每一条指令都会新建一个镜像层, 并且对镜像进行提交
  • 执行完毕后会提交一个新的镜像层, 并且给予刚提交的镜像运行一个新的容器

Reference

  • FROM
    • 设置一个初始的镜像, 在这个镜像上扩展
    • scratch 代表最原始的镜像
  • WORKDIR
    • 设置在镜像里面的工作目录
  • ADD/COPY
    • 将宿主机目录下的文件拷贝进镜像
    • ADD 命令比 COPY 多一个步骤, 会自动处理 URL 和解压 tar 压缩包
  • VOLUME
    • 用于数据保存和持久化
    • 会在容器里面创建新的
  • CMD
    • 格式
      • shell 格式: CMD <Command>
      • exec 格式: CMD ["executable file", "arg1", "arg2", ...]
    • Dockerfile 中多个 CMD 只会执行最后一个
      • 一般会在 dockerfile 末尾加一段 CMD 命令, 使得不带参数跑 docker run 的时候运行这段 CMD 命令
      • docker run [IMAGE] 就会默认执行最后一段 CMD
      • docker run [IMAGE] npm run dev 忽略原本 dockerfile 中的 CMD 并执行 npm run dev
  • ENTRYPOINT
    • 和 CMD 类似, 区别在于这个是一定执行不会有替换最后一段 CMD 的情况, 并且会追加组合对应的命令
    • ENTRYPOINT 的好处:
      • 如果在 dockerfile 中设定了 CMD ["npm", "run", "dev"] 随后想要在 docker run 的时候就无法给最后一段 CMD 添加额外参数
        • CMD ["npm", "start"] + docker run [IMAGE] -iCMD ["npm", "-i", "start"]
        • 这个时候必须使用 docker run 执行完整的命令或者重新 build container
      • 但是 ENTRYPOINT 可以实现
        • ENTRYPOINT ["npm", "start"] + docker run [IMAGE] -i = ENTRYPOINT ["npm", "-i", "start"]
  • ONBUILD
    • 当 build 一个继承镜像的时候触发, 父镜像在被子镜像继承后触发父镜像的 onbuild
  • ENV
    • 环境变量

Example 1

一个简单的 dockerfile:

FROM centos
VOLUME ["/folder1", "/folder2"]
CMD echo "Done"
CMD /bin/bash

然后 build 一个新的 image

# 注意尾部有一个点用于当前目录
docker build -f [DOCKERFILE] -t [IMAGE_NAME] . 

# 然后 docker run 跑起一个新的 container
# 新的 container 里面就会带上 folder1 和 folder2 两个目录
docker run -it [IMAGE]

# 需要注意的是, 就算这里没有使用 -v 来 bind host 的目录, docker 依然会生成一个目录用于数据持久化, 这个自动生成的逻辑只有通过 dockerfile 才会执行

Example 2

FROM centos
ENV mypath /tmp # 设置一个环境变量
WORKDIR $mypath # 设置容器内的工作目录, 设定到 /tmp

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD /bin/bash

Example 3

dockerfile1

FROM centos
ONBUILD RUN echo "this is father image" # 父镜像的 ONBUILD

假设使用上方 dockerfile 构建了一个镜像 centos1 : docker build -f dockerfile1 -t centos1 .

然后编写一个新的 dockerfile:

dockerfile2

FROM centos1 # 继承刚才创建的镜像

创建一个新的镜像: docker build -f dockerfile2 -t centos2 .

这个时候就会触发父镜像里面的 ONBUILD

Troubleshooting

RUN 命令没有显示输出

加上一段参数即可

docker build -t hello-world ./ --progress=plain --no-cache