Docker实操过程

news/2024/12/24 4:32:18/文章来源:https://www.cnblogs.com/isshiki-iroha/p/18443011

Docker实操过程

体会

知乎上搜“docker入门”搜到的笔记总是起一个赚噱头的标题,然后点进去一看,里面大多是一些入门内容的简单罗列,要么对于背景内容长篇大论让读者抓不住重点,要么对于命令API简单罗列,入门者甚至连这些API如何衔接使用,这些命令大概发生了什么可能都没有概念,说是入门教程,实际跟着实操之后依然云里雾里。

image

链接

个人比较欣赏的入门教程是这个:Docker超详细教程 | 观星客 (chasonlee.github.io)

其中概念性介绍足够精炼,同时能说明核心的概念,而且实操部分足够详细,从例子讲起。

更新:该地址已经失效。

个人思考

下面是自己在实操后对一些更具体内容的思考补充。

关于DockerDesktop界面

image

如上图,Docker Desktop安装好后,第一个镜像应该是hello-world。稍后我们会用一下它。我个人的感受是先不要用Docker Desktop的可视化界面创建和操作镜像和容器,应该用命令行,多敲命令能更清楚地发现发生了什么,也能更明晰地感受到docker命令执行之后有一个什么结果。Docker Desktop可以作为已有镜像和容器的可视化展示。

上图中,Images镜像,Containers容器,镜像是容器的模板,容器是镜像的实例。镜像与容器好比C++中类与对象。所以同一个镜像可以有多个实例。

镜像或者是容器如何指定?一种是名字,一种是ID。镜像的名字就是Name:Tag的格式,如上图中的hello-world:latest。容器的名字通常就是创建它时指定的名字,用docker ps -a通常都可以看到。而不管是容器还是镜像,ID就是它创建时被分配的唯一hash码,如上图中的9c7a54a9a43c

可视化展示就不多做截图,下面以命令行为主。主打解释一个命令的诸多细节与效果

关于Docker命令行

(base) C:\Users\80563\Desktop>docker pull chasonlee/ubuntu_demo:latest
latest: Pulling from chasonlee/ubuntu_demo
9ff7e2e5f967: Pull complete
59856638ac9f: Pull complete
6f317d6d954b: Pull complete
a9dde5e2a643: Pull complete
583e635329f1: Pull complete
d74dae086c4f: Pull complete
Digest: sha256:f4396916a5cbb3ece8e5eb74a860d956b8957965675d5dde707ed4f316407b8c
Status: Downloaded newer image for chasonlee/ubuntu_demo:latest
docker.io/chasonlee/ubuntu_demo:latest(base) C:\Users\80563\Desktop>
  • docker pull拉取镜像
  • chasonlee/ubuntu_demo:latest正是之前的镜像指定格式
(base) C:\Users\80563\Desktop>docker image ls
REPOSITORY              TAG       IMAGE ID       CREATED        SIZE
hello-world             latest    9c7a54a9a43c   6 months ago   13.3kB
chasonlee/ubuntu_demo   latest    59693b89568e   4 years ago    158MB(base) C:\Users\80563\Desktop>docker images
REPOSITORY              TAG       IMAGE ID       CREATED        SIZE
hello-world             latest    9c7a54a9a43c   6 months ago   13.3kB
chasonlee/ubuntu_demo   latest    59693b89568e   4 years ago    158MB(base) C:\Users\80563\Desktop>docker ps -a
CONTAINER ID   IMAGE                             COMMAND                   CREATED          STATUS          PORTS                  NAMES
44ebbb32efae   docker/welcome-to-docker:latest   "/docker-entrypoint.…"   31 seconds ago   Up 31 seconds   0.0.0.0:8088->80/tcp   welcome-to-docker
  • docker image ls或者docker images查看镜像
  • docker ps或者docker ps -a查看容器,前者只显示运行中的,后者显示所有的,包括已经停止的
(base) C:\Users\80563\Desktop>docker images
REPOSITORY              TAG       IMAGE ID       CREATED        SIZE
hello-world             latest    9c7a54a9a43c   6 months ago   13.3kB
chasonlee/ubuntu_demo   latest    59693b89568e   4 years ago    158MB(base) C:\Users\80563\Desktop>docker run --rm hello-worldHello from Docker!
This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/(base) C:\Users\80563\Desktop>docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
  • docker images查看有什么镜像,然后根据具体名字运行hello-world(组合招),因为实际中经常记不清具体名字。
  • 根据自带hello-world镜像创建一个容器并运行。
  • 图中这个容器的实际内容就是打印这段文字然后直接结束。
  • --rm表示这个容器如果stop,那就立即删除这个容器,而不是留着。如果没有--rm,那么就会留着这个容器。
  • docker ps显示确实没有了该镜像的容器实例。
  • 可以经常使用docker imagesdocker ps来查看现有的镜像和对应的容器以及ID,名称等
(base) C:\Users\80563\Desktop>docker run hello-worldHello from Docker!
This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/(base) C:\Users\80563\Desktop>docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS                     PORTS     NAMES
a70726ad972b   hello-world   "/hello"   2 minutes ago   Exited (0) 2 minutes ago             amazing_lumiere
  • 没有加--rm的后果

  • 运行完容器,它已经停止(Exited),但是因为没有--rm所以还留着。此时要docker rm a70726ad972b或者docker rm amazing_lumiere手动删除

  • NAMES是amazing-lumiere是因为创建容器时如果不指定容器名(--name),就会自动给一个

  • -it是什么意思:i是交互模式(将当前命令行的终端输入输出接入容器的输入输出),t是伪终端,二者通常结合使用。

  • -d是后台运行的意思,有了这个参数,执行命令后不会将当前命令行转为容器中的命令行,而是只输出创建容器所分配的ID。之后再想进去(必须是容器已经在运行中)可以用docker attach ID

    • ID当然也可以写ContainerName
    • 实际上docker attach ID 的方法并不推荐,因为这样的话当前终端结束会导致该容器一同停止
    • 推荐的用法是exec,个人觉得叫“切入”比较贴切,即临时启动一个终端,让该(已经运行的该容器,如果没有运行需要先docker start ID 运行)执行一条命令,作为当前终端的启动任务,例如
      • docker exec a70726ad972b /bin/bash
      • 这样当前终端退出后不会导致该容器的停止
  • docker exec是针对已存在的容器的,docker run是针对镜像的。

  • Docker Desktop中,容器的log中也可看到容器的命令行输出。

一个综合的例子

image

如上是我在windows上开发的一个项目,这个项目的启动方式是在nl2sql_server_load/ 根目录下运行python -m app_nl2sql_server.app_server来启动。现在需要为它配一个镜像打包到linux服务器上去运行。

首先在项目根目录下放上requirements.txt,写上依赖包

Flask==3.0.3
mysql-connector-python==8.4.0
numpy==1.26.4
pandas==2.2.2
portalocker==2.8.2
pynvml==11.5.0
Requests==2.32.3
tabulate==0.9.0
vanna
vanna[chromadb,openai,mysql]
openpyxl
fastapi
sse_starlette
aiohttp

然后需要在项目根目录下放上Dockerfile ,里面写上(注意看里面的注释)这些指令

FROM robd003/python3.10:latest
# 其实对于部署来说
# 用 FROM python:3.10-slim 会专业
# 因为这个slim更精简,体积更小
# 而我这个后来打完镜像发现有1-2G了# 将当前工作目录设置为 /app/nl2sql_server_load
# 后面的命令也都将会在WORKDIR上执行,包括你进去容器时也是
WORKDIR /app/nl2sql_server_load# 复制当前目录(也就是项目根目录)的内容到当前工作目录
# 此时当前工作文件夹为WORKDIR,也就是 /app/nl2sql_server_load
# 第一个句点表示宿主机的当前目录,第二个是容器的当前目录
COPY . .
# 以下是一个小BUG,与本次例子关系不大
# COPY ./nl2sql_server_load/ /app/
# 不要像上面这样写,这样写只会把当前目录下的nl2sql_server_load文件夹的【内容】复制到/app中
# 而不会把这个文件夹作为子文件夹复制过去
# 要把该文件夹复制过去,应该写
# COPY ./nl2sql_server_load/ /app/nl2sql_server_load# 安装所需的 Python 包
# RUN和下文的CMD不同,RUN作用于构建镜像时,
# 而CMD是在启动每一个由该镜像创建的容器时的默认启动命令,
# 即docker run <image_name>时的启动命令
RUN pip install --no-cache-dir -r nl2sql_server_load/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 那么对于这个CMD指令,如果想(根据镜像)启动容器并且不执行默认的启动命令,应该写
# docker run -it --entrypoint /bin/bash <image_name>
# 表示把/bin/bash作为本次该镜像创建的容器的启动命令,而不是默认的命令# 暴露应用运行的端口
EXPOSE 63000# 启动服务
# CMD python -m app_nl2sql_server.app_server
# 现实还是很难一步到位,
# 后来我实操发现还有bug,不能跑起来,所以这句其实没必要写
# 应该在创建并运行容器,在容器里面debug完成确认能跑起来再手动在容器中启动

然后在项目根目录下用该Dockerfile来构建镜像:

docker build -t oms:v1 .

也就是说,假设你有一个名为nl2sql_server_load的项目根目录,其中包含了一个Dockerfile,你想要基于这个Dockerfile创建一个新的镜像,并将其标记为oms,标签为v1。这里的.表示当前目录,也就是包含Dockerfile的目录。

构建完成之后,就可以基于该镜像创建容器

docker run -it --entrypoint /bin/bash -p 127.0.0.1:63000:63000 --name oms2 oms:v1

注意镜像名称要放在最后,不然不行。

注意该命令设置的端口映射。

这个时候就进去了容器,可以装些必要东西,然后再手动运行项目。

检查确认项目成功跑起来之后,可以根据该容器导出镜像文件

docker export oms2 -o container_backup.tar

然后把该.tar文件传到服务器上,再在服务器上用docker导入成镜像

docker import container_backup.tar oms:v2

就可以在服务器上用该镜像创建容器了。

docker run -it --entrypoint /bin/bash -p 127.0.0.1:63000:63000 --name oms2 oms:v2

备注:为什么要先写dockerfile构建镜像,由该镜像创建了容器,再由容器导出镜像文件,再传到服务器上用docker引入该镜像?有两个原因,一是dockerfile创建的镜像oms:v1所创建的容器并不一定直接可用,中间可能有bug。这个时候改完bug的容器相对于oms:v1来说已经有了一个更新。所以应该基于这个最新的容器导出成镜像。第二是服务器不连网,不能直接在服务器上用dockerfile来构建镜像。只能把镜像先打包好再传到服务器上用docker导入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/806674.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谷歌收录批量查询,教你批量查询谷歌收录的方法

批量查询谷歌收录是网站管理员和SEO人员常见的需求,以下是一些实用的方法和步骤来实现这一目标: 一、使用Google Search Console(谷歌搜索控制台) 注册并验证网站:首先,在Google Search Console中注册并验证你的网站。这是获取网站在谷歌搜索结果中详细数据的基础。 下载…

修改Nacos2.4.1源码-适配达梦数据库麒麟ARM系统(国产XC化)

前言:应集团公司现在推广XC化,其中基础环境需要用麒麟ARM操作系统和达梦数据库,而官网的nacos默认适配mysql,需要重新编译源码来适配需要对接的数据库,2.4.2试验了一把,安装启动后 nacos 控制台出现 “创建命名空间失败 / 数据库语法问题”,经分析,问题出在源码的sql语…

怎么查看网站是否被谷歌收录,你会查看网站被谷歌收录的方法吗

查看网站是否被谷歌收录是一个相对简单的过程,以下是几种常用的方法,可以帮助你确定网站或其特定页面是否已被谷歌搜索引擎索引: 一、使用“site:”搜索指令 打开谷歌搜索引擎(Google)。 在搜索框中输入“site:你的网站域名”(注意使用英文冒号,并将“你的网站域名”替换…

操作系统:保护模式(二)内存模型

平坦内存模型 现代操作系统一般不会使用过于复杂的分段机制,而是采用平坦内存模型 + 分页模型来管理内存。 平坦内存模型(Flat Memory Model),这是现代操作系统(如 Linux 和 Windows)常用的内存模型。在这种模型中,所有段的段基址都为 0,段界限为 4GB,使得整个内存空间…

操作系统:保护模式(五)特权

特权机制 特权特权级数值越大,级别越小。通常,因为操作系统是为所有程序服务的,可靠性最高,而且必须对软硬件有完全的控制权,所以它的主体部分必须拥有特权级0,并处于整个环形结构的中心。也正是因为这样,操作系统的主体部分通常又被称做内核(Kernel、 Core)。 特权级1和…

操作系统:保护模式(一)GDT 与分段机制

GDT 与分段机制 CPU开机时运行于实模式,寻址方式是段寄存器 \(\times\) 10+偏移寄存器=物理地址,主要原因是因为 8086 地址线和数据线不匹配导致的。但是这种寻址方式既不安全也不支持现代操作系统所需的、多任务支持、cpu 特权模式等。 在实模式下,对于基址,变址寻址的寄存…

CSP2024-30

A 题意:将一个圆等分为 \(K\) 分,给出其中 \(n\) 个等分点的编号,\(x_i < x_{i + 1}\)。 有向边 \(i \to j\) 存在,当且仅当 \(j\) 是距离 \(i\) 最大的点(不唯一),且与图中其他边无交点(端点不算)。 求图中最多有多少条边。\(3 \le K \le 10^9, 3 \le n \le \min(…

小白上手Arcgis—用于结合Netlogo、matlab等进行复杂网络操作

小白上手Arcgis(Netlogo复杂网络数据预处理) 1.前言废话:昨天突然想到可以写一下博客,用来记录一下自己的工作,主要是涉及复杂网络方面。情况简介:本人Arcgis小白,之前只是略微知道有这么个软件,以及知道怎么打开软件。学渣一个,而且不是学gis方向的,但由于工作需要,要…

windows10如何安装jdk8,并且配置java home环境?超详细!

前言 大家好,我是小徐啊。记得我刚学习Java的时候,我的老师第一步就是教我们如何安装jdk并且配置java环境。这应该算是学习Java的第一步吧。虽然这个安装过程对我来说已经不是非常难了,但是我知道,对于一些刚入门的小伙伴还是经常容易搞错的,所以,今天小徐就写一篇详细的…

安装小雅问题

如何卸载重装小雅、apt remove xiaoya docker stop 01ec8396b2c529819bb7c95091a88a9af6999c042bcb7ab57662837c97dca5cd docker rm 01ec8396b2c529819bb7c95091a88a9af6999c042bcb7ab57662837c97dca5cdsystemctl start cpolar 开启cplpr systemctl status cpolar

leetcode24 两两交换链表中的节点(swap-nodes-in-pairs)

题目描述: 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1:输入:head = [1,2,3,4] 输出:[2,1,4,3]示例 2: 输入:head = [] 输出:[]示例 3: 输入:head = [1] 输出:[…

第一章:Borel测度

第1章 Borel测度 在正式讨论我们的内容之前我们先做几点说明 1.我们只讨论\(\mathbb{R}^n\) 上的测度,因此如果不作特别说明,我们均认为测度和集合为于\(\mathbb{R}^n\) 中: 2.我们不特别区分外测度和测度,因为将外测度限制在可测集上就是可测集上的测度: 3.我们默认读者已…