Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docker学习 #284

Closed
isaaxite opened this issue Oct 27, 2022 · 13 comments
Closed

docker学习 #284

isaaxite opened this issue Oct 27, 2022 · 13 comments

Comments

@isaaxite
Copy link
Owner

isaaxite commented Oct 27, 2022

Table Of Content

目标

创建node镜像,安装与node10版本有兼容问题的npm报。将此node镜像运行的node v10环境下,访问镜像里面的资源

  • centos7环境安装docker;
  • docker的基础使用;
  • 创建镜像
  • 使用镜像

docker的基础使用

启动docker

$ sudo systemctl enable docker
$ sudo systemctl start docker

image

测试docker

docker run --rm hello-world

image

常见docker命令

  • --rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间
docker run -it --rm ubuntu:18.04 bash

docker基本命令释义

image

运行交互式的容器

使用 -it 命令

-t: 在新容器内指定一个伪终端或终端。

-i: 允许你对容器内的标准输入 (STDIN) 进行交互。

使用镜像

docker run -t -i <REPOSITORY>:<TAG> /bin/bash

# exp
docker run -t -i ubuntu:15.10 /bin/bash 

使用 docker images 列出本机上的镜像

$ docker images           
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              14.04               90d5884b1ee0        5 days ago          188 MB
php                 5.6                 f40e9e0f10c8        9 days ago          444.8 MB
nginx               latest              6f8d099c3adc        12 days ago         182.7 MB
mysql               5.6                 f2e8d6c772c0        3 weeks ago         324.6 MB
httpd               latest              02ef73cf1bc0        3 weeks ago         194.4 MB
ubuntu              15.10               4e3b13c8a266        4 weeks ago         136.3 MB
hello-world         latest              690ed74de00f        6 months ago        960 B
training/webapp     latest              6fae60ef3446        11 months ago       348.8 MB

各个选项说明:

  • REPOSITORY:表示镜像的仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

创建镜像

附录

image

参考

命令详解

  • -d, --detach=false, 指定容器运行于前台还是后台,默认为false
  • -i, --interactive=false, 打开STDIN,用于控制台交互
  • -t, --tty=false, 分配tty设备,该可以支持终端登录,默认为false
  • -u, --user="", 指定容器的用户
  • -a, --attach=[], 登录容器(必须是以docker run -d启动的容器)
  • -w, --workdir="", 指定容器的工作目录
  • -c, --cpu-shares=0, 设置容器CPU权重,在CPU共享场景使用
  • -e, --env=[], 指定环境变量,容器中可以使用该环境变量
  • -m, --memory="", 指定容器的内存上限
  • -P, --publish-all=false, 指定容器暴露的端口
  • -p, --publish=[], 指定容器暴露的端口
  • -h, --hostname="", 指定容器的主机名
  • -v, --volume=[], 给容器挂载存储卷,挂载到容器的某个目录
  • --volumes-from=[], 给容器挂载其他容器上的卷,挂载到容器的某个目录
  • --cap-add=[], 添加权限,权限清单详见:http://linux.die.net/man/7/capabilities
  • --cap-drop=[], 删除权限,权限清单详见:http://linux.die.net/man/7/capabilities
  • --cidfile="", 运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法
  • --cpuset="", 设置容器可以使用哪些CPU,此参数可以用来容器独占CPU
  • --device=[], 添加主机设备给容器,相当于设备直通
  • --dns=[], 指定容器的dns服务器
  • --dns-search=[], 指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件
  • --entrypoint="", 覆盖image的入口点
  • --env-file=[], 指定环境变量文件,文件格式为每行一个环境变量
  • --expose=[], 指定容器暴露的端口,即修改镜像的暴露端口
  • --link=[], 指定容器间的关联,使用其他容器的IP、env等信息
  • --lxc-conf=[], 指定容器的配置文件,只有在指定--exec-driver=lxc时使用
  • --name="", 指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字
  • --net="bridge", 容器网络设置:
  • bridge 使用docker daemon指定的网桥
  • host //容器使用主机的网络
  • container:NAME_or_ID >//使用其他容器的网路,共享IP和PORT等网络资源
  • none 容器使用自己的网络(类似--net=bridge),但是不进行配置
  • --privileged=false, 指定容器是否为特权容器,特权容器拥有所有的capabilities
  • --restart="no", 指定容器停止后的重启策略:
  • no:容器退出时不重启
  • on-failure:容器故障退出(返回值非零)时重启
  • always:容器退出时总是重启
  • --rm=false, 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)
  • --sig-proxy=true, 设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理
@isaaxite
Copy link
Owner Author

isaaxite commented Oct 27, 2022

创建镜像

  • 从已经创建的容器中更新镜像,并且提交这个镜像
  • 使用 Dockerfile 指令来创建一个新的镜像

从已经创建的容器中更新镜像

当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个 docker commit 命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。

栗子

1 用 nginx 镜像启动一个容器,命名为 webserver,并且映射了 80 端口,这样我们可以用浏览器去访问这个 nginx 服务器

docker run --name webserver -d -p 80:80 nginx

2 使用 docker exec 命令进入容器,修改其内容

docker exec -it webserver bash
root@3729b97e8226:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
root@3729b97e8226:/# exit
exit

3 [可选] 通过 docker diff 命令看到具体的改动

$ docker diff webserver
C /root
A /root/.bash_history
C /run
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp

4 将修改提交创建镜像

docker commit 的语法格式为:

docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

// exp
docker commit \
    --author "Tao Wang <[email protected]>" \
    --message "修改了默认网页" \
    webserver \
    nginx:v2

慎用 docker commit

使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。
首先,如果仔细观察之前的 docker diff webserver 的结果,你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的执行,还有很多文件被改动或添加了。这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,将会导致镜像极为臃肿。
此外,使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为 黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体的操作。这种黑箱镜像的维护工作是非常痛苦的。

参考

使用 Dockerfile 指令来创建一个新的镜像

基于 从已经创建的容器中更新镜像 例子使用 Dockerfile 创建镜像

1 创建 Dockerfile 文件

# 创建名为 Dockerfile 的文件
touch Dockerfile

2 编辑 Dockerfile 文件内容

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

FROM 指定基础镜像

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制
Docker Hub 上有非常多的高质量的官方镜像。
创建空白镜像

FROM scratch

RUN 执行命令
格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。

栗子

RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。

RUN命令注意点

Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。

所以,应该将RUN命令用 && 聚合在一起,比如

RUN set -x; buildDeps='gcc libc6-dev make wget' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

3 构建镜像

使用 docker build 命令进行镜像构建。其格式为:

docker build [选项] <上下文路径/URL/->

参考

@isaaxite
Copy link
Owner Author

isaaxite commented Oct 28, 2022

创建文件服务pollify镜像

  • 镜像使用最新的node版本
  • 支持文件压缩相关功能
  • 支持node-canvas
  • server服务,或者做成serverless,函数服务

数据持久化,使用卷
https://www.51cto.com/article/630132.html

@isaaxite
Copy link
Owner Author

isaaxite commented Oct 28, 2022

容器基本使用

  • 查看容器;
  • 查看指定容器状态;
  • 启动容器;
  • 进入容器;
  • 停止容器;
  • 删除容器;

查看容器

docker ps查看正在运行的容器

docker ps -a

查看指定容器状态

使用 docker inspect 来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。

$ sudo docker inspect romantic_hamilton
[
    {
        "Id": "d740b78463699294189ec9bc27c0a24c8c849fbe2d12e3282802ca0dbac86a8e",
        "Created": "2022-10-28T10:28:03.192946138Z",
        "Path": "docker-entrypoint.sh",
        // ...
    }
]

启动容器

  • 启动新容器
  • 重启
  • 后台运行

启动新容器

docker run 启动新容器

# 栗子
docker run -it ubuntu /bin/bash

重启容器

docker start <容器id>

后台运行

-d 选项

docker run -itd --name ubuntu-test ubuntu /bin/bash

进入容器

  • exec 命令(推荐);
  • attach 命令;

exec 命令

例子:docker exec -it <容器id> /bin/bash

注意: 如果从这个容器退出,容器不会停止

attach 命令

docker attach <容器id>

注意: 如果从这个容器退出,会导致容器的停止。

停止容器

docker stop <容器 ID>

删除容器

删除容器使用 docker rm 命令:

docker rm -f <容器id>

附录

参考

@isaaxite
Copy link
Owner Author

isaaxite commented Oct 30, 2022

制作镜像

基于已有镜像创建容器,使用终端进入镜像。使用卷,将容器内的修改保存到容器外!

在修改符合预期之后,就可以使用Dockerfile制作镜像!

制作思路:将 容器内的修改 复制到镜像中!

开发

#!/bin/bash
docker run --rm -it \
  -v /data/home/isaacgan/workspace/kg-file-upload/pollfy_image:/data/svr \
  -w /data/svr \
  node:16.18.0 \
  /bin/bash
  • --rm,退出容器后删除
  • -v,挂载卷。将容器外的 pollfy_image 挂载到 容器内容的 data/svr。使用卷可以保留对当前镜像的修改
  • -w,指定 /data/svr 工作目录
  • 以 node:16.18.0 作为镜像创建容器

Dockerfile

# 指定镜像来源 
FROM node:16.18.0

LABEL maintainer="isaacgan"
LABEL descrition="kg_file_upload-pollfy_svr"

# 指定奖项的工作目录,指定后下面使用就会基于工作目录解析相对路径
# ./ => /data/svr
WORKDIR /data/svr

# 将当前Dockerfile所有在目录的所有内容 复制 到 ./ 下,即是工作目录
COPY . .

build镜像

sudo docker build -t node:kg_file_upload_pollfy_svr_v1 ./pollfy_image

image

基于刚制作的镜像,创建容器并后台运行

#!/bin/bash
docker run -d -p 9113:9113 \
  -w /data/svr \
  node:kg_file_upload_pollfy_svr_v1 \
  node app.js

image

@isaaxite
Copy link
Owner Author

isaaxite commented Oct 30, 2022

编写脚本重启容器

if 启动docker
启动docker
fi

if 容器是否启动
暂停容器
删除容器
fi
启动容器

附录

参考

@isaaxite
Copy link
Owner Author

isaaxite commented Nov 1, 2022

部署镜像

如何将build的镜像部署到生产机器,并且运行?!

@isaaxite
Copy link
Owner Author

isaaxite commented Nov 1, 2022

FAQ:将镜像删除,运行中的容器会怎么样?

存在依赖关系,删除失败

 docker image rm <image>:<tag> 

# output
Error response from daemon: conflict: unable to remove repository reference "<image>:<tag>" \
(must force) - container e8a28d0e2432 is using its referenced image 9fcf84b911b2

@isaaxite
Copy link
Owner Author

isaaxite commented Nov 4, 2022

FAQ:启动容器失败

启动失败

docker run -itd -p 9113:9113 \
  --name="<container name>" \
  xxx:v1 \
  /data/polyfill_svr/sh/start.sh

可以启动成功

docker run -itd -p 9113:9113 \
  --name="<container name>" \
  xxx:v1 \
  node app.js

@isaaxite
Copy link
Owner Author

isaaxite commented Nov 9, 2022

自动更新容器版本

0 是否安装docker(优先级低)

1 判断docker是否启动

否则,启动docker

faq:如果判断是否启动容器

2 判断是否已有同名容器启动

否则,删除已经启动容器

@isaaxite
Copy link
Owner Author

isaaxite commented Nov 11, 2022

批量删除历史镜像

不断迭代之后,产生了许多无用镜像
image

无用的镜像也是占用内容,有必要想方法批量删除!

docker image rm $(docker image ls -q -f before=xxx:3.2)

@isaaxite
Copy link
Owner Author

isaaxite commented Nov 18, 2022

win下使用docker

  • 安装win版本docker客户端
  • 下载镜像
  • 制作Dockerfile

制作dockerfile

  • 下载centos7镜像
  • 安装node

安装node

  • 安装nvm

安装nvm

考虑到会频繁切换node版本,所以选择安装 nvm

安装失败!!!

使用curl安装下载并安装,失败!

image

看提示,应该是因为没有绑ssh-key导致访问失败。暴露出另外一个问题:在 docker容器使用ssh-key

当前先按下,使用另外的方法!

本地安装

现在在浏览器直接下载 nvm 的tar包,然后build dockersfile的时候将它复制到镜像内并执行安装!

image

重新run镜像,创建容器并挂在卷

 winpty docker run -it -v /d/workspace:/data/workspace tme:v2

image

在查询之后发现是要手动在docker客户端中设置共享目录!!!详细见附录

挂在卷

#!/bin/bash
winpty \
docker run --rm -it \
  --mount type=bind,source="`pwd`",target="/data/workspace" \
  tme:v2

执行脚本安装nvm,失败!安装也是需要下载github资源!

经搜索发现是dns污染导致dns解析失败!

当前的解决方法是直接修改hosts,手动将xx解析到它的实际IP。参考: 如何解决类似 curl: (7) Failed to connect to raw.githu...

image

遇到的问题

-v 挂载卷,在容器内部出现奇怪的路径

image

在改用 --mount type=bind,source="xxx",target="xxx" 语法后正常!

image

附录

设置共享目录

You have to add C:\Users\path_to_my_folder to Docker Filesharing.
Go to docker dashboard -> settings ->Resources -> FileSharing. Add required folder and hit Apply & Restart.

image

参考:Docker : Error response from daemon: user declined directory sharing

@isaaxite
Copy link
Owner Author

参考

@isaaxite
Copy link
Owner Author

docker修改容器hosts

  • 构建时写入
  • 启动时写入

构建时写入

  • RUN + echo
  • CMD + echo

使用 Dockerfile 文件build镜像时,执行命令将hosts写入镜像中

RUN + echo

失败!

需要 root权限

image

RUN echo "185.199.108.133 raw.githubusercontent.com" >> /etc/hosts

RUN + echo

失败!

启动容器时提示失败!

容器创建时 hosts并没有创建!

image

启动时写入

使用 --add-host 命令

docker run --rm -it --privileged=true \
  --add-host=raw.githubusercontent.com:185.199.108.133 \

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant