docker

346 阅读8分钟
不给予别人参考、仅作为自己学习了解记录

docker

解决了什么问题?

  • 内核隔离

  • 运行环境和配置不统一的问题(典型的例子就是在我们本地可以跑、测试环境有不行)

    • 程序跑起来需要 代码 + 运行环境 + 配置 + 依赖的服务
    • 现在我是将我们开发好的代码打包发给运维的同学去部署、如果我们直接将 代码 + 运行环境 打包给运维的同学部署就可以解决这个问题

docker架构

  • Docker 主要由 容器镜像仓库

    • 容器(Container): 镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

    • 镜像(Image): Docker镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的root文件系统。

    • 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。

  • docker架构图

    架构图
镜像(image)Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。
容器(container)容器是独立运行的一个或一组应用,是镜像运行时的实体。
客户端(client)Docker 客户端通过命令行或者其他工具使用 Docker SDK (docs.docker.com/develop/sdk…) 与 Docker 的守护进程通信。
主机(Host)一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
仓库(Registry)dockerhub

如何使用?

首先下载安装docker就不赘述了、自行去官网去下载安装

docker官网传送门

小试牛刀

我们这里做一个小练习、从远端dockerhub上拉取一个nginx官方镜像、然后本地构建容器跑一下
$ docker search nginx
# 我们这里是搜索nginx镜像、当然你也可以搜索其它的、比如redis、mysql、node、centos、tomcat等等
# 我们会看到第一个就是 official 版本的、我们拉取官方版本

$ docker pull nginx
# 不写版本号、默认是最新的

$ dokcer images
# 查看镜像
# 我们可以看到 images具体信息、包括仓库信息、TAG信息、镜像id、创建时间、镜像大小

$ docker run -id --name=nginx_demo -p 8080:80 nginx
# 通过我们的nginx镜像去创建一个容器
# 此时我们可以去8080端口去访问nginx欢迎页了、这样我们就启动了一个nginx服务

$ docker ps
# 查看容器信息、包括容器id、从哪一个镜像来、创建时间、容器状态、端口映射、容器名称

容器命令总结

$ docker ps
# 查看容器信息

$ docker ps -a
# 查看所有历史

$ docker rm <container-id>
# 删除容器

$ docker ps -aq
# 列出所有容器id

$ docker rm `docker ps -aq`
# 删除所有容器

$ docker rm <container1-id> <container2-id>
# 一次删除多个容器

# docker 执行二进制文件 run 结合二进制文件运行容器 

$ docker run -id --name=nginx_demo -p 8080:80 nginx
# docker run -id<-i是可输入、-d是后台运行模式> --name=<container-name> -p <宿主机port:容器port> ngixn<镜像> /bin/bash<可以不写>
# -i 允许你对容器内的标准输入、进行交互
# -d 后台运行
# -it 创建容器并进入 退出后容器停止
# -id 创建容器不进入 手动进入、退出后不停止
# --name=xxx || -name xxx

$ docker exec -it nginx_demo /bin/bash
# 进入刚才创建好的容器

$ exit
# 在容器中执行、退出当前容器到宿主机

$ docker stop nginx_demo || <nginx_demo container-id>
# 停掉容器、也可以使用id来停掉、id可以不复制全部、部分即可

$ docker start nginx_demo || <nginx_demo container-id>
# 启动 容器

$ docker inspect nginx_demo || <nginx_demo container-id>
# 查看容器信息

镜像命令总结

$ docker search nginx
# 搜索镜像

$ docker pull nginx
# 拉取镜像、不指定版本默认latest

$ docker images
# 产看本地镜像

$ docker rmi <images-id> || <images-name>
# 删除镜像

$ docker images -q
# 查看所有镜像id

$ docker rmi `docker iamges -q`
# 删除所有镜像

$ docker rmi <images1-id> <images2-id>
# 删除镜像images1和images2

$ docker inspect <images-id>
# 查看镜像信息

eg

我们通过tomcat部署我们的项目
$ docker search tomcat

$ docker pull tomcat

$ docker run -id --name=tomcat_demo -p 8080:8080 tomcat
# 这里我们直接去访问8080端口是404

$ docker exec -it tomcat_demo /bin/bash
# 进入到tomcat容器、切换到目录/usr/local/tomcat/webapps后我们发现webapps为空目录、所以404的原因找到了
# 但是可以发现有一个webapps.dist目录里面有我们的tomcat的文件

$ mv -f webapps.dist webapps
# 将webapps.dist重命名为 webapps

$ exit
# 退出去后就可以去访问我们8080端口记得路径看对、如果你是/usr/local/tomcat/webapps/dist/index.html 访问的时候加上localhost:8080/dist/index.html


# 这里我们只是启动了一个tomcat成功、那么如何部署我们的本地静态项目呢
# 截止目前没有学习到数据卷和容器数据卷的知识、所以我们可以将我们本地的静态文件拷贝到容器中

$ docker `pwd` <container-name>:/usr/local/tomcat/webapps
# 这里pwd就是我们宿主机中你静态文件的绝对路径
# 然后我们就可以去访问我们自己静态资源项目了

容器与宿主机之间的文件拷贝

  • 从宿主机到容器中

    • docker <宿主机中绝对路径> :<容器内的绝对路径>

    • 从容器中拷贝文件到宿主机(比如将nginx拷贝配置文件到宿主机中、然后通过数据卷映射到容器中)

    • docker :<容器内的绝对路径> <宿主机中绝对路径>

    • 我们可以使用命令pwd来查看绝对路径

  • 在容器中安转vim

    • 首先执行apt-get update

    • Apt-get install vim -y

    这样我们就可以访问到我们的前端资源了、可以是使用webpack 打包好的ditst

数据卷

宿主机中的一个目录或者文件、将宿主机中的目录和容器中的目录挂载起来、这样容器和宿主机共享同一份数据、则实现了通信
  • 作用
    • 容器数据持久化
    • 外部机器和容器之间的通信
    • 容器之间的数据交换
  • 提示
    • 一个数据卷可以被多个容器挂载
    • 一个容器可以挂载多个数据卷

配置数据卷

$ docker run -id --name=data_volume -p 8080:8080 -v `<pwd>`:<container-absolute-url> nginx
# 通过-v 我们可以将我们宿主机中的文件映射到容器内、这样容器内就可以访问到我们宿主机中的资源、共享一份数据、容器退出去后资源还是存在在我们的宿主机中的、不会丢失

$ docker run -id --name=data_volume -p 8080:8080 --volume `<pwd>`:<container-absolute-url> nginx
# 这样也可以、而且可以映射多个

# eg.tomcat
$ docker run -id --name=tomcat_data_volume -p 8080:8080 -v $pwd:/usr/local/tomcat/webapps tomcat

# eg.nginx
$ docker run -id -name nginx_data_volume -p 8080:8080 \ 
$ --volume $pwd/conf/nginx.conf:/etc/nginx/nginx.conf \
$ --volume $pwd/logs:/var/log/nginx \
$ --volume $pwd/html:/usr/share/nginx/html \
$ nginx

# 这里的 '\'是可以将一行过长的命令拆分为多行进行输入
# 上面就是将nginx容器的配置文件映射到我们宿主机中的conf/nginx.conf、将日志也映射、将资源也映射
# 当我们使用nginx进行部署我们vue项目的时候、我们如果router模式是history的时候会出现刷新404的问题
# 我们可以在nginx中进行配置 location / { try_files $uri $uri/ /index.htnl;}
# $uri相当于读取目录

数据卷容器

多个容器挂载一个数据卷、有个弊端、操作起来比较繁琐
$ dcoker run -it --name=container-3 -v /volumn centos /bin/bash
# 创建一个数据卷容器 并且挂载到宿主机的/voluen、如果不写容器中的则会自动的创建

$ docker run -it --name=container-1 --volumes-from container-3
# 创建容器container-1、使用命令--volumes-from将容器container-1载到container-3容器

$ docker run -it --name=container-2 --volumes-from container-3
# 创建容器container-2、使用命令--volumes-from将容器container-2载到container-3容器

# 这样这三个容器直接和宿主机的/volumn就实现了通信、共享同一份数据

dockerFile

1、什么是dockerfile?

特殊的文件系统叠加而成的、基于现有的镜像去创建新的镜像的一个文件
dockerfile是一个文本文件、每一层构建一层

2、docker镜像的原理本质是什么?

分层的文件系统

3、为什么centos几个G但是镜像只有两百多M?

因为复用了bootfs

4、为什么docker中的tomcat有五百多M但是我们一个安装包才几十M?

因为有底层系统、所以镜像会大
$ mkdir Dockerfile && cd Dockerfile
$ vi Dockerfile
# 编辑文件

$ FROM nginx
$ RUN echo '哈哈哈哈哈哈' -> /usr/local/share/html/index.html

# 执行dockerfile文件
$ docker build -t nginx:v1 .
# 这个 '.' 是上下文路径
# 是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。
# 注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

# 产看我们本地是否存在我们构建的v1版本的nginx镜像
$ docker images

指令详解

copy菜鸟教程加加深印象
$ FROM <images-name>
# 依据哪个镜像做为根镜像

$ RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
#	创建文件index.htnl内容为 '这是一个本地构建的nginx镜像'
# RUN有两种格式
# 1、shell格式
# RUN <命令行命令>
# 2、exec格式
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
# 注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大 使用&&来连接就是一层

$ COPY
# 复制指令
# 格式:
$ COPY [--宠物呢<user>:<group>] <源路径1><目标路径>
$ COPY [--chown=<usr>:<group>] ["<源路径1>", ... "<目标路径>"]
# [--chown=<user>:<group>] 可选参数,用户改变复制到容器内文件的拥有者和属组。
# <源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。
# COPY hom* /mydir/
# COPY hom?.txt /mydir/

$ ADD
# ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)
# 两者的区别
# ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
# ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

$ CMD
# 类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
# CMD 在docker run 时运行
# RUN 是在 docker build
# 作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
# 如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

# 推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh

$ ENTRYPOINT
# 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
# 但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
# 优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
# 注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
$ ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

$ ENV
# 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
# ENV <key> <value>
# ENV <key1>=<value1> <key2>=<value2>...

$ ARG
# 构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
# 构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

$ VOLUME
# 定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

# 避免重要的数据,因容器重启而丢失,这是非常致命的
# 避免容器不断变大。

# 格式
# VOLUME ["<路径1>", "<路径2>"...]
# VOLUME <路径>
# 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

$ EXPOSE
# 仅仅只是声明端口。
# 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
# 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

$ WORKDIR
# 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
# docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
# WORKDIR <工作目录路径>

$ USER
# 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
# USER <用户名>[:<用户组>]

$ HEALTHCHECK
# 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

$ ONBUILD
# 用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

部署前端项目

FROM nginx

COPY ./dist /usr/share/nginx/html
# /usr/share/nginx/html 目录下面放的是nginx的静态资源

# nginx默认的端口是80 我们这里做一个端口映射 将80映射到8080
EXPOSE 8080

# nginx 配置文件在 /etc/nginx/conf.d/default.conf
# 我们也可以本地配置一份简单的配置文件、在构建镜像的时候打包进去覆盖掉原有的配置就可以做到我们在项目中随时配置nginx
RUN echo 'successful'
创建文件dockerfile放在项目根目录下面、直接yarn build 前端项目、得到dist文件夹

/dist
/dockerfile

执行 docker build -t <images-name>:<tag> .
得到本地镜像

由此镜像创建容器
docker run -id --name=my_concainer -p 8080:80  <images-id>

现在就可以直接访问8080端口
** 刷新404 去nginx配置文件中修改下 try_file $uri $uri/ /index.html

本地镜像推送到远程仓库

# 首先我们需要去注册一个dockerhub账户
# 类似于github 这样子的一个镜像的仓库
$ docker login
# 登陆、输入用户名和密码

# 如果我们有提前在dockerhub上建仓库、那么我们的镜像名称就要和远端仓库的保持一致
# 报错:requested access to the resource is denied

# 修改本地镜像名称 和docker用户名保持一致
# 有点慢、需要耐心等待
# 这样就可以成功上传

$ docker search xxx/xxx
# 这样子可以搜所到、但是拉取的时候记得加版本号、因为没有上传latest版本、所以会抛下面的错误
# Error response from daemon: manifest for huhufeng/nginx_vue:latest not found: manifest unknown: manifest unknown
# 可以搜索下是否可以搜到、然后可以拉到本地跑一下、看看效果