title: Docker基础
date: 2020-03-19 10:29:51
categories: 微服务基础设施


  • 虚拟机里不能装虚拟机,但可以装Docker
  • 镜像和容器的关系类似于类与对象
  • 容器之间独立,(隔离机制)(沙箱机制)
  • docker由C/S结构组成,我们的命令去请求服务端,服务端返回请求结果

使用脚本自动安装 Docker

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装:

$ curl -fsSL get.docker.com -o get-docker.sh
# 可能会出现 404 错误,请移步下面的特别说明
$ sudo sh get-docker.sh --mirror Aliyun

执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker CE 的 Edge 版本安装在系统中。

2018 年 7 月 21 日,貌似阿里云这边在做调整,故导致 Docker 的 Aliyun 安装脚本不可用,是永久性还是临时性的尚不清除,如果你已经按照之前的操作安装 Docker,请按以下步骤进行修复并重新安装

  • 如果已经使用了 Aliyun 脚本安装并成功的
    • 请先卸载 Docker,命令为:apt-get autoremove docker-ce
    • 删除 /etc/apt/sources.list.d 目录下的 docker.list 文件
  • 使用 AzureChinaCloud 镜像脚本重新安装,命令为:sudo sh get-docker.sh --mirror AzureChinaCloud

配置镜像加速器

请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)(第二个位置为私服Registry)

{
  "registry-mirrors": [
    "https://qy5lms4s.mirror.aliyuncs.com"
  ],
  "insecure-registries": [
    "172.18.48.57:5000"
  ]
}

注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。

之后重新启动服务。

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

注意:如果您之前查看旧教程,修改了 docker.service 文件内容,请去掉您添加的内容(--registry-mirror=https://registry.docker-cn.com),这里不再赘述

Docker镜像

下载

docker pull tomcat
docker pull tomcat:9-jre8
docker pull ip:port/tomcat:9-jre8

列出本地镜像

docker images
docker image ls
  • 镜像下载的是压缩体积大小
  • 可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间
docker system df
  • 列出部分镜像
docker image ls ubuntu

启动

  • 启动tomcat (启动一次新建一个容器)
docker run -p 8088:8080 (--name mytomcat(容器名)) tomcat:9-jre8    
(将Tomcat的8080端口映射到宿主机的8088端口)

docker run -P(大写) tomcat:8-jre8 (宿主机随机端口,docker端口由EXPOSE决定)
  • 启动Ubuntu (启动一次新建一个容器)
$ docker run -it --rm \
    ubuntu:16.04 \
    bash

root@e7009c6ce357:/# cat /etc/os-release

-it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。(将主线程交给Docker)
--rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
ubuntu:16.04:这是指用 ubuntu:16.04 镜像为基础来启动容器。
bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash

虚悬镜像

<none>               <none>              00285df0df87        5 days ago          342 MB

要删除

$ docker image prune

无互交模式时

docker rmi $(docker images -q -f dangling=true)

镜像更新

docker pull ubuntu:16.04

删除镜像

如果该镜像还有容器没有删除,先删除容器

docker image rm [选项] <镜像1> [<镜像2> ...]
docker rmi <镜像1> [<镜像2> ...]

docker image rm 4e7840b49fad
docker rmi tomcat:8-jre8

使用 DockerFile 定制镜像

DockerFile定制镜像

  • 将我的应用程序打包到镜像里,然后可以到处运行
  • 像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建
  • 首先在 /usr/local 目录下新建一个docker 文件夹,再建一个tomcat文件夹,最后建立一个文本文件Dockerfile

Dockerfile脚本

  • 一个定制tomcat的简单例子
FROM tomcat:8-jre8

WORKDIR /usr/local/tomcat/webapps/ROOT/
RUN rm -rf *
RUN echo "hello docker! hello world!" > /usr/local/tomcat/webapps/ROOT/index.html

构建定制对象

  • 构建镜像
docker build -t qblog .

将当前目录打包成压缩包,传到服务端
  • 镜像构建上下文(Context)

上文的构建命令表示 :把当前目录大包为上下文,传到服务端

表面上我们好像是在本机执行各种 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻而易举,这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎(通过REST API),这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

如果在 Dockerfile 中这么写:

COPY ./package.json /app/

这并不是要复制执行 docker build 命令所在的目录下的 package.json,也不是复制 Dockerfile 所在目录下的 package.json,而是复制 上下文(context) 目录下的 package.json

一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。

Dockerfile指令

  • FROM

    • 指定基础镜像(在那个镜像的基础上定制)

    • FROM tomcat:8-8jre
      
  • RUN

    • 用来执行命令行命令(shell格式)

    • RUN echo "hello docker!" > /usr/local/tomcat/webapps/ROOT/index.html
      
  • WORKDIR

    • 用来指定工作目录,可以是Dockerfile 的命令执行目录,或者是bash的默认目录

    • WORKDIR /usr/local/tomcat/webapps/ROOT/
      
      //再次进入容器
      root@swing:/usr/local/docker/tomcat# docker run -it --rm qblog2 bash
      root@528c6fbea908:/usr/local/tomcat/webapps/ROOT#
      

    之前说过每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。

  • COYP

WORKDIR /usr/local/tomcat/webapps/ROOT

COPY my-shop-web-admin-1.0.0-SNAPSHOT.zip .
  • ADD

    • 可以自动解压缩 tar 包

    • 更高级复制,比如 <源路径> 可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径> 去。下载后的文件权限自动设置为 600,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用

  • CMD

    • 用来启动镜像里面的程序
  • ENTRYPOINT

  • ENV

  • VOLUME

  • EXPOSE

    • EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口

Docker 容器

列出Dockers容器及信息

docker ps -a

启动或暂停一个已存在的容器

docker start(stop) 5f7f86902b8c

删除容器和 批量删除

docker rm 2a0c11797f39

//删除所有未运行的容器
docker rm $(sudo docker ps -a -q)

//强行删掉一个容器
root@swing:/usr/local/docker/mysql/conf# docker rm -f mysql

守护态运行

在后台运行,不占用控制台主线程

//启动第一个容器
root@swing:/usr/local/docker/tomcat# docker run -p 8088:8080 --name swing-tomcat -d tomcat:8-jre8 
f100430594dd9700ea36f6f0d03e34378f4a80923a19aacacf3e0706f8dad008

//启动第二个容器
root@swing:/usr/local/docker/tomcat# docker run -p 8089:8080 --name swing-tomcat2 -d tomcat:8-jre8 
cb851d2775fd6214237acf4429c270604418aa137cc812e66a6be2b2e053c502

以bash的方式进入容器

docker exec -it ddfa08d12284 bash

数据卷

数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

  • 数据卷 可以在容器之间共享和重用
  • 数据卷 的修改会立马生效
  • 数据卷 的更新,不会影响镜像
  • 数据卷 默认会一直存在,即使容器被删除

注意:数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷

实例:

root@swing:/usr/local/docker/tomcat# mkdir ROOT
root@swing:/usr/local/docker/tomcat# cd ROOT/
root@swing:/usr/local/docker/tomcat/ROOT# vi index.html

root@swing:/usr/local/docker/tomcat/ROOT# docker run -p 8082:8080 --name volumetest -d \
> -v /usr/local/docker/tomcat/ROOT:/usr/local/tomcat/webapps/ROOT tomcat:8-jre8
261ab7efe7e89b77efec51b9fd2e67fc4379daa72a4b95d5fefff31c03e4d5e0

Docker构建MySQL

  • MySQL 8.0 :InnoDB 支持事务 效率也提高了,支持原生分布式解决方案
docker run -p 3308:3306 --name mysql \
-v /usr/local/docker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=qqhzn.000 \
-d mysql:5.7.22


-p 3308:3306:将容器的3306端口映射到主机的3308端口
-v /usr/local/docker/mysql/conf:/etc/mysql:将主机当前目录下的 conf 挂载到容器的 /etc/mysql
-v /usr/local/docker/mysql/logs:/var/log/mysql:将主机当前目录下的 logs 目录挂载到容器的 /var/log/mysql
-v /usr/local/docker/mysql/data:/var/lib/mysql:将主机当前目录下的 data 目录挂载到容器的 /var/lib/mysql
-e MYSQL\_ROOT\_PASSWORD=123456:初始化root用户的密码
  • 使用数据卷配置MySQL容器最大能导入的sql语句

    • 在启动容器内配置
    //首先启动一个MySQL容器
    docker run -p 3308:3306 --name mysql \
    -v /usr/local/docker/mysql/logs:/var/log/mysql \
    -v /usr/local/docker/mysql/data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=qqhzn.000 \
    -d mysql:5.7.22
    
    //进入这个启动的容器中
    root@swing:/usr/local/docker/mysql# docker exec -it  mysql bash
    
    //查询MySQL配置文件的位置
    root@71a448e1e71a:/# whereis mysql
    mysql: /usr/bin/mysql /usr/lib/mysql /etc/mysql /usr/share/mysql
    
    //查询配置
    root@71a448e1e71a:/# cd /etc/mysql
    root@71a448e1e71a:/etc/mysql# cd conf.d/
    root@71a448e1e71a:/etc/mysql/conf.d# cat mysqldump.cnf 
    [mysqldump]
    quick
    quote-names
    max_allowed_packet	= 16M
    
    //将`max_allowed_packet`的配置追加到mysqld.cnf末尾中
    root@71a448e1e71a:/etc/mysql/mysql.conf.d# echo "max_allowed_packet = 128M" >> mysqld.cnf
    
    
    • 上面配置是临时的修改,当容器销毁后,有需要重新配置,因此要将容器中的配置复制放到宿主机,作用于新容器
    //将容器里的配置文件拷贝入宿主机
    root@swing:/usr/local/docker/mysql/conf# docker cp mysql:/etc/mysql .
    
    //将复制文件内的文件移动到上级目录
    root@swing:/usr/local/docker/mysql/conf/mysql# mv *.* ..
    root@swing:/usr/local/docker/mysql/conf# rm -rf mysql/
    
    //删掉原有的容器
    root@swing:/usr/local/docker/mysql/conf# docker rm -f mysql
    //删掉挂载的数据文件
    root@swing:/usr/local/docker/mysql# rm -rf data/
    
    //新建数据库并挂在数据卷
    root@swing:/usr/local/docker/mysql# docker run -p 3308:3306 --name mysql \
    -v /usr/local/docker/mysql/conf:/etc/mysql \
    -v /usr/local/docker/mysql/logs:/var/log/mysql \
    -v /usr/local/docker/mysql/data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=qqhzn.000 \
    -d mysql:5.7.22
    
    

项目的容器化部署

  • 先初始化数据库数据
  • 再用数据卷导入已经解压的目录
root@swing:/usr/local/docker/tomcat/ROOT# ll
total 20
drwxr-xr-x 5 root root 4096 Mar 17 17:57 ./
drwxr-xr-x 3 root root 4096 Mar 17 14:01 ../
drwxr-xr-x 2 root root 4096 Mar 17 10:05 META-INF/
drwxr-xr-x 4 root root 4096 Mar 17 10:05 static/
drwxr-xr-x 7 root root 4096 Mar 17 10:05 WEB-INF/

root@swing:/usr/local/docker/tomcat# docker run -p 8088:8080 --name myshoptomcat -d \
>  -v /usr/local/docker/tomcat/ROOT:/usr/local/tomcat/webapps/ROOT tomcat:8-jre8
  • 记得修改数据源,并且要先启动MySQL再启动Tomcat
  • 查看tomcat日志
docker logs myshoptomcat

//一直监听者日志的变化
docker logs -f  myshoptomcat

Docker Compose

  • 解决部署多个容器的复杂启动参数,和容器的管理

Compose 中有两个重要的概念:

  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

安装

Docker Compose 存放在Git Hub,不太稳定。你可以也通过执行下面的命令,高速安装Docker Compose。

curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

使用

docker-compose.yml

编写 docker-compose.yml 文件,这个是 Compose 使用的主模板文件。

(不能用 Tab)

caversion: '3'
services:
  tomcat:
    restart: always
    image: tomcat:8-jre8
    container_name: mytomcat
    ports:
      - 8088:8080

运行 compose 项目

root@swing:/usr/local/docker/tomcat# docker-compose up

//守护态
root@swing:/usr/local/docker/tomcat# docker-compose up -d

此时访问本地 8088 端口即可

命令说明

模板文件

docker-compose部署项目

version: '3'
services:
  web:
    restart: always
    image: tomcat:8-jre8
    container_name: myshoptomcat
    ports:
      - 8088:8080
    volumes:
      - /usr/local/docker/myshop/ROOT:/usr/local/tomcat/webapps/ROOT

  mysql:
    restart: always
    image: mysql:5.7.22
    container_name: myshopmysql
    ports:
      - 3308:3306
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: 123456
    command:
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --explicit_defaults_for_timestamp=true
      --lower_case_table_names=1
      --max_allowed_packet=128M
      --sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO"
    volumes:
      - mysql-data:/var/lib/mysql

volumes:
  mysql-data:
  • 导入数据库
  • 解压项目压缩包到ROOT目录下,修改数据源
  • 重启docker-compose
docker-compose up

docker-compose down
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐