docker常用操作
1、启动docker
参考:https://zhuanlan.zhihu.com/p/544310970
sudo systemctl status docker
或
sudo service docker status
启动(start)、停止(stop)、重启(restart)、查看状态(status)等。
2.容器
2.1创建容器
创建并运行
sudo docker run -it ubuntu:latest /bin/bash
创建不运行
sudo docker run -it -d alpine:latest
运行容器
sudo docker attach d74f2ceb5f3a
或
docker exec -it 容器id /bin/bash
docker exec -it mycontainer /bin/bash
docker exec 相当于进入容器并开启一个新的终端,可以在里面操作。
如果使用exit退出,容器也不会停止。
docker attach 进入容器正在执行的终端,不会启动新的进程。
如果使用exit退出,容器会停止运行!
创建并命名
sudo docker run -it -d --name ostechnix_alpine alpine:latest
sudo docker run -it --name name ubuntu:latest /bin/bash
创建分配gpu
sudo docker run -it -d --name czc_tensorrt_2310 --gpus all --cpus 48 --shm-size 16G --memory 500gb \
-v /etc/localtime:/etc/localtime \
-v /data/Codes:/data/Codes \
-v /data/NFS:/data/NFS nvcr.io/nvidia/tensorrt:23.10-py3
docker run --gpus all --cpus 48 --shm-size 16G --memory 500gb -itd \
-v /etc/localtime:/etc/localtime \
-v /data/Codes:/data/Codes \
-v /data/NFS:/data/NFS \
--name czc_triton2_2310 \
-p 8049:8001 \
-p 8059:8000 \
nvcr.io/nvidia/tritonserver:23.10-py3
docker exec 命令用于在正在运行的 Docker 容器中运行指定的命令。
docker exec [OPTIONS] CONTAINER COMMAND [ARG…]
其中,OPTIONS 可以省略,常用的选项如下:
-i:保持标准输入打开,使得可以与容器交互。
-t:分配一个伪终端,使得可以与容器交互。
CONTAINER 是要操作的容器的名称或 ID。
COMMAND 是要在容器内运行的命令。
ARG… 是命令的参数。
在名为 mycontainer 的容器中执行命令 /bin/bash 并分配一个伪终端:
docker exec -it mycontainer /bin/bash
在名为 mycontainer 的容器中执行命令 ls -l:
docker exec mycontainer ls -l
# 常用的参数
docker run -d -p 宿主机端口:容器端口 --name 容器名称 镜像的标识|镜像名称[tag]
# -d: 代表后台运行容器
# -p: 宿主机端口:容器端口: 为了映射当前Linux的端口和容器的端口
# --name 容器名称: 指定容器的名称
2.2查看容器
#查看运行
sudo docker ps
#列出所有可用的容器(运行或者停止)
sudo docker ps -a
#查看容器信息
docker inspect <container id>
#查看容器Privileged权限是否开启
docker inspect --format='{{.HostConfig.Privileged}}' <container id>
2.3启动容器
启动start、重启restart、暂停pause 和终止容器stop
#名称或ID
sudo docker start modest_cray
sudo docker start 10615254bb45
容器脱离(不要退出)回到主机系统的 shell。不要终止或者关闭容器。使用 CTRL+P 然后 CTRL+Q 从容器中脱离,这样不会关闭容器。
删除容器
sudo docker rm 377e6d77ebb5
2.4创建容器脚本
#!/bin/bash
docker_run_name=$1
docker_image_name=$2
docker_image_version=$3
ssh_port=$4
jupyter_port=$5
tensorboard=$6
docker run --gpus all --cpus 48 --shm-size 16G --memory 500gb --privileged=true -itd \
-p ${ssh_port}:22 \
-p ${jupyter_port}:8888 \
-p ${tensorboard}:6006 \
-v /etc/localtime:/etc/localtime \
-v /data/Codes:/data/Codes \
-v /data/NFS:/data/NFS \
--name ${docker_run_name} \
-e JUPYTER_PASSWORD="123456" \
-e JUPYTER_PORT=8888 \
-e ROOT_PASS="123456" \
${docker_image_name}:${docker_image_version}
# bash create_pytorch_container.sh virtual_ngc_2306 nvcr.io/nvidia/pytorch 23.06-py3 8018 8019 8020
# bash create_pytorch_container.sh llama_efficient_pytorch_2306 nvcr.io/nvidia/pytorch 23.06-py3 8005 8006 8007
#
# bash create_pytorch_container.sh czc_test_ngc_2312 nvcr.io/nvidia/pytorch 23.12-py3 8066 8067 8068
# bash create_pytorch_container.sh czc_videointer_ngc_2312 nvcr.io/nvidia/pytorch 23.12-py3 8046 8047 8048
#添加--privileged=true
# bash create_pytorch_container.sh czc_sshcontainer_ngcpytorch_2312 nvcr.io/nvidia/pytorch 23.12-py3 8056 8057 8058
2.5Docker容器修改端口映射
参考:https://zhuanlan.zhihu.com/p/94949253
1.使用docker ps -a命令找到要修改容器的CONTAINER ID
2.运行以下命令,进入该容器目录
docker inspect【CONTAINER ID】| grep Id
cd /var/lib/docker/containers
停止容器
docker stop [容器id]
3.停止主机docker服务
systemctl stop docker
4.进入2得到的文件夹内,修改hostconfig.json 和 config.v2.json
5.保存之后重启docker服务和容器
systemctl start docker
docker start [docker id]
3、镜像
3.1查看镜像
sudo docker images
sudo docker search ubuntu
sudo docker pull ubuntu
3.2创建镜像
将容器变成镜像
sudo docker commit 377e6d77ebb5 ostechnix/ubuntu_apache
docker commit 7ca736d99653 yolov5:v6.2
移除容器
docker rm container_id
docker rm container_name
删除镜像
docker rmi [image] 或者:docker image rm [image]
docker rmi allen_mysql:5.7
docker rmi ee7cbd482336
3.3保持和加载镜像
参考:https://blog.csdn.net/qq_41204464/article/details/122034637
二、打包tar
使用save参数进行打包,格式如:docker save -o tar文件名称 镜像REPOSITORY:TAG
docker save -o yolov5-v6.2.tar yolov5:v6.2
其中yolov5:v6.2 是需要保存镜像的REPOSITORY、和TAG;也是上面保存的镜像名称。
三、加载tar镜像
使用load进行从tar文件导出镜像
docker load -i yolov5-v6.2.tar
然后查看是否出现镜像
docker images
3.4上传镜像到docker hub仓库
1、注册dockerhub: https://registry.hub.docker.com/
2、登录docker:docker login (CentOS系统docker服务中操作)
3、登出、退出: docker logout
4、tag修改镜像为仓库的规范才能推送
推送镜像的规范是:docker push 注册用户名/镜像名
tag命令修改为规范的镜像:
docker tag boonya/tomcat-allow-remote boonyadocker/tomcat-allow-remote
推送镜像的规范是:
docker push 注册用户名/镜像名
查看修改后的规范镜像:
docker images
5、推送镜像到Docker Hub
通过push命令推送镜像:
docker push boonyadocker/tomcat-allow-remote:latest
参考:https://blog.csdn.net/boonya/article/details/74906927
4、在宿主机和容器之间交换⽂件
在宿主机和容器之间相互COPY⽂件 cp的⽤法如下
# 容器中 复制到 宿主机
docker cp [OPTIONS] CONTAINER:PATH LOCALPATH
eg:docker cp tomcat-8081:/usr/local/tomcat/webapps/ROOT/index.jsp /root/
# 宿主机 复制到 容器中
docker cp [OPTIONS] LOCALPATH|- CONTAINER:PATH
eg:docker cp /root/index.html tomcat-8081:/usr/local/tomcat/webapps/ROOT/
复制文件
将当前目录tpch文件夹复制到mysql容器相应的位置:
docker cp tpch mysql56:/var/lib/mysql #mysql56为容器名
容器文件拷贝到宿主机:
docker cp 容器名:要拷贝的文件在容器里面的路径 要拷贝到宿主机的相应路径
Docker数据卷
通过镜像创建一个容器。容器一旦被销毁,则容器内的数据将一并被删除。但有些情况下,通过服务器上传的图片出会丢失。容器中的数据不是持久化状态的。这个时候可以通过数据卷来解决这个问题。https://zhuanlan.zhihu.com/p/430652941
5、docker 容器之间通信
菜鸟:https://www.runoob.com/docker/docker-container-connection.html
https://www.cnblogs.com/makalochen/p/14242125.html#%E7%AE%80%E4%BB%8B
我们安装Docker后,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host。
host:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
None:该模式关闭了容器的网络功能,相当于一个回环网络。
Bridge:此模式会为每一个容器分配、设置IP等,并将容器连接到一个叫docker0的虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
以哪种方式让服务器内部的容器与公网进行通信。
1、假如使用的是默认的桥接网络模式,启动容器的时候需要使用参数-p 宿主机端口:容器端口设置端口的映射。
2、假如使用的是host主机模式,因为使用的是宿主机的ip与端口,那就直接可以与公网通信。
查看IP:
ip安装apt-get update & apt-get install -y iproute2
ip addr 或 ip a
或用ifconfig
5.1查看网络
docker network ls
docker network inspect NETWORKID
5.2创建网络
链接:https://blog.csdn.net/longjuanfengzc/article/details/89340391
https://blog.csdn.net/u013355826/article/details/84987233
1.默认创建容器时默认连接的是bridge,其实可以创建容器时可以指定使用的网络,可以指定host、none甚至可以自己建一个bridge
docker network create -d bridge my-bridge
2.通过link,使用link相当于使用DNS记录(不推荐)
通过busybox创建一个容器名为test1
docker run -d --name test1 busybox /bin/sh -c “while true; do sleep 3600; done”
再用busybox创建一个容器名为test2,创建test2时使用了link链接了test1
docker run -d --name test2 --link test1 busybox /bin/sh -c “while true; do sleep 3600; done”
5.3容器连接到网络
将容器连接到网络
docker run --net= …
或者将已存在容器加入新的网络
docker network connect
创建时指定网络
docker network create -d bridge my-bridge
启动容器并指定模式
默认是Bridge
在容器启动命令时用参数–net=host指定当前容器网络模式
如: docker run -itd --net=host centos:7 /bin/bash
5.4网络端口映射
参考:https://cloud.tencent.com/developer/article/1831540
外网如何访问容器?
端口映射,-p指定对应端口
外网访问容器用到了docker-proxy和iptables DNAT
- 宿主机访问本机容器使用的是iptables DNAT
- 外部主机访问容器或容器之间的访问是docker-proxy实现
可以通过 -P 或 -p 参数来指定端口映射。
当使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。
-p (小写的)可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。
docker run -d -P training/webapp python app.py
使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,可以执行
docker run -d -p 5000:5000 training/webapp python app.py
5.5Docker的跨主机网络访问
跨主机网络解决方案
docker原生的overlay和macvlan
第三方的flannel、weave、calico
6、docker嵌套
docker --privileged=true 参数作用
大约在0.6版,privileged被引入docker。
使用该参数,container内的root拥有真正的root权限。
否则,container内的root只是外部的一个普通用户权限。
privileged启动的容器,可以看到很多host上的设备,并且可以执行mount。
甚至允许你在docker容器中启动docker容器。
链接:https://blog.csdn.net/wangxuelei036/article/details/107457712
方法1:共享宿主机 dockerd 服务
方法2:独立隔离的容器运行环境
方法3:使用 Sysbox 运行时
参考:https://www.zhaowenyu.com/docker-doc/dind/docker-in-docker.html
有关Docker容器内不能使用Systemctl等命令的解决方法
systemctl start mysql
System has not been booted with systemd as init system (PID 1). Can’t operate
解决方法
有两种
-
使用service代替systemctl
service mysql start -
赋予特权并在init中启动
docker run -it --privileged=true -h node02 --ip 172.18.0.2 --name node02 ubuntu:v1 /usr/sbin/init
链接:https://blog.csdn.net/weixin_43410596/article/details/121865128
解决办法:
运行容器时添加`--privileged=true`,修改/bin/bash为/sbin/init
[root@919 ~]# docker run -itd --name nginxv2 --privileged=true centos /usr/sbin/init
验证:
powershell
[root@919 ~]# docker exec -it nginxv2 /bin/bash
[root@491ab139e4fd /]# systemctl start nginx
7、服务集群
参考:https://www.runoob.com/docker/docker-swarm.html
Docker Compose
Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。使用前面介绍的Dockerfile我们很容易定义一个单独的应用容器。然而在日常开发工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器;再比如在分布式应用一般包含若干个服务,每个服务一般都会部署多个实例。如果每个服务都要手动启停,那么效率之低、维护量之大可想而知。这时候就需要一个工具能够管理一组相关联的的应用容器,这就是Docker Compose。
Docker Swarm是Docker官方提供的容器集群管理以及容器编排解决方案,Docker Swarm基于Docker Compose组件以及网络等基础能力,提供了服务编排、负载均衡、动态伸缩、滚动更新等能力。
Docker Engine:作为 Docker 镜像构建与容器化启动的工作引擎;
Docker Machine:安装与管理 Docker Engine 的工具;
Docker Swarm:是 Docker 自1.12后自带的集群技术,将多个独立的 Docker Engine 利用 Swarm 技术进行集群化管理;
8、显示GPU进程所属docker 容器
https://www.jianshu.com/p/df7b444c4153
nvidia-smi查看进程占用GPU情况PID
1、查看单个
通过docker ps 查看所有运行的容器,然后一个一个运行docker top containerId| grep PID,根据返回情况判断这个进程在哪个容器里面。比如 docker top d7c1 | grep 21274 ,返回为空,说明不在这个容器里面,接着再试直到找到容器为止。
docker top 15766f6eeaf7(容器ID) | grep 55123(PID)
2、查看所有
#!/bin/bash
# find docker container by process id
processId=
# 提取程序的名字
PROGNAME=$(basename $0)
usage () {
echo " $PROGNAME [-p --processId] or $PROGNAME"
return
}
# 一个while case用来提取参数
while [[ -n $1 ]]; do
case $1 in
-p | --processId) shift
processId=$1
;;
-h | --help) usage
exit
;;
*) usage >&2
exit 1
;;
esac
shift
done
# 定义一个函数
findCon () {
# $1 是函数的输入
local pId=$1
# awk '{print $1,$NF}' 打印第一列和最后一列,即容器ID和容器Name,awk 'NR != 1' 不打印第一行
# read代表读入变量
docker ps | awk '{print $1,$NF}' | awk 'NR != 1' | while read conId conName; do
# 对pId的grep使用正则表达式,不然的话如果输入进程pId为21则会匹配到21274,通过前后加入空格匹配就可以防止出现这种问题
local temp="[[:space:]]\{1\}${pId}[[:space:]]\{1\}"
if [[ -n $(docker top $conId | grep -e $temp) ]]; then
printf "%s\t\t%s\t\t%s\t\t" $pId $conId $conName
break
fi
done
return
}
# 如果 $processId不为空
if [[ -n $processId ]]; then
# 判断输入是否为数字
if [[ $processId =~ ^[0-9]+$ ]]; then
printf "conId%s\t\t\tconName%s\n" $conId $conName
findCon $processId
else
echo "Please input number"
exit 1
fi
else
num=1
printf "PID\t\tconId%s\t\t\tconName%s\t\t\tGPU Memory\n" $conId $conName
# 这一串awk操作为提取进程id和GPU使用情况,然后去掉空格,-F为设定awk分隔符,在命令行输出一边就看懂了
nvidia-smi -q 2>&1| awk '/Process ID|Used GPU Memory/' | awk '{gsub(/[[:blank:]]*/,"",$0);print $0}' | awk -F ":" '{print $NF}' | while read item; do
if [[ $(($num % 2)) != 0 ]]; then
findCon $item
else
printf "%s\n" $item
fi
num=$((num+1))
done
fi