|
Docker实操过程
体会
知乎上搜“docker入门”搜到的笔记总是起一个赚噱头的标题,然后点进去一看,里面大多是一些入门内容的简单罗列,要么对于背景内容长篇大论让读者抓不住重点,要么对于命令API简单罗列,入门者甚至连这些API如何衔接使用,这些命令大概发生了什么可能都没有概念,说是入门教程,实际跟着实操之后依然云里雾里。
链接
个人比较欣赏的入门教程是这个:Docker超详细教程 | 观星客 (chasonlee.github.io)
其中概念性介绍足够精炼,同时能说明核心的概念,而且实操部分足够详细,从例子讲起。
更新:该地址已经失效。
个人思考
下面是自己在实操后对一些更具体内容的思考补充。
关于DockerDesktop界面
如上图,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-world
- Hello 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 the
- executable that produces the output you are currently reading.
- 4. The Docker daemon streamed that output to the Docker client, which sent it
- to your terminal.
- To try something more ambitious, you can run an Ubuntu container with:
- $ docker run -it ubuntu bash
- Share 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 images和docker ps来查看现有的镜像和对应的容器以及ID,名称等
- (base) C:\Users\80563\Desktop>docker run hello-world
- Hello 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 the
- executable that produces the output you are currently reading.
- 4. The Docker daemon streamed that output to the Docker client, which sent it
- to your terminal.
- To try something more ambitious, you can run an Ubuntu container with:
- $ docker run -it ubuntu bash
- Share 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中也可看到容器的命令行输出。
一个综合的例子
如上是我在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导入。
来源:https://www.cnblogs.com/isshiki-iroha/p/18443011
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|