docker架构
docker中最重要的两个概念:
- image:镜像
- container:容器
可以简单的把image理解为可执行程序,container就是运行起来的进程。那么写程序需要源代码,那么“写”image就需要dockerfile,dockerfile就是image的源代码,docker就是"编译器"。
因此我们只需要在dockerfile中指定需要哪些程序、依赖什么样的配置,之后把dockerfile交给“编译器”docker进行“编译”,也就是docker build命令,生成的可执行程序就是image,之后就可以运行这个image了,这就是docker run命令,image运行起来后就是docker container
安装
主要是在Centos上安装。
首先如果之前安装了,需要卸载旧版本:
yum remove docker docker-common docker-selinux docker-engine
安装需要的软件包, yum-util 提供yum-config-manager功能,另两个是devicemapper驱动依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
设置一个yum源,下面两个都可用
# (中央仓库)
yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo
# (阿里仓库)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
查看可用版本有哪些
yum list docker-ce --showduplicates | sort -r
选择一个版本安装即可:yum install docker-ce-版本号
# 安装版本号为20.10.9的docker
yum install docker-ce-20.10.9
最后docker服务(docker demon)
通过systemctl来接管。
# 开启docker服务
systemctl start docker
# 设置docker服务开机自启动
systemctl enable docker
# 查看docker服务开启状态
systemctl status docker
在使用过程中,报错:permission denied while trying to connect to the Docker daemon socket at unix:
///var/run/docker.sock
: Get “http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/json”: dial unix /var/run/docker.sock: connect: permission denied.
表示普通用户对连接/var/run/docker.sock
权限不足,通过ll /var/run/docker.sock
查看该文件发现属于用户root,并且属于用户组docker,因此可以将普通用户加入到docker组
中。
sudo gpasswd -a username docker
和newgrp docker
用于将普通用户username加入到docker用户组,并且更新docker用户组。
docker通过对镜像构建容器,如果在本地没有该镜像,则会从远程仓库中下载下来使用,一般远程仓库默认在国外,因此在国内需要更换为国内源。对docker镜像下载加速(更换国内源):在/etc/docker/daemon.json
中写入以下内容:
{"registry-mirrors":["https://reg-mirror.qiniu.com/"]}
然后重启docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker
容器(container)
启动容器(docker run)
运行交互式的容器(-i)
docker run -it ubuntu /bin/bash
参数说明:
- -i :允许你对容器内的标准输入 (STDIN) 进行交互
- -t :在新容器内指定一个伪终端或终端
- ubuntu:镜像名字,使用最后版本,可以指定版本,比如
ubuntu:15.10
- /bin/bash:命令,在镜像中使用命令。
后台模式启动容器(-d)
docker run -itd --name ubuntu-test ubuntu /bin/bash
参数说明:
1. -d:detach的缩写,等价于--detach
,表示后端运行该容器
启动已停止运行的容器(docker start)
查看所有的容器命令:
docker ps -a
输出说明:
CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。
状态有7种:
- created(已创建)
- restarting(重启中)
- running 或 Up(运行中)
- removing(迁移中)
- paused(暂停)
- exited(停止)
- dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
NAMES: 自动分配的容器名称。
对于后端启动的容器输出,可以在宿主主机内使用docker logs
命令,查看容器内的标准输出。
对于已经停止的容器,可以通过docker start
启动,或者通过docker restart
重新启动。
docker start <容器ID>
docker restart <容器ID>
进入容器(docker attach | docker exec)
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
docker attach
:从容器退出会导致容器停止。docker exec
:该命令会退出容器终端,但是容器并不会停止。(推荐使用)
docker attach <容器ID>
docker exec -it <容器ID> /bin/bash
停止容器(docker stop)
docker stop <容器ID>
导出&导入容器
导出容器(docker export)
# 将容器ID导出为ubuntu.tar
docker export <容器ID> > ubuntu.tar
导入容器快照(docker import)
使用 docker import
从容器快照文件中再导入为镜像
# 将ubuntu.tar导入为镜像
docker import ubuntu.tar test/ubuntu:v1
删除容器(docker rm)
docker rm -f <容器ID>
清理掉所有终止状态的容器:
docker container prune
镜像(image)
列出镜像列表(docker images)
使用 docker images
来列出本地主机上的镜像。输出说明如下:
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
查找镜像(docker search)
可以去网站搜索,当然也可以通过docker search
来查找
docker search <镜像名>
- NAME: 镜像仓库源的名称
- DESCRIPTION: 镜像的描述
- OFFICIAL: 是否 docker 官方发布
- stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。
- AUTOMATED: 自动构建。
获取镜像(docker pull)
docker pull <镜像名>
删除镜像(docker rmi)
docker rmi <镜像名>
创建镜像
当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。
- 1、从已经创建的容器中更新镜像,并且提交这个镜像(docker commit)
- 2、使用 Dockerfile 指令来创建一个新的镜像(docker build)
docker commit
docker commit -m="update ubuntu" -a="My_name" e218edb10161 My_name/ubuntu:v2
各个参数说明:
- -m: 提交的描述信息
- -a: 指定镜像作者
- e218edb10161:容器 ID
- My_name/ubuntu:v2: 指定要创建的目标镜像名
docker build
创建一个Dockerfile 文件,其中包含一组指令来告诉 Docker 如何构建我们的镜像。每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。第一条FROM,指定使用哪个镜像源。RUN 指令告诉docker 在镜像内执行命令,安装了什么。然后,我们使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像。
注意尽量少使用多个RUN语句,尽量使用 && 符号将其转换成一个。
docker build -t My_name/centos:6.7 .
参数说明:
- -t :指定要创建的目标镜像名
- . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径
设置镜像标签(docker tag)
docker tag 镜像ID 用户名称/镜像名:新的标签名
端口映射
在运行容器的时候使用docker run
通过指定
我们使用 -P 绑定端口号,使用 docker ps 可以看到0.0.0.0:32768->5000/tcp
,表示容器端口5000 绑定主机端口 32768。也可以使用 -p 标识来指定容器端口绑定到主机端口。
两种方式的区别是:
- -P :是容器内部端口随机映射到主机的端口。
- -p : 是容器内部端口绑定到指定的主机端口。
应用
docker搭建nginx,并挂载到宿主机器上
获取镜像
docker pull nginx
首先在启动镜像之前,需要将配置文件中从镜像中复制到宿主主机上(用于运行容器的挂载)。否则在启动容器并且挂载的时候,会找不到配置文件,从而导致启动失败。
> docker run -d -p 80:80 --name nginx nginx # 运行nginx容器
#从名为nginx的容器中复制配置文件到宿主主机中
> docker cp nginx:/etc/nginx/nginx.conf /etc/nginx/nginx.conf
# 从容器中复制配置文件夹
> docker cp nginx:/etc/nginx/conf.d /etc/nginx/conf.d
# 从容器中复制html文件
> docker cp nginx:/usr/share/nginx/html /var/nginx/html
# 从容器中复制日志文件
> docker cp nginx:/var/log/nginx /var/nginx/log
# 停止并删除nginx容器
> docker stop nginx
> docker rm nginx
可能在运行过程中会出现operation not permitted
问题,翻译是不允许操作
,可能是复制权限问题。
说明:docker挂载文件时,并不是挂载了某个文件的路径,而是挂载了对应的文件,即挂载了linux指定的
inode
文件.当使用vim之类的编辑器进行保存时,它不是直接保存文件,而是采用了备份、替换的策略,就是编辑时,是创建一个新的文件,在保存的时候,把备份文件替换源文件,这个时候文件的 inode 就发生了变化,而原来 inode 对应的文件其实并没有修改,也就是容器内的文件没有变化。当重启容器的时候,会挂载新的 inode
所以官方不建议直接挂载文件,而是文件夹
docker run -d -p 80:80 --name nginx --net host \
-v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /etc/nginx/conf.d:/etc/nginx/conf.d \
-v /etc/nginx/cert:/etc/nginx/cert \
-v /var/nginx/html:/usr/share/nginx/html \
-v /var/nginx/log:/var/log/nginx \
-e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 \
--privileged=true --restart=always nginx
命令 | 描述 |
---|---|
-d | 守护式容器在后台运行 |
-p 80:80 | 端口映射,格式为 主机(宿主)端口:容器端口 |
–name nginx | 启动容器的名字 |
-v | 挂载目录 |
–privileged=true | 给容器内root权限 |
–restart=always | 随docker自启动 |
–net host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口 |
\ | shell 命令换行 |
nginx | 镜像名 |
启动前需要先创建Nginx外部挂载的配置文件( /home/nginx/conf/nginx.conf)
之所以要先创建 , 是因为Nginx本身容器只存在/etc/nginx 目录 , 本身就不创建 nginx.conf 文件
当服务器和容器都不存在 nginx.conf 文件时, 执行启动命令的时候 docker会将nginx.conf 作为目录创建 , 这并不是我们想要的结果。
神经网络进行训练后的权重和环境,将其打包为docker镜像文件
在python中一般使用anaconda
或者miniconda
来创建多个虚拟环境。当然也可以直接使用python的全局环境。(这里以anaconda为例说明)
搜索anaconda的镜像
docker search anaconda
可以看到continuumio/anaconda3
的stars数最高。拉取该镜像(挺大的)
docker pull continuumio/anaconda3
使用该镜像创建一个名为docker_conda_env的环境,使用-d
用于后端运行,防止退出环境后导致其不运行。后面可以通过docker exec
进入该后端运行环境。
# 运行名为docker_conda_env的容器
docker run -id --name docker_conda_env continuumio/anaconda3
# 进入docker_conda_env 容器环境
docker exec -it docker_conda_env /bin/bash
进入容器环境后,查看anaconda环境的工作env:
> whereis anaconda
anaconda: /opt/conda/bin/anaconda
> conda env list
# conda environments:
#
base * /opt/conda
可以看出,base环境的目录为/opt/conda
,因此,如果想将宿主机上的环境加入到docker中,只需要将宿主机上的环境拷贝到docker中,通过语句docker cp
:
docker cp /home/user/miniconda3/envs/pytorch_gpu test:/opt/conda/envs
可以进入该容器中,并运行conda env list
语句查看是否添加成功。当然环境也可以自己在容器中自行下载。
将本地代码通过docker cp
语句复制到docker容器中后,就可以将环境进行打包操作:退出容器后执行:
docker commit -a '作者名' -m '描述' <容器名字> <保存的镜像的名字>
docker commit -a 'author' -m '打包python项目' docker_conda_env conda_env
将镜像存为压缩包,方便给别人使用:
# 打包操作
docker save -o conda_env.tar conda_env
# 解压操作,将tar解压为镜像文件,并交给docker
docker load -i conda_env.tar
docker images # 查看一下镜像是否添加成功