美文网首页docker
docker和docker-compose的前后端项目部署(含M

docker和docker-compose的前后端项目部署(含M

作者: dreamguys | 来源:发表于2019-02-13 16:35 被阅读0次

    前言

    Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。

    Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。

    Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

    下面两张图比较了传统虚拟机和docker之间的区别

    传统虚拟机 Docker

    从而我们可以看出传统虚拟机是在硬件层面实现的,而docker是在操作系统层面上实现的虚拟化

    p.s.:Hypervisor是一种运行在物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享一套基础物理硬件,因此也可以看作是虚拟环境中的“元”操作系统,它可以协调访问服务器上的所有物理设备和虚拟机,也叫虚拟机监视器(Virtual Machine Monitor)。Hypervisor是所有虚拟化技术的核心。非中断地支持多工作负载迁移的能力是Hypervisor的基本功能。当服务器启动并执行Hypervisor时,它会给每一台虚拟机分配适量的内存、CPU、网络和磁盘,并加载所有虚拟机的客户操作系统。

    现在项目一般为单点登录或者是分布式,而分布式能想到微服务,所以如果把这种思想应用到容器部署中则会有基于单容器部署(类似单点登录)和多容器部署(类似微服务)两种方式,多容器部署即把mysql、rabbitMq、redis等依赖组件和spring boot服务分开成多个容器来部署的方式;单容器部署即把MySQL等其他组件和spirng boot应用放在同一容器的部署方式。

    多容器部署的方式是目前主流的方式,因为具有以下优势:

    1. 方便横向扩展;
    2. 服务可用性高,不会因为一个容器服务挂了而导致所有服务都不能用;
    3. 单个容器不会太臃肿、资源消耗相对较小;
    4. 部署方便。

    多容器的部署方式又有基于docker命令和基于docker-compose命令两种方式。这里首先要再介绍下docker compose。

    Docker Compose 是Docker官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。比较直观的感受是多个容器可以通过一个配置来启动,从而简化了部署过程,我们也可以通过一个配置文件来查看部署的命令等等。

    下面我就介绍基于docker run等docker命令和基于docker compose两种部署方式

    e.g:本文中前端采用pm2工具部署,后端采用spring boot + mysql + redis + rabbitmq

    基于docker命令部署

    后端Spring boot及依赖服务部署

    首先Spring Boot应用依赖于Mysql、redis和RabbitMQ服务,所以我们先把这三个服务部署好。

    在安装部署前我们可以搜索要安装的服务有哪些镜像,可以选择合适我们的。

    docker search 镜像名
    

    例如要搜索mysql的镜像就可以用命令(其他服务同理)

    docker search mysql
    

    MySQL服务部署

    我采用了镜像搜索结果中的第一个镜像

    NAME                                                   DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
    mysql                                                  MySQL is a widely used, open-source relati...   7708      [OK]    
    

    执行镜像拉去命令

    docker pull mysql
    

    使用该命令会去拉取tag为latest的mysql镜像,使用以下命令可以查看本地存在的所有镜像,我们就可看到刚才下载的mysql镜像了。

    docker images   
    

    使用启动镜像的命令:

    docker run --name test-mysql --restart=always -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql --lower_case_table_names=1 --default-authentication-plugin=mysql_native_password
    

    p.s:命令详解

    • --name:给容器命名

    • --restart:容器重启策略

      • no,默认策略,在容器退出时不重启容器
      • on-failure,在容器非正常退出时(退出状态非0),才会重启容器
        • on-failure:3,在容器非正常退出时重启容器,最多重启3次
      • always,在容器退出时总是重启容器
      • unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
    • -p:端口映射,映射逻辑为主机端口:容器端口

    • -e:参数设置,这里的MYSQL_ROOT_PASSWORD就是设置账号名为root的账户的密码

    • -d:后台运行容器

    • mysql:要运行的镜像名

    • --lower_case_table_names=1:设置不区分表名大小写,不然可能会在spring boot应用时报表不存的错误(实际创建的数据库和表为:test.user,报错提示为test.USER is not exist)

    • --default-authentication-plugin=mysql_native_password:mysql版本为8.0以上时需要,因为8.0和5.7的密码加密机制不同,如果本地navicat版本不支持新的加密机制(ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded)则要加上这条命令;如果不加的话也可以通过后续密码的方式来解决。解决方法如下:1.执行命令:docker exec -it 容器id /bin/bash;2.再执行:mysql -h 127.0.0.1 -P 3306 -u root -p,输入密码进去mysql;3.修改密码:ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

    p.s:

    1. 第三步中的BY 'root',root为要设置的新密码。
    2. docker exec -it表示开启交互模式的终端(-it=-i -t)
    3. /bin/bash表示可以执行一些简单的shell命令

    在执行完以上操作后就可以用Navicat等工具链接数据库测试是否搭建成功。

    Redis服务部署

    搜索和下载镜像的部署同MySQL中一样,本文采用的redis镜像为:

    NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
    redis                             Redis is an open source key-value store th...   6431      [OK]       
    

    执行命令启动服务

    docker run -d --name test-redis -p 6379:6379 redis --requirepass 'mypassword'
    

    如果要开启redis的持久化则加上 --appendonly yes
    完成命令如下:

    docker run -d --name test-redis -p 6379:6379 redis --requirepass 'mypassword' --appendonly yes
    

    如果不加--appendonly yes则默认开启redis的RDB模式,如果加了则开启AOF模式。

    redis服务测试:

    docker exec -it 容器id redis-cli -h 127.0.0.1 -p 6379
    

    进入redis后验证密码的命令为:
    auth mypassword

    RabbitMQ服务部署

    本文拉取的rabbitmq的镜像为:(rabbitmq:management)

    NAME                                       DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
    rabbitmq                                   RabbitMQ is an open source multi-protocol ...   2445      [OK] 
    

    运行服务命令:

    docker run -d --hostname localhost --name test-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:management
    

    --hostname:指定容器主机名称

    这里用了两次-p的端口映射是因为5672是给服务用的端口。15672是web端访问的接口

    如果要在启动时同时设置用户和密码可使用一下命令

    docker run -d --hostname localhost --name test-rabbit -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 rabbitmq:management
    

    启动服务后检查是否可以通过访问ip:15672打开web管理页面(使用的镜像如果是rabbitmq:latest则无法打开,如果是rabbitmq:management则可以打开),如果打不开则是因为rabbitmq默认不开启web页面,需要进去容器中设置。执行命令:

    docker exec -it 容器id /bin/bash
    

    在进入容器后执行:

    rabbitmq-plugins enable rabbitmq_management
    

    我们再访问web页面就发现可以打开了。

    Spring Boot服务部署

    在部署完其他的组件后终于可以部署我们的应用了,而整体的思路就是把我们的应用的jar文件变成镜像文件,然后再运行即可。所以首先我们需要把应用打包成jar文件,拷贝到服务器上一个目录下,本文中拷贝到了/opt/test/jar文件夹下,然后在该文件夹下再用命令vi Dockerfile创建文件。

    #指定基础镜像,格式为:FROM image:tag
    FROM java
    
    #维护者信息
    MAINTAINER TEST
    
    #添加要加入的文件,与COPY命令的性质基本一致,但是ADD更强大
    #可添加源路径,可自动解压压缩包,但解压功能和指定目标路径不可同时使用
    #该命令在使用docker run -v时可不用,在后续有介绍
    ADD spring-boot-test.jar /opt/test/test.jar
    #add命令会把config下的所有文件拷贝到容器中的/opt/test/config下,此条代码只用作添加文件夹的讲解示范,
    ADD config /opt/test/config/
    
    #用于指定在容器启动时要执行的命令
    CMD java -jar /opt/test.jar
    
    #为构建镜像设置监听端口,使容器在运行时监听
    EXPOSE 8082
    

    以上就是创建一个简单的Dockerfile的示例。

    然后运行命令:

    docker build -t my-test-image .
    
    • -t:给镜像命名
    • 最后的点表示使用当前上下文中的dockerfile文件

    构建好了可以用以下命令查看是否有自己的镜像了

    docker images
    

    有我们的镜像后就可以运行了。

    docker run -d -p 8082:8082 --name my-spring-boot my-test-image
    

    e.g.(推荐)

    可以在docker run的时候加入-v 来映射数据卷,这样的话在后续版本更新中可方便地替换jar文件。

    docker run -d -p 8082:8082 --name my-spring-boot -v jar:/opt/test
    

    这条命令中 -v后的参数的意思为:把本机的当前目录的jar文件夹映射到容器中的/opt/test文件夹,这样每次更新只需更换test.jar即可(使用数据卷的话可在Dockerfile中把ADD spring-boot-test.jar /opt/test/test.jar这行命令去掉)

    使用以下命令可查看当前运行的镜像

    docker ps
    

    如果要查看运行过的所有镜像(包括以前运行过,现在停止的)

    docker ps -a
    

    如果启动失败了可以通过以下几条命令查看容器日志排查问题

    docker logs [OPTIONS] CONTAINER
    Options:
        --details        显示更多的信息
        -f, --follow         跟踪实时日志
        --since string   显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
        --tail string    从日志末尾显示多少行日志, 默认是all
        -t, --timestamps     显示时间戳
        --until string   显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)
    

    前端pm2部署

    1.首先把项目文件发布到服务器上,本例中放到了/opt/frontend/file下

    2.拉取node镜像,本例中用的node镜像为:

    NAME                                   DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
    node                                   Node.js is a JavaScript-based platform for...   6935      [OK]   
    

    3.使用vi Dockerfile创建文件,文件内容如下:

    #使用的基础镜像
    FROM node:latest
    
    #作者信息
    MAINTAINER test
    
    #把file文件夹下的所有文件添加到容器的/opt/frontend下
    ADD file /opt/frontend/
    
    #在镜像的构建过程中执行特定的命令并生成一个中间镜像,node的镜像中没有pm2,所以在此安装
    RUN npm install -g pm2
    
    #指定工作路径,之后的命令将在此路径上运行
    WORKDIR /opt/frontend
    
    #因为本例中不会自动生成日志文件和文件夹所以在这创建,如果自己的项目不需要的可以去掉这里的命令
    RUN mkdir logs
    RUN touch logs/app.log
    
    #修改脚本的权限,不然会报没有权限的错误
    RUN chmod 775 frontend-start.sh
    
    #npm安装
    RUN npm install
    
    #暴露前端4010端口(根据自己前端服务的端口修改)
    EXPOSE 4010
    
    #执行脚本
    CMD /opt/frontend/frontend-start.sh
    

    e.g:因为CMD命令是只有最后一个才生效,而我们要执行的命令又不止一条,所以采用了运行脚本文件的方式来运行

    脚本文件frontend-start.sh内容如下:

    #pm2部署项目
    pm2 start /opt/frontend/pm2.json
    
    #持续监控日志,让容器不退出
    tail -f /opt/frontend/logs/app.log
    

    4.在编写完这些文件后就可以开始构建镜像

    docker build -t test-frontend .
    

    最后的点表示使用当前上下文中的dockerfile文件

    5.使用docker images命令查看我们构建的镜像

    运行镜像的命令

    docker build -d -p 4010:4010 --name test-frontend test-frontend:latest
    

    6.运行之后我们通过docker ps命令查看容器是否在运行,如果在运行了就可在本地通过浏览器访问地址来打开页面:http://服务器ip:4010

    7.如果运行有错误可通过docker logs 容器id来查看日志解决问题

    基于docker-compose部署

    首先我介绍一下本例子的目录结构

    -docker-compose.yml
    -fontend
      -Dockerfile
      -files(前端项目文件,已包含pm2.json)
    -backend
      -Dockerfile
      -test.jar
    -mysql
      -Dockerfile
      -db
      -sql(要初始化数据库所需要的sql)
    

    前后端的Dockerfile在前文中已经介绍,这里主要相比前文做一些差异化介绍,差一点就在于docker-compose.yml文件和mysql的Dockerfile

    mysql的Dockerfile的内容如下:

    #使用mysql8.0在后续的sql自动执行中会有问题,所以这里采用mysql5.7
    FROM mysql:5.7
    
    MAINTAINER test-mysql-compose
    
    #把sql
    ADD sql /docker-entrypoint-initdb.d
    

    编写该Dockerfile的目的主要是把要初始化mysql数据库的sql文件添加入容器中,把我们想要自动执行的sh文件或sql文件放入/docker-entrypoint-initdb.d中即可,在容器初始化时就会自动执行(原理是在容器中的/docker-enetrypoint.sh文件,容器启动时会去执行该文件,该文件又会去执行/docker-entrypoint-initdb.d中的sh和sql文件)

    e.g.

    这里有两个需要特别注意的问题

    1. 在mysql8.0中如果在docker-compose中添加了volumn的映射就不会再去执行docker-entrypoint.sh文件,而5.7版本没有这个问题。我暂没有找到解决办法,所以这里就采用了5.7版本。
    2. 我在添加了sql文件,执行mysql镜像后出现连不上mysql的问题,报的unknow server的错误,过了十多分钟后才能正常脸上。经过排查才发现是因为sql文件太大导致没有导入完(我的运行了16个SQL文件大概共15.5MB,用了20分钟左右)。这样的问题当然有主机性能等因素影响,所以建议初始化的sql文件尽量要小。

    接下来就是最重要的docker-compose.yml文件的介绍

    #docker-compose的版本
    version: '3'
    
    #定义服务
    services:
    
      #服务名称,可随意定义
      backend:
        build:
          #dockerfile的路径
          context: backend
          #dockerfile的名称
          dockerfile: Dockerfile
        #相当于docker run -v的作用
        volumes:
          - "./jar:/opt/test"
        #容器名称
        container_name: test-backend-compose
        #该服务依赖的其他服务,该配置选项可修改启动顺序
        depends_on:
          - mysql
          - redis
          - rabbitmq
        ports:
          - "8082:8082"
    
      frontend:
        build:
          context: frontend
          dockerfile: Dockerfile
        ports:
          - "4010:4010"
        container_name: test-frontend-compose
    
      mysql:
        build:
          context: mysql
          dockerfile: Dockerfile
        ports:
          - "3306:3306"
        #相当于docker run命令中的-e
        environment:
          MYSQL_ROOT_PASSWORD: root
          #初始化的数据库名称
          MYSQL_DATABASE: test
        container_name: test-mysql-compose
        restart: always
        #数据卷映射关系,把本机的./mysql/db目录映射到容器中的/var/lib/mysql
        volumes:
          - "./mysql/db/:/var/lib/mysql"
        #该选项中的命令会覆盖Dockfile中的CMD中的命令.lower_case_table_names参数是为了表名不区分大小写,default-authentication-plugin是8.0中密码加密策略不同带来的链接问题,如果不用8.0可不加此选项
        command: mysqld --lower_case_table_names=1 --default-authentication-plugin=mysql_native_password
    
      redis:
        image: redis
        ports:
          - "6379:6379"
        container_name: test-redis-compose
        restart: always
        #启动redis服务并添加密码为:123456,并开启redis的持久化
        command: redis-server --requirepass 123456 --appendonly yes
    
      rabbitmq:
        image: rabbitmq:management
        ports:
          - "5672:5672"
          - "15672:15672"
        container_name: test-rabbitmq-compose
        environment:
          #rabbitmq的初始用户名
          RABBITMQ_DEFAULT_USER: admin
          #rabbitmq的初始密码
          RABBITMQ_DEFAULT_PASS: 123456
    
    #指定使用的网络,此处是使用已经提前创建好的自定义网络
    #网络创建命令:docker network create -d bridge --subnet 172.50.0.0/16 cooperationassociation
    #--subnet指定网段 -d指定连接方式,最后的cooperationassociation为网络名称
    #使用新的指定网络是为了防止网段占用完,这样会导致启动容器时XShell会自动退出,且本地用不了访问不了服务(服务器已有大量连接时可能会出现)
    #查看网段占用情况的命令:route -n
    networks:
      default:
        external:
          name: cooperationassociation
    

    编写文件后使用以下命令即可运行

    #-d表示后台运行
    docker-compose up -d
    

    docker-compose还有以下常用命令

    #停止运行并移除容器
    docker-compose down
    
    #启动单个服务
    docker-compose up -d 服务名
    
    #查看当前运行的服务
    docker-compose ps
    
    #构建镜像,--no-cache表示不用缓存,否则在重新编辑Dockerfile后再build可能会直接使用缓存而导致新编辑内容不生效
    docker-compose build --no-cache
    
    #查看镜像
    docker-compose images
    
    #查看日志
    docker-compose logs
    
    #启动/停止服务
    docker-compose start/stop 服务名
    
    #拉取镜像
    docker-compose pull 镜像名
    

    以上只是一些最常用的命令,我们也可以看出常用的docker命令在docker-compose中也可使用。

    相关文章

      网友评论

        本文标题:docker和docker-compose的前后端项目部署(含M

        本文链接:https://www.haomeiwen.com/subject/rvudeqtx.html