docker发布项目的3种方式(war包,jar包,docker-compose)

项目发布流程

war包发布

  1. 服务器上创建新的docker容器(新建一个tomcat包),名称以功能用途命名(eg:java-hello)。
    * mkdir java-hello
    在这里插入图片描述

  2. 登录对应git,在settings-CI/CD-variables下设置新增包(eg:java-hello)路径
    在这里插入图片描述

  3. 切换项目到需要自动发布分支(eg:application-hello.yml )

  4. 修改项目.gitlab-ci.yml文件,新增build与run,修改监控分支与路径

.gitlab-ci.yml

    variables:
      MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=./.m2/repository"
    
    cache:
      paths:
        - ./.m2/repository
    
    stages:
      - build
      - run
    
    image: maven:3-jdk-8
    
    build:
      retry: 1
      only:
        - hello
      stage: build
      tags:
        - java-runner
      script:
        - mvn clean package -T 1C -Dmaven.compile.fork=true -Dmaven.test.skip=true -Phello
      cache:
        paths:
          - target/$PACKAGE    
    run:
      retry: 1
      only:
        - hello
      stage: run
      tags:
        - java-runner
      script:
        - eval $(ssh-agent -s)
        - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
        - mkdir -p ~/.ssh
        - chmod 700 ~/.ssh
        - ssh-keyscan $DEPLOY_SERVER >> ~/.ssh/know_hosts
        - chmod 644 ~/.ssh/know_hosts
        - scp -o StrictHostKeyChecking=no -P 22 target/$PACKAGE root@$DEPLOY_SERVER:$DEPLOY_HELLO
        - ssh -o StrictHostKeyChecking=no -p 22 root@$DEPLOY_SERVER "cd $DEPLOY_HELLO; chmod +x $DEPLOY_SHELL; ./$DEPLOY_SHELL"
        
        
    build_rel:
      retry: 1
      only:
      - release #监控分支
      stage: build
      tags:
      - java-runner
      script:
      - mvn clean package -T 1C -Dmaven.compile.fork=true -Dmaven.test.skip=true -Prel #rel为对应环境
      cache:
        paths:
        - target/$PACKAGE
        
    run_rel:
      retry: 1
      only:
      - release #监控分支
      stage: run
      tags:
      - java-runner
      script:
      - eval $(ssh-agent -s)
      - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
      - mkdir -p ~/.ssh
      - chmod 700 ~/.ssh
      - ssh-keyscan $DEPLOY_SERVER >> ~/.ssh/know_hosts
      - chmod 644 ~/.ssh/know_hosts
      - scp -o StrictHostKeyChecking=no -P 22 target/$PACKAGE root@$DEPLOY_SERVER:$DEPLOY_RELEASE
      - ssh -o StrictHostKeyChecking=no -p 22 root@$DEPLOY_SERVER "cd $DEPLOY_RELEASE; chmod +x $DEPLOY_SHELL; ./$DEPLOY_SHELL"
      
      # 修改root@$ + git配置对应路径

api-redeploy.sh

 #!/bin/bash
 docker_container_name=java-hello #docker容器名称
 java_package_name=java-hello.war #项目名称
 rm -rf ./webapps/ROOT
 unzip -q $java_package_name -d webapps/ROOT
 docker restart $docker_container_name
  1. 将war包上传到java-hello/tomcat下
  2. 上传war包后通过命令运行docker
    docker run -d --name=java-hello --restart=always -e TZ="Asia/Shanghai" -v /disk/logs/docker/apps-logs/java-hello/logs:/home/logs -v /disk/logs/docker/apps-logs/java-hello/tomcat:/usr/local/tomcat -v /disk/logs/docker/apps-logs/java-hello/export:/exprot -v /etc/localtime:/etc/localtime -p 18088:8080 tomcat:9.0.26-jdk8

name 对应docker名(包名)

/disk/logs/docker/apps-logs/java-hello/logs 对应报下log日志包

/disk/logs/docker/apps-logs/java-hello/tomcat tomcat运行包

/disk/logs/docker/apps-logs/java-hello/export 导出包

-p 18088:8080 18088为对外映射端口,8080为默认启动端口

jar包发布

  1. 项目打可运行jar包

Dockerfile 文件

    FROM openjdk:8
    MAINTAINER Lee
    VOLUME ["/etc/localtime:/etc/localtime:ro"]
    ADD demo.jar app.jar
    RUN echo 'Asia/Shanghai' >/etc/timezone
    EXPOSE 8080
    CMD ["java","-jar", "/app.jar", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8080"]

api-redeploy-jar.sh

    #!/bin/bash
    docker_container_name=java-hello
    docker_image_name=java-hello
    docker_mapping_name=java-hello
    docker stop $docker_container_name
    docker rm -f $docker_container_name
    docker rmi $docker_image_name
    docker build -t $docker_image_name .
    docker run -d -p 18055:8080 --name $docker_mapping_name $docker_image_name
  1. Dockerfile 、api-redeploy-jar.sh、可运行jar包上传linux
  2. 在上传的Dockerfile ,可运行jar包文件下执行以下命令
docker build -t 镜像名 . #注意末尾的"."不要忘了
docker run -d -p 8089:8089 --name jy_gentle gentle 
#  -d 后台运行、
#  最后一个 gentle 是引用的镜像的名字、
#  --name jy_gentle 给容器取名为 jy_gentle (取名参数前面是两短横线)、
#  -p 8089:8089 端口映射,注意是小写 p 
# 前一个 8089 是对外浏览器上访问的端口,后一个 8089 是容器内工程本身的端口,两者可不一样

docker-compose发布方式

  1. 将所需发布项目打包,打包方式为jar包
  2. 在服务器上创建一个新的docker容器,名称建议以功能用途命名便于理解
  3. 将打包的jar包上传到新建的docker容器下
  4. 创建docker-compose.yml,将docker-compose上传到docker容器下。

docker-compose.yml

    version: '1'
    services1:
      java-hello: #服务名称
        image: java-hello #镜像名称
        container_name: java-hello #容器名称
        restart: "always" #重启策略,能够使服务保持始终运行,生产环境推荐使用
        ports:
          - 8089:8080 #暴露端口信息
        volumes:
          - /etc/localtime:/etc/localtime:ro #挂载文件
    services2:
      java-hello1: #服务名称
        image: java-hello1 #镜像名称
        container_name: java-hello1 #容器名称
        restart: "always" #重启策略,能够使服务保持始终运行,生产环境推荐使用
        ports:
          - 8090:8080 #暴露端口信息
        volumes:
          - /etc/localtime:/etc/localtime:ro #挂载文件
  1. 建Dockerfile文件,并上传到docker容器下
    Dockerfile文件
FROM openjdk:8	#jdk版本
MAINTAINER Lee	#作者
VOLUME ["/etc/localtime:/etc/localtime:ro"]	#挂在路径
ADD demo.jar app.jar	#项目jar包
RUN echo 'Asia/Shanghai' >/etc/timezone
EXPOSE 8080
CMD ["java","-jar", "/app.jar", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8080"]

startup.sh运行脚本

 #!/bin/bash
 docker build -t java-hello .
 docker-compose -f docker-compose.yml up -d

在这里插入图片描述

  1. 在docker-compose.yml所在路径下执行docker-compose up命令,compose就会自动构建镜像并使用镜像启动容器

所有可能用到命令

  • docker ps -a: 查看docker运行与端口占用
  • docker logs -f -t --tail 1000 docker名 :查看日志
  • docker stop dockerID : 停止对应docker
  • docker start dockerID : 运行对应dokcer
  • docker rm dockerID : 杀死对应docker容器
  • docker rmi dockerID: 杀死对应镜像
  • mkdir 包名
  • cp -r /disk/logs/docker/apps-logs/empty/* /disk/logs/docker/apps-logs/包名/tomcat/

GIT CI/CD下定义变量

DEPLOY_SERVER :127.0.0.1

DEPLOY_SHELL : api-redeploy.sh

PACKAGE : demo.war

DEPLOY_SHOW : /disk/logs/docker/apps-logs/java-hello/tomcat

job内定义作业流程的参数列表

KeywordRequiredDescription
scriptyes定义在runner中执行的命令
extendsnoDefines a configuration entry that this job is going to inherit from
includenoDefines a configuration entry that allows this job to include external YAML files
imagenoUse docker image, covered in Using Docker Images
servicesnoUse docker services, covered in Using Docker Images
stageno定义job属于哪个阶段,默认test阶段
typenostage别名
variablesno定义job层次的变量
onlyno定义哪些分支或tag的修改触发该流程
exceptno定义哪些分支或tag的修改不触发该流程
tagsno定义哪个标签的runner来执行,该标签指runner配置时的名称,不是Git的tag分支
allow_failurenoAllow job to fail. Failed job doesn’t contribute to commit status
whennoDefine when to run job. Can be on_success, on_failure, always or manual
dependenciesno定义该job依赖于哪项job的结果,用于把之前job的附件传进来
artifactsno定义job产生的附件,可用于下载和保存以及传递,没有该项设置产生的过程文件都会被删除
cacheno定义缓存的文件或文件夹,如果是在job外定义则为全局变量
before_scriptno定义job执行前的操作
after_scriptno定义job执行后的操作
environmentnoDefines a name of environment to which deployment is done by this job
coveragenoDefine code coverage settings for a given job
retryno定义任务失败后的重复执行次数或时间
parallelno定义并行的任务数量,限于2~50
triggernoDefines a downstream pipeline trigger

出现过的问题

  1. springboot通过外置war包启动时404
 @SpringBootApplication
 public class DemoApplication extends SpringBootServletInitializer {
 
     public static void main(String[] args) {
         SpringApplication.run(DemoApplication.class, args);
     }
 
     @Override
     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
         return application.sources(DemoApplication.class);
     }
      jar包和war包启动区别:
          jar包:执行SpringBootApplication的run方法,启动IOC容器,然后创建嵌入式Servlet容器
         war包:  先是启动Servlet服务器,服务器启动Springboot应用(springBootServletInitizer),然后启动IOC容器
         
      Servlet 3.0+规则:
        1  服务器启动(web应用启动),会创建当前web应用里面所有jar包里面的ServletContainerlnitializer实例
        2 ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下
        3  还可以使用@HandlesTypes注解,在应用启动的时候加载指定的类。
        
      外部Tomcat流程以及原理:
        ①  启动Tomcat
         ②  据上述描述的Servlet3.0+规则,可以在Spring的web模块里面找到有个文件名为javax.servlet.ServletContainerInitializer的文件,而文件的内容为org.springframework.web.SpringServletContainerInitializer,用于加载SpringServletContainerInitializer类
        ③  SpringServletContainerInitializer定义
      在上面一段长长的注释中可以看到,SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有WebApplicationInitializer这个类型的类都传入到onStartup方法的Set参数中,并通过反射为这些WebApplicationInitializer类型的类创建实例;
        ④  方法最后,每一个WebApplicationInitilizer实现调用自己onstartup方法
        ⑤  而WebApplicationInitializer有个抽象实现类SpringBootServletInitializer(记住我们继承了该抽象类),则会调用每一个WebApplicationInitializer实例(包括SpringBootServletInitializer)的onStartup方法:
      SpringBootServletInitializer实例执行onStartup方法的时候会通过createRootApplicationContext方法来执行run方法,接下来的过程就同以jar包形式启动的应用的run过程一样了,在内部会创建IOC容器并返回,只是以war包形式的应用在创建IOC容器过程中,不再创建Servlet容器了。
  1. springboot是通过内嵌tomcat启动,在使用外置tomcat启动war是缺少web.xml
      public abstract class SpringBootServletInitializer implements WebApplicationInitializer {
      
      	protected Log logger; // Don't initialize early
      
      	private boolean registerErrorPageFilter = true;
      
      	/**
      	 * Set if the {@link ErrorPageFilter} should be registered. Set to {@code false} if
      	 * error page mappings should be handled via the server and not Spring Boot.
      	 * @param registerErrorPageFilter if the {@link ErrorPageFilter} should be registered.
      	 */
      	protected final void setRegisterErrorPageFilter(boolean registerErrorPageFilter) {
      		this.registerErrorPageFilter = registerErrorPageFilter;
      	}
      
      	@Override
      	public void onStartup(ServletContext servletContext) throws ServletException {
      		// Logger initialization is deferred in case an ordered
      		// LogServletContextInitializer is being used
      		this.logger = LogFactory.getLog(getClass());
      		WebApplicationContext rootAppContext = createRootApplicationContext(servletContext);
      		if (rootAppContext != null) {
      			servletContext.addListener(new ContextLoaderListener(rootAppContext) {
      				@Override
      				public void contextInitialized(ServletContextEvent event) {
      					// no-op because the application context is already initialized
      				}
      public interface WebApplicationInitializer {
      
      	/**
      	 * Configure the given {@link ServletContext} with any servlets, filters, listeners
      	 * context-params and attributes necessary for initializing this web application. See
      	 * examples {@linkplain WebApplicationInitializer above}.
      	 * @param servletContext the {@code ServletContext} to initialize
      	 * @throws ServletException if any call against the given {@code ServletContext}
      	 * throws a {@code ServletException}
      	 */
      	void onStartup(ServletContext servletContext) throws ServletException;
      @HandlesTypes(WebApplicationInitializer.class)
      public class SpringServletContainerInitializer implements ServletContainerInitializer {
      
      	/**
      	 * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
      	 * implementations present on the application classpath.
      	 * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
      	 * Servlet 3.0+ containers will automatically scan the classpath for implementations
      	 * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
      	 * such types to the {@code webAppInitializerClasses} parameter of this method.
      	 * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
      	 * this method is effectively a no-op. An INFO-level log message will be issued notifying
      	 * the user that the {@code ServletContainerInitializer} has indeed been invoked but that
      	 * no {@code WebApplicationInitializer} implementations were found.
      	 * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
      	 * they will be instantiated (and <em>sorted</em> if the @{@link
      	 * org.springframework.core.annotation.Order @Order} annotation is present or
      	 * the {@link org.springframework.core.Ordered Ordered} interface has been
      	 * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
      	 * method will be invoked on each instance, delegating the {@code ServletContext} such
      	 * that each instance may register and configure servlets such as Spring's
      	 * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
      	 * or any other Servlet API componentry such as filters.
      	 * @param webAppInitializerClasses all implementations of
      	 * {@link WebApplicationInitializer} found on the application classpath
      	 * @param servletContext the servlet context to be initialized
      	 * @see WebApplicationInitializer#onStartup(ServletContext)
      	 * @see AnnotationAwareOrderComparator
      	 */
      	@Override
      	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
      			throws ServletException {

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值