Docker实战–以jeecgboot项目为例

  • Post author:
  • Post category:其他




背景

实际开发中如何使用docker?本例使用

jeecgboot项目

为例实战一下。下载代码开始实战。



环境准备

本例全程在centos上操作,需要安装一下环境, 安装过程略。可以参考:

Linux环境安装一



Linux环境安装二

  1. git
  2. docker
  3. maven 3.6+
  4. node 14.17.0
  5. yarn



总述

  1. 简单来说, docker主要由 远程仓库(repository)、本地镜像(image)、本地容器(container)组成。基本使用过程为:远程镜像–下载–>本经镜像–运行–>本地容器
  2. 可以直接使用官方镜像,即:下载、运行、使用, 如本例中的redis
  3. 对于需要添加定制内容的,一般使用Dockerfile构建,如本例中的mysql,在mysql官方镜像中添加了项目数据库,是镜像运行后,容器中就有原始数据库
  4. 对于自研项目,一般使用Dockerfile构建, 如本例中的 springboot项目,从jdk镜像开始构建,并添加了本项目的jar包和启动命令
  5. 容器之间有依赖关系,需要注意启动顺序,被依赖的应先启动容器,否则有依赖的容器启动不能成功
  6. 使用docker-compose可以批量构建镜像和启动容器,本例中有介绍docker-compose的用法
  7. 本文适合有一定docker基础的开发者浏览



docker安装

还是记录一下docker安装命令,

官方安装说明

,这个是centos的安装说明,其他平台可自行切换。

# 卸载旧版本
yum remove docker \
	docker-client \
	docker-client-latest \
	docker-common \
	docker-latest \
	docker-latest-logrotate \
	docker-logrotate \
	docker-engine

yum install -y yum-utils

# 设置镜像仓库, 这里我们改为国内阿里云的,保证速度
yum-config-manager \
	--add-repo \
	https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 更新yum软件包索引
yum makecache fast

# 安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io

# 使用docker version查看是否安装成功
docker version



后端项目

后端项目涉及Java项目、MySQL、Redis,比前端项目更为复杂,一般的做法是,分开准备镜像, 然后使用docker-compose统一启动。



redis

Redis无特殊配置,直接使用官方镜像即可。

# 查找镜像
docker search redis

# 下载镜像, 默认最新版本
docker pull redis:[tag]

# 运行镜像
docker run --name redis01 -d -p 6379:6379 redis:latest

# 使用redis-cli测试
docker exec -it redis01 /bin/bash

docker进入容器内操作

# 进入docker容器测试redis是否安装按成
# docker exec -it 容器id bashshell
docker exec -it redis01 /bin/bash
 > redis-cli
 > set a 10
 > get a
 ...



mysql

  1. dockerfile

    对于需要定制的镜像,使用dockerfile构建,查看…/db/Dockerfile, 分析一下

# 指定初始镜像
FROM mysql:8.0.19
# 说明作者
MAINTAINER jeecgos@163.com
# 定义变量
ENV TZ=Asia/Shanghai
# 执行命令
# 建立软连接 指定时区
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 复制sql文件, 此处我们不使用微服务, 先注释掉
# COPY ./tables_nacos.sql /docker-entrypoint-initdb.d

# 复制sql 本系统数据库
COPY ./jeecgboot-mysql-5.7.sql /docker-entrypoint-initdb.d
# 复制sql 也暂不需要
# COPY ./tables_xxl_job.sql /docker-entrypoint-initdb.d
  1. 构建镜像
docker build -t jmysql:0.0.1 .
REPOSITORY            TAG                      IMAGE ID       CREATED              SIZE
jmysql                0.0.1                    1e786d62ffb8   About a minute ago   553MB
  1. 运行容器
docker run --name=jmysql01 -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root jmysql:0.0.1
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                                  NAMES
6b4b9f5f1a31   jmysql:0.0.1   "docker-entrypoint.s…"   8 seconds ago   Up 6 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   jmysql01

如果要建立目录映射

docker run -p 3306:3306 --name jmysql01 \
-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=root \
-d mysql:0.0.1
  1. 测试

    可以测试一下端口及数据情况。



Java项目

  1. 查看…/jeecg-boot-module-system/Dockerfile文件, 仍然分析一下
# 指定打包基础  anapsix/alpine-java:8_server-jre_unlimited是一个Java8环境
FROM anapsix/alpine-java:8_server-jre_unlimited
# 说明作者
MAINTAINER jeecgos@163.com
# 创建镜像时执行命令
# 文件夹软连接
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 创建项目文件目录
RUN mkdir -p /jeecg-boot
# 指定工作区, 即容器默认在此目录运行
WORKDIR /jeecg-boot
# 暴露端口
EXPOSE 8080
# 将jar包添加到镜像中
ADD ./target/jeecg-boot-module-system-3.0.jar ./
# 容器运行时执行命令
# 停顿60s 启动项目
CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.0.jar
  1. 打包项目jar包
mvn clean install
cd ...system
mvn clean package
# ...
  1. 构建docker镜像
docker build -f Dockerfile -t jserver:0.0.1 .
REPOSITORY            TAG                      IMAGE ID       CREATED         SIZE
jserver               0.0.1                    331b24fc463b   8 seconds ago   306MB
  1. 这里涉及docker容器访问docker容器问题
  • docker容器运行时会自动分配网络, 所以容器之间是可以直接通过ip访问的, 但是使用IP有一定的局限, 当IP变化时, 则需要修改需要访问的容器。

  • 使用 –link [目标容器] 可以实现主机名(容器名)访问

  1. 运行容器
docker run --name=jserver01 -d -p 8080:8080 --link redis01 --link jmysql01 jserver:0.0.1
CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS         PORTS                                                  NAMES
175696301f09   jserver:0.0.1   "/bin/sh -c 'sleep 6…"   9 seconds ago   Up 9 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp              jserver01
  1. 也可以先测试下

    浏览器访问:http://ip:8080/jeecg-boot



前端项目

前端项目比较简单, 只是nginx+静态资源

  1. dockerfile.

    下载代码后发现已经有一个dockerfile文件,学习研究一下(使用注释加以说明):

# docker镜像从nginx开始构建
FROM nginx
# 说明作者
MAINTAINER jeecgos@163.com
# 挂载docker镜像tmp目录到宿主机tmp目录
VOLUME /tmp
# 定义变量 LANG=en_US.UTF-8
ENV LANG en_US.UTF-8
# 运行命令, 将nginx配置覆盖写入到默认配置文件 && 创建静态资源目录(配置和资源目录需要对应起来)
# 这里修改了监听端口
RUN echo "server {  \
                      listen       80; \
                      location ^~ /jeecg-boot { \
                      proxy_pass              http://jserver01:8080/jeecg-boot/; \
                      proxy_set_header        Host jserver01; \
                      proxy_set_header        X-Real-IP \$remote_addr; \
                      proxy_set_header        X-Forwarded-For \$proxy_add_x_forwarded_for; \
                  } \
                  #解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \
                  location / { \
                     root   /var/www/html/; \
                      index  index.html index.htm; \
                      if (!-e \$request_filename) { \
                          rewrite ^(.*)\$ /index.html?s=\$1 last; \
                          break; \
                      } \
                  } \
                  access_log  /var/log/nginx/access.log ; \
              } " > /etc/nginx/conf.d/default.conf \
    &&  mkdir  -p  /var/www \
    &&  mkdir -p /var/www/html
# 将宿主机dist/内容添加到镜像/var/www/html/下
ADD dist/ /var/www/html/
# 暴露端口 80和443
EXPOSE 80
EXPOSE 443


说明:

  1. 由于后台容器名字不同,此处我修改了nginx后台配置,将

    proxy_pass http://jeecg-boot:8080/jeecg-boot/;

    修改为

    proxy_pass http://jserver01:8080/jeecg-boot/;

    同理修改

    Host jserver01
  2. 否则镜像打包/容器运行时可能发生错误,当然,也可以根据具体错误,做相应处理
  3. 容器运行日志查看

    docker logs [container id]
  1. 打包

    根据上述dockerfile文件可知, 我们需要先将前端打包到dist下

这里有一个坑, 本项目前端配置文件中将后台地址写死了, 我们这里修改为相对地址

# .ev.production
# VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
VUE_APP_API_BASE_URL=/jeecg-boot
# 使用yarn打包
yarn install
yarn run build

# 或者使用npm/cnpm
npm install
npm run build

  1. 构建镜像
# docker build [OPTIONS] PATH | URL | -
docker build -f Dockerfile -t jeecg-front:0.0.1 .


docker build的一点说明:

-f 指定dockerfile文件, 如果不制定, 则使用当前目录下的 Dockerfile 文件, 当然也可以指定路径

-t,–tag 指定镜像名及标签,支持指定多个标签

  1. 查看镜像
docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
jeecg-front   0.0.1     095bad917cd8   About a minute ago   150MB
  1. 运行容器
docker run --name=jfront01 -d -p 80:80 --link jserver01 jeecg-front:0.0.1
  1. 查看容器
docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                        NAMES
9d396e169316   jfront:0.0.1   "/docker-entrypoint.…"   7 seconds ago   Up 7 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   jfront01

  1. 测试

    使用浏览器访问, 正常。这样我们就完成项目的docker部署了。



docker网络

有上面可知 docker内部可以通过

--link [container]

的方式实现访问, 自定义docker网络是更好的互相访问方法。

  1. 容器之间的访问

    上面启动容器的时候我们总是映射了端口到宿主机, 实际上除了前端服务外, 其他容器并不需要向外提供服务, 完全不用映射端口。见下文

  2. 自定义docker网络

# docker有默认网络但是默认不能直接通过容器名访问, 必须使用--link指定, 可以自定义一个网络来实现
# 查看现有网络
docker network ls
# 新增网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 jnet

docker network create [option] [net name]

–driver 驱动, 默认使用bridge即可

–subnet 子网范围

–gateway 网关

  1. 为容器指定使用网络
# 不指定网络其实使用的是默认网络
# docker run -d -P --name tomcat01 tomcat
# 等价于 => docker run -d -P --name tomcat01 --net bridge tomcat
docker run -d [other option] --net jnet [image]

# 我们使用自定义网络重新运行我们的四个容器
# 停止 并删除
docker ps -aq|xargs docker stop|xargs docker rm

# 运行容器
docker run -d --net jnet --name redis01 redis:latest
docker run -d --net jnet --name jmysql01 -e MYSQL_ROOT_PASSWORD=root jmysql:0.0.1
docker run -d --net jnet --name jserver01 jserver:0.0.1
docker run -d --net jnet --name jfront01 -p 80:80 jfront:0.0.1

  1. 验证

    success.



docker-compose(一)

有上面可知, 本项目至少涉及四个镜像,如果要做负载均衡或者数据库集群则会更多, 一一启动太麻烦,使用docker-compose可以批量启动。

docker-compose相关内容可以参考

  1. 源码中已经写好docker-compose.yml 根据实际参数, 稍微调整一下
# docker-compose版本, 2 指令最多, 1将被弃用
version: '2'
# 服务
services:
  # 服务名
  # jeecg-boot-mysql:
  mysql:
    # 镜像, 可以是线上的 也可以是本地的
    # image: 81.70.17.111:5000/jeecg-boot-mysql:1.0
    image: jmysql:0.0.1
    # 变量
    environment:
      MYSQL_ROOT_PASSWORD: root
    restart: always
    # 容器名称
    container_name: jmysql01
    # 启动命令, 使用command可以覆盖容器启动后默认执行的命令
    command:
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --explicit_defaults_for_timestamp=true
      --lower_case_table_names=1
      --max_allowed_packet=128M
    # 映射端口
    ports:
      - 3306:3306
  
  # redis
  # jeecg-boot-redis:
  redis:
    # 如果本地没有, 则会去仓库下载
    image: redis:5.0
    # 端口映射
    ports:
      - 6379:6379
    restart: always
    # 容器名称
    container_name: redis01
  
  # 后台服务
  jserver:
    # 镜像
    # image: 81.70.17.111:5000/jeecg-boot-system:1.0
    image: jserver:0.0.1
    restart: always
    container_name: jserver01
    # 文件路径挂载 宿主机:容器
    volumes:
      - /data/config:/jeecg-boot/config
    ports:
      - 8080:8080
    links:
      # 此处关联的是本文件中服务的名字
      - mysql
      - redis
    # 增加关联配置, server依赖 redis和mysql
    depends_on:
      - mysql
      - redis
  
  # web
  front:
    # image: 81.70.17.111:5000/nginxhtml
    image: jfront:0.0.1
    restart: always
    container_name: jfront01
    ports:
      - 80:80
    # 增加容器访问link
    links:
      # 此处关联的是本文件中服务的名字
      - jserver
    # 增加关联配置, 前端依赖后端server
    depends_on:
      - jserver
  1. 使用docker-compose创建并启动容器
# docker-compose是docker官方开源的项目, 需要额外安装
# 本例使用的centos 8 
# compose 安装说明
# https://docs.docker.com/compose/install/
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 清除之前的容器
docker ps -aq|xargs docker stop|xargs docker rm

# 执行 docker-compose, 在docker-compose.yml同目录下执行
docker-compose up -d
  1. 验证页面

    success.



docker-compose(二)

docker-compose也可以从构造开始操作。再次使用compose实现,这次注意:

  • 自己的镜像从build开始
  • 通过新建网络的方式实现容器之间的访问。尝试构建两个网络, 网络一:前端容器和后端容器;网络二:后端容器和redis及mysql之间
  • 不再映射多余的端口, 只映射前端访问端口
  1. 准备mysql、前后端的dockerfile和构建文件, 本例建了三个文件夹, 将需要的文件依次放入

    1. mysql(mysql)

      • Dockerfile
      • XXX.sql
    2. 后端(server)

      • Dockerfile
      • jar包
      • application.yml文件
    3. 前端(front)

      • Dockerfile
      • dist
  2. 修改整理一下

    docker-compose.yml

# docker-compose版本, 2 指令最多, 1将被弃用
version: '2'
# 服务
services:
  # 服务名
  mysql:
    # 镜像, 构建
    build: ./mysql
    image: jmysql:0.0.1
    # 变量
    environment:
      MYSQL_ROOT_PASSWORD: root
    restart: always
    # 容器名称
    container_name: jmysql01
    # 启动命令, 使用command可以覆盖容器启动后默认执行的命令
    command:
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --explicit_defaults_for_timestamp=true
      --lower_case_table_names=1
      --max_allowed_packet=128M
    # 指定使用服务网络
    networks: 
      - server-net

  
  # redis
  redis:
    # 使用官方镜像
    image: redis:5.0
    restart: always
    # 容器名称
    container_name: redis01
    # 指定使用服务网络
    networks: 
      - server-net


  # 后台服务
  jserver:
    build: ./server
    image: jserver:0.0.1
    restart: always
    container_name: jserver01
    # 文件路径挂载 宿主机:容器
    volumes:
      - /data/config:/jeecg-boot/config
    
    # 增加关联配置, server依赖 redis和mysql
    depends_on:
      - mysql
      - redis
    # 添加两个网络
    networks: 
      - front-net
      - server-net
  
  # web
  front:
    build: ./front
    image: jfront:0.0.1
    restart: always
    container_name: jfront01
    ports:
      - 80:80
    # 增加关联配置, 前端依赖后端server
    depends_on:
      - jserver
    # 使用前端网络
    networks: 
      - front-net
      
# 建两个网络
networks:
  server-net:
    driver: bridge
  front-net:
    driver: bridge
  1. 执行测试
# 清除现有的镜像和容器
# 先清除容器
docker ps -aq|xargs docker stop|xargs docker rm
# 再删除镜像
docker images -q|xargs docker rmi

# 执行docker-compose
docker-compose up -d
  1. 访问测试

    见页面。success



docker镜像上传和下载

联合部署时 我们可以将镜像传输到公司私有仓库, 然后供其他同事下载部署。这里我们使用

阿里云 -> 容器镜像服务 -> 个人实例

为目标仓库, 记录上传过程。

阿里云准备过程略

# 登录
docker login --username=username registry.cn-hangzhou.aliyuncs.com
# 提交和上传镜像
# docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/deping/learn:[镜像版本号]
# docker push registry.cn-hangzhou.aliyuncs.com/deping/learn:[镜像版本号]
docker tag [imageid] registry.cn-hangzhou.aliyuncs.com/deping/learn:1.0.0
docker push registry.cn-hangzhou.aliyuncs.com/deping/learn:1.0.0

# 拉取镜像
# docker pull registry.cn-hangzhou.aliyuncs.com/deping/learn:[镜像版本号]
docker pull registry.cn-hangzhou.aliyuncs.com/deping/learn:1.0.0

# 尝试运行下载的镜像
docker run -d --name jfront02 -p 8080:80 registry.cn-hangzhou.aliyuncs.com/deping/learn:1.0.0

# 测试 success

支持从代码库自动构建, 可以是用阿里云/github等代码托管

不支持gitee

  • 挖个坑,后续尝试一下通过代码仓库直接构建。。。。。

使用官方仓库推送和下载, 需要前往官方镜像网站注册账号, 下文以账号zhagnsan演示,

以下本例未尝试

# 打标签
# docker tag [imageid] [username]/[image name]:[tag]
docker tag 124553552 zhangsan/test:1.0.1

# 上传
docker push zhangsan/test:1.0.1

# 拉取同一般拉取
docker pull zhangsan/test:1.0.1



docker导入和导出

很多时候, 客户服务器是内网,我们需要将我们镜像导出后使用U盘等方式传递镜像。



导出

# 导出镜像
# docker save [option] [targetfile] image
docker save -o XXX.tar jfront:0.0.1

# 导出容器
# docker export [option] [targetfile] container
docker export -o xxx.tar jfront01



导入

# 导入镜像
# docker load -i [image file]
# docker load < [imagefile]
docker load < xxx.tar

# 导入容器
# docker import [options] file|URL|- [REPOSITORY[:TAG]]
docker import xxx.tar jfront:0.0.1


注意:

  1. 即使是import容器, 也是一个镜像, 需要手动 run
  2. 导出镜像即时当初构建的镜像,导出容器可以保留在容器中的修改,所以如果容器启动后有修改,建议导出容器



一个镜像搞定

有时候,一个小项目要给客户交付四五个镜像, 客户觉得太麻烦,希望我们一个镜像搞定。还是以上述项目为例。


思路:

从centos开始,依次安装jdk、nginx 、mysql、redis,运行jar包。

  1. 准备安装包

    • Java8
    • mysql 5.7
    • redis 5
    • nginx
    • redis
    • 后端项目.jar
    • 前端项目文件夹
  2. 编写Dockerfile文件
FROM centos
MAINTAINER zhangsan@163.com
# ...
# 留个坑




docker服务及容器自启动

  1. docker服务随系统启动

    systemctl enable docker
    
  2. docker容器自启

    # 启动容器是 添加 --restart always
    # 举例
    docker run -d --name jfront01 --restart always -p 80:80 jfront:0.0.1
    



其他常用docker命令

# 镜像
# 查看
docker images
docker image ls

# 删除
docker rmi [image id]
docker image rm [image id]

# 容器
# 查看容器
docker ps -a
docker ps -aq
# 删除
docker rm [contain id]

# 查看日志
docker logs [contain id]

# 其他
# 复制主机和容器文件
docker cp [container]:/path /home/
docker cp  /home/aa.java [container]:/path


# 查看镜像元数据
docker inspect [container id]

  • docker --help
docker --help
# 当前shell下 attach连接指定运行的镜像
attach Attach local standard input, output, and error streams to a running container

#  通过Dockerfile定制镜像
build Build an image from a Dockerfile 

# 提交当前容器为新的镜像
commit Create a new image from a container's changes 

# 拷贝文件
cp Copy files/folders between a container and the local filesystem 

# 创建一个新的容器
create Create a new container 

# 查看docker容器的变化
diff Inspect changes to files or directories on a container's filesystem 

# 从服务获取容器实时时间
events Get real time events from the server 

#  在运行中的容器上运行命令作业练习
exec Run a command in a running container 

# 导出容器文件系统作
export Export a container's filesystem as a tar archive 

#  展示一个镜像形成历史
history Show the history of an image 

# 列出系统当前的镜像
images List images 

# 从tar包中导入内容创建一个文件系统镜像
import Import the contents from a tarball to create a filesystem image 

#  显示全系统信息
info Display system-wide information 

# 查看容器详细信息
inspect Return low-level information on Docker objects 

#  kill指定docker容器
kill Kill one or more running containers 

# 从一个tar包或标准输入中加载
# 一个镜像[对应save]
load Load an image from a tar archive or STDIN 

# 登入和登出
login Log in to a Docker registry 
logout Log out from a Docker registry

# 查看日志
logs Fetch the logs of a container

pause Pause all processes within one or more containers

port List port mappings or a specific mapping for the container

ps List containers

pull Pull an image or a repository from a registry

push Push an image or a repository to a registry

rename Rename a container

restart Restart one or more containers

rm Remove one or more containers

rmi Remove one or more images

run Run a command in a new container

save Save one or more images to a tar archive (streamed to STDOUT by default)

search Search the Docker Hub for images

start Start one or more stopped containers

stats Display a live stream of container(s) resource usage statistics

stop Stop one or more running containers

tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

top Display the running processes of a container

unpause Unpause all processes within one or more containers

update Update configuration of one or more containers

version Show the Docker version information

wait Block until one or more containers stop, then print their exit codes



版权声明:本文为Lee_0220原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。