暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Docker实战篇-快速开始

Java软件编程之家 2019-04-04
245

在软件开发技术更新迭代的历史以来,学习一门技术最有上手意义的莫过于来一个helloworld的例子,那么我们学习docker也遵循这种方式。

前面我们通过虚拟化软件已经从windows系统中虚拟出3个节点作为学习docker服务器,接着我们又经历了私服的漫长搭建过程,接下来我们将进入实战环节。

首先我们需要创建一个java springboot web应用,将其打包后上传到节点1,通过docker push命令推送镜像到私服,然后再编写Dockerfile脚本将应用构建出一个镜像,再通过镜像创建和运行docker容器。

通过helloworld实战后,相信读者可以快速体验docker部署独立容器的整个流程和方式。

接下来我们将通过创建一个简单的Java Spring Boot Web应用,将其部署到docker容器中,下面是项目结构:

 

其中pom.xml内容如下:


 

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lazy.study.docker</groupId>
    <artifactId>lazy-study-docker</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>lazy-study-docker</name>
    <description>Demo project for Spring Boot</description>
    <properties>
    <java.version>1.8</java.version>
    </properties>
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    </dependency>


    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    </dependencies>
    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    </project>

    HelloController 类内容如下:

      package com.lazy.study.docker;


      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;


      /**
      * <p></p>
      *
      * @author laizhiyuan
      * @since 2019/3/26.
      */
      @RestController
      public class HelloController {
      @Autowired
      private RedisTemplate<String, Object> redisTemplate;


      @GetMapping("/visitor")
      public String visitor() {
      String result = "Hello World ";
      try {
      Long visitorCount = redisTemplate.opsForValue().increment("visitorCount");


      result += "你是第[" + visitorCount + "]个访客";
      } catch (Exception ex) {
      result += "connection to redis error";
      }
      return result;
      }
      }


       

      RedisAutoConfiguration类内容如下:


        package com.lazy.study.docker;


        import com.fasterxml.jackson.annotation.JsonAutoDetect;
        import com.fasterxml.jackson.annotation.PropertyAccessor;
        import com.fasterxml.jackson.databind.ObjectMapper;
        import org.springframework.cache.annotation.CachingConfigurerSupport;
        import org.springframework.cache.annotation.EnableCaching;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.data.redis.connection.RedisConnectionFactory;
        import org.springframework.data.redis.core.RedisTemplate;
        import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
        import org.springframework.data.redis.serializer.RedisSerializer;


        import java.net.UnknownHostException;


        /**
        * <p>
        * Redis Cache Config Java Class
        * redis命令手册可参考:http://doc.redisfans.com/
        * </p>
        *
        * @author laizhiyuan
        * @date 2018/12/27.
        */
        @EnableCaching
        @Configuration
        @SuppressWarnings("unchecked")
        public class RedisAutoConfiguration extends CachingConfigurerSupport {


        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);


        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);


        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);


        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setKeySerializer(RedisSerializer.string());


        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());


        redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();


        return redisTemplate;
        }
        }


        LazyStudyDockerApplication 类内容如下:

          package com.lazy.study.docker;


          import org.springframework.boot.SpringApplication;
          import org.springframework.boot.autoconfigure.SpringBootApplication;


          /**
          * @author laizhiyuan
          */
          @SpringBootApplication
          public class LazyStudyDockerApplication {


          public static void main(String[] args) {
          SpringApplication.run(LazyStudyDockerApplication.class, args);
          }
          }


          logback.xml内容如下:

            <?xml version="1.0" encoding="UTF-8"?>
            <!-- Logback configuration. See http://logback.qos.ch/manual/index.html -->
            <configuration scan="true" scanPeriod="10 seconds">


            <include resource="org/springframework/boot/logging/logback/base.xml" >
            <property name="LOG_PATH" value="/opt/applications/helloworld/logs" >
            <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <File>${LOG_PATH}/info.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/info-%d{yyyyMMdd}.log.%i</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>2</maxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
            </appender>


            <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
            </filter>
            <File>${LOG_PATH}/error.log</File>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/error-%d{yyyyMMdd}.log.%i
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>2</maxHistory>
            </rollingPolicy>
            <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
            </appender>


            <!-- hibernate日志配置 -->
            <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="ERROR" >
            <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="ERROR" >
            <logger name="org.hibernate.SQL" level="ERROR" >
            <logger name="org.hibernate.engine.QueryParameters" level="ERROR" >
            <logger name="org.hibernate.engine.query.HQLQueryPlan" level="ERROR" >


            <root level="INFO">
            <appender-ref ref="INFO_FILE" >
            <appender-ref ref="ERROR_FILE" >
            </root>


            </configuration>


             

            注意日志保存的路径为:/opt/applications/helloworld/logs后面我们需要把这个路径绑定到宿主机。

            application.properties内容如下:

              server.port=8100


              # Redis数据库索引(默认为0)
              spring.redis.database=0
              # Redis服务器地址
              spring.redis.host=myredis
              # Redis服务器连接端口
              spring.redis.port=6379
              # Redis服务器连接密码(默认为空)
              spring.redis.password=
              # 连接池最大连接数(使用负值表示没有限制)
              spring.redis.lettuce.pool.max-active=8
              # 连接池最大阻塞等待时间(使用负值表示没有限制)
              spring.redis.lettuce.pool.max-idle=-1
              # 连接池中的最大空闲连接
              spring.redis.lettuce.pool.max-wait=8s
              # 连接池中的最小空闲连接
              spring.redis.lettuce.pool.min-idle=0
              # 连接超时时间(毫秒)
              spring.redis.timeout=6000ms
              # 缓存类型
              spring.cache.type=redis


              logging.config=classpath:logback.xml
              debug=true
              logging.level.org.springframework.web=INFO
              logging.level.org.hibernate=INFO
              spring.output.ansi.enabled=DETECT


               

              以上我们罗列一堆代码和配置,应用功能非常简答,就是每当有人访问该应用程序是,程序通过连接redis,原子累计加1后返回上一个值告诉客户端属于第几个访客。为了测试应用,我们启动它,访问:http://127.0.0.1:8100/visitor 结果如下:

               

              因为我们redis并没有部署,所以连接失败,这个我们先不管它,我们目的是知道如何将一个应用部署为docker容器。

               

              接下来没有特别声明的情况下,所有的命令均在node1虚拟机上执行。

              1、创建目录mkdir -p /usr/local/docker/build/myhelloworld

              2、lazy-study-docker打包上传到/usr/local/docker/build/myhelloworld

              笔者打包名称为:

              lazy-study-docker-0.0.1-SNAPSHOT.jar

              3、复制一份jdk到目录/usr/local/docker/build/myhelloworld

              4、在目录/usr/local/docker/build/myhelloworld下编写Dockerfile_helloworld文件,内容如下:

                FROM registry.laizhiy.cn/ubuntu:16.04

                RUN mkdir -p /opt/applications/helloworld &&\
                mkdir -p /opt/software

                COPY jdk1.8.0_161 /opt/software/jdk1.8.0_161

                COPY lazy-study-docker-0.0.1-SNAPSHOT.jar /opt/applications/helloworld/

                ENV JAVA_HOME /opt/software/jdk1.8.0_161
                ENV PATH JAVA_HOME/bin:$PATH

                CMD java -jar /opt/applications/helloworld/lazy-study-docker-0.0.1-SNAPSHOT.jar

                 

                注意FROM后面的基础镜像[ registry.laizhiy.cn/ubuntu:16.04],我们开始使用前面我们在节点2上搭建的私服,这也符合实际操作。目前我们构建上下文目录内容如下:

                 

                整体操作步骤如下:

                1、在私服节点1登录私服:


                  docker login registry.laizhiy.cn
                  docker build -t myhelloworld -f Dockerfile_helloworld .


                  注意:最后面有个点,,代表当前目录所有文件参与构建上下文。运行容器:

                    docker run -d --rm \
                    -v /var/myhelloworld/logs:/opt/applications/helloworld/logs \
                    -p 8100:8100 \
                    --name myhelloworld \
                    myhelloworld:latest


                     

                    停掉宿主机防火墙:

                      systemctl stop firewalld

                       

                      浏览器访问:http://node1:8100/visitor

                       

                      现在myredis还没相关的服务到时笔者打算将myredis也以容器的方式部署,我们会发现,我们应用一般都会使用很多组件或相关服务应用,如果应用很多且集群,我们还是一个一个地以手工构建,运行方式管理Docker就显得力不从心了。所以后面笔者会介绍Docker另一个多容器管理的利器Docker Compose,到时我们再把myredis部署上去,敬请期待。


                      文章转载自Java软件编程之家,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论