专栏首页彤哥读源码7. 死磕 k8s系列之maven安装docker插件

7. 死磕 k8s系列之maven安装docker插件

简介

本章我们将学习如何在maven中集成docker插件,通过maven直接打包docker镜像并将之推送到docker仓库中。

前提

  • 必须已安装docker客户端

创建springboot应用

我们这里使用springboot快速创建一个应用。

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>

    <groupId>com.tt.k8s</groupId>
    <artifactId>docker-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <!-- 生成jar包的名称 -->
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

注意,这里生成的jar包去除掉版本号。

HelloController.java

@RestController
public class HelloController {

    @GetMapping("/hello/{name}")
    public String hello(@PathVariable String name) {
        return "Hello " + name + "!";
    }
}

本地启动,浏览器输入 http://localhost:8080/hello/Andy后成功打印出 HelloAndy!说明应用没问题。

编写Dockerfile文件

在工程的主目录创建Dockerfile文件,并输入以下内容:

#pull base image
FROM openjdk:8-jdk-alpine

#maintainer
MAINTAINER andy

#expose port 8080
EXPOSE 8080

#default command
CMD java -jar /data/docker-test.jar

#copy docker-test.jar to docker image
ADD ./target/docker-test.jar /data/docker-test.jar

FROM,表示基础镜像,这里我们选择一个openjdk的基础镜像。

MAINTAINER,表示作者,随便写。

EXPOSE,暴露的端口。

ADD,表示将target目录下的jar包拷贝到镜像中的对应目录,前一个目录是执行docker build所在的机器,后一个目录是镜像中的目录。

CMD,表示容器启动执行的命令,可以在启动镜像的时候被覆盖。

ENTRYPOINT,表示容器启动的进入点,不可以被覆盖。

CMD和ENTRYPOINT比较容易混淆,这里略作区分。

比如,按照上面Dockerfile的配置:

(1)如果执行 docker run test,则会执行CMD后的命令 java-jar/data/docker-test.jar

(2)如果执行 docker run test/bin/bash,则不会执行CMD后的命令,相当于被覆盖了;

如果把上面配置中的CMD换成ENTRYPOINT:

ENTRYPOINT java -jar /data/docker-test.jar

(1)如果执行 docker run test,则会执行ENTRYPOINT后的命令 java-jar/data/docker-test.jar

(2)如果执行 docker run test/bin/bash,则会执行 java-jar/data/docker-test.jar/bin/bash,这时候 /bin/bash相当于变成ENTRYPOINT后面命令的参数了;

总之,ENTRYPOINT后面的命令是一定会执行的,但CMD却不一定。

集成时间插件

Maven本身是包含时间插件的,但是那个插件取出来的时间为UTC时间,比中国的时间慢8个小时,看着很不爽。

所以,这里我们集成一个时间插件,用于后面自动生成镜像的版本号。

pom.xml中加入以下plugin:

<!--生成当前时间,maven自带的是UTC时间,不符合要求-->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <version>1.4</version>
    <configuration>
        <timestampFormat>yyyyMMddHHmmss</timestampFormat>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>create-timestamp</goal>
            </goals>
        </execution>
    </executions>
    <inherited>false</inherited>
</plugin>

集成dockerfile插件

现在网上流传的docker插件有两个版本,分别是 docker-maven-plugindockerfile-maven-plugin

它们都是同一个作者写的,作者已经明确声明,前者已经被废弃,所以我们这里使用dockerfile插件。

pom.xml中加入以下plugin:

<!-- dockerfile插件 -->
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>
    <version>1.4.10</version>
    <executions>
        <execution>
            <id>default</id>
            <goals>
                <!--如果package时不想用docker打包,就注释掉这个goal-->
                <goal>build</goal>
                <goal>push</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!-- Dockerfile -->
        <dockerfile>Dockerfile</dockerfile>
        <username>admin</username>
        <password>Harbor12345</password>
        <!-- 注意这里的前缀填写前面我们harbor的地址 -->
        <repository>core.harbor.domain/test/${project.artifactId}</repository>
        <tag>${timestamp}</tag>
    </configuration>
</plugin>

注意,这里填写我们前面安装的harbor的用户名、密码和仓库地址。

构建并推送到远程仓库

上面的准备工作做完了,在IDEA的右侧找到maven,点击输入命令的那个框,输入以下命令,点击执行,即可构建/推送一步完成。

clean package dockerfile:build dockerfile:push

如果不出意外,你是怎么都不会成功的。

无限踩坑过程

cannot conn to localhost:2375

如果报连接不上localhost:2375,尝试把IDEA重启下,因为docker安装的过程中会修改环境变量DOCKER_HOST,IDEA好像没有感知到,重启下即可。

如果是使用DeskTop方式安装的docker客户端,需要打个勾,自己百度下这个错误就能查到答案了。

lookup core.harbor.domain on 10.0.2.3:53: no such host

这是因为我们使用的是toolbox安装的docker,而实际上docker的操作是在virtual box虚拟机中,所以这里也要修改虚拟机中的hosts,添加core.harbor.domain域名的映射。

打开桌面上的图标 OracleVMVirtualBox,双击其中正在运行的虚拟机default或者点击上方的“显示”按钮,进入虚拟机内部。

注,这里操作窗口比较小且不可滚动,可以使用XSHELL等工具进入,ip固定为192.168.99.100,用户名为docker,密码为tcuser。

进入后找到/etc/hosts文件添加一行:

# 任意worker节点的ip
xx.xx.xx.xx core.harbor.domain

然后,你会发现没有修改权限,使用 sudo su切换到root,再次修改保存。

再次执行maven构建/推送命令,又来个新错误。

x509: certificate signed by unknown authority

这是因为docker客户端没有配置docker仓库的证书。

打开harbor,选择项目test,点击“镜像仓库”标签页,点击“注册证书”。

在虚拟机的 /etc/docker/certs.d/core.harbor.domain/目录下新建 ca.crt文件,并把刚才下载的证书的内容拷贝进去,保存退出。

root@default:/home/docker# mkdir -p /etc/docker/certs.d/core.harbor.domain/
root@default:/home/docker# cd /etc/docker/certs.d/core.harbor.domain/
root@default:/etc/docker/certs.d/core.harbor.domain# vi ca.crt
root@default:/etc/docker/certs.d/core.harbor.domain# ls
ca.crt

注,这里无法直接使用上传命令,使用拷贝粘贴的方式更快捷。

再次执行maven构建/推送命令,又来个新错误。

denied: requested access to the resource is denied

这是因为docker客户端没有登录到我们的私仓。

虽然,上面我们maven插件中配置了用户名/密码,但是似乎不生效。

打开docker客户端(命令行),登录到远程仓库:

$ docker login core.harbor.domain
Authenticating with existing credentials...
Stored credentials invalid or expired
Username (alan): admin
Password:
WARNING! Your password will be stored unencrypted in C:\Users\01384359\.docker\config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

再次执行maven构建/推送命令,又来个新错误。

413 Request Entity Too Large

报了个413错误,请求体太大,查看镜像的大小大概有122M的样子。

出现这个错误,一般是nginx上传文件时做了限制,这时候我们想一下,我们的harbor是通过Ingress访问的,Ingress是需要一个Ingress Controller的,还记得我们当时装的nginx ingress吗?对了,这里使用的就是nginx。

这时候我们通过kuboard,打开任意一个nginx ingress的web版ssh。

点击终端进入docker容器内部,找到harbor的配置文件,你肯定会问我怎么知道harbor的配置文件在这里,我只能说这只能靠经验了。

root@nginx-ingress-55dfk:/# cd /etc/nginx/conf.d/
root@nginx-ingress-55dfk:/etc/nginx/conf.d# ls
harbor-harbor-harbor-ingress.conf  kube-system-kuboard.conf
root@nginx-ingress-55dfk:/etc/nginx/conf.d# cat harbor-harbor-harbor-ingress.conf
# 省略...
        location / {


                proxy_http_version 1.1;


                proxy_connect_timeout 60s;
                proxy_read_timeout 60s;
                client_max_body_size 1m;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Host $host;
                proxy_set_header X-Forwarded-Port $server_port;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_buffering on;

                proxy_pass http://harbor-harbor-harbor-ingress-core.harbor.domain-harbor-harbor-portal-80;


        }
# 省略...

可以看到,上面的 client_max_body_size的值为1m,这也就意味着上传文件的大小不能超过1M。

我们肯定不能直接修改这里的配置,因为nginx ingress一重启就又会变回1M。

这时候反过来查看harbor ingress的配置。

[root@master kubelet]# kubectl get ingress -n harbor
NAME                    HOSTS                                     ADDRESS   PORTS     AGE
harbor-harbor-ingress   core.harbor.domain,notary.harbor.domain             80, 443   4h1m
[root@master kubelet]# kubectl edit ingress harbor-harbor-ingress -n harbor

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    ingress.kubernetes.io/proxy-body-size: "0"
    ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  creationTimestamp: "2019-11-01T07:32:14Z"
  generation: 1
# 省略...

发现这里有一坨参数,也就是 metadata.annotations下面的部分,添加一行参数:

nginx.org/client-max-body-size: 500m

保存退出,这里的配置会自动同步到nginx ingress那边。

注,这里有个坑,出现这个错误,你去官网或者百度或者谷歌,几乎所有的资料都显示让你修改 proxy-body-size,但是实际上修改这个参数并没有一点效果。

注,还有另外一种方式是修改nginx ingress的ConfigMap中添加一行参数 client-max-body-size:500m

[root@master kubelet]# kubectl get configmap -n nginx-ingress
NAME           DATA   AGE
nginx-config   1      2d2h
[root@master kubelet]# kubectl edit configmap nginx-config -n nginx-ingress

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  server-names-hash-bucket-size: "1024"
  # client-max-body-size: 500m
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"server-names-hash-bucket-size":"1024"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"nginx-config","namespace":"nginx-ingress"}}
  creationTimestamp: "2019-10-30T08:48:50Z"
  name: nginx-config
  namespace: nginx-ingress
  resourceVersion: "2986"
  selfLink: /api/v1/namespaces/nginx-ingress/configmaps/nginx-config
  uid: 38f98f6a-2107-4a42-9b82-58003606d371

注,如果遇到超时的问题,同样是修改Ingress的参数。

再次执行maven构建/推送命令,哎哟我操,终于成功了。

登录到harbor查看

打开项目test,发现下面多了个镜像,可以点进去看看,有一个标签(版本号),正是我们刚才提交的时间。

总结

本章的内容比较多,主要是坑有点多。

(1)maven中配置dockerfile插件;

(2)本地虚拟机中需要配置hosts;

(3)本地虚拟机中需要存放harbor仓库的证书;

(4)Ingress需要修改nginx上传文件body大小的限制。

坑其多也,踩之爽也。

本文分享自微信公众号 - 彤哥读源码(gh_63d1b83b9e01)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 6. 死磕 k8s系列之windows安装docker客户端

    我们平时开发都是在windows的机器上进行,但是操作docker镜像是需要安装docker客户端的,本文将介绍在windows下安装docker客户端的两种方...

    彤哥
  • 8. 死磕 k8s系列之kuboard部署微服务

    获取镜像名称,在harbor中点到docker-test镜像的标签列表中,点击Pull命令下面的复制按钮。

    彤哥
  • 2. 死磕 k8s系列之安装k8s集群(v1.16.2)

    k8s真是一个复杂的东西,每一次安装都可能出现不一样的问题,本文特记录下来彤哥安装过程中出现的一些问题及解决方案。

    彤哥
  • 使用docker部署spring cloud项目详细步骤

    (1)到Oracle官网下载好 jdk-8u181-linux-x64.tar.gz 备用 (2)卸载系统自带的java

    lyb-geek
  • 使用docker部署spring cloud项目详细步骤

    (1)到Oracle官网下载好 jdk-8u181-linux-x64.tar.gz 备用 (2)卸载系统自带的java

    java思维导图
  • 虚拟化明星——深挖轻量级容器docker

    docker是一个轻量级容器,属于操作系统层面的虚拟化技术,封装了文件系统(AUFS)以及网络互联,进程隔离等特性。 传统虚拟化架构: ? docker虚拟化架...

    文彬
  • Docker容器

    如果容器理解为独立运行的一个或一组应用,以及它们的运行态环境。 而虚拟机则为可理解为跑在上面的应用。

    yaohong
  • docker常用操作

    启动镜像nginx并:1.指定容器名称(sunshine-nginx-test);2.后台运行(-d);3.指定端口绑定(-p)

    CS逍遥剑仙
  • Docker常用命令汇总

    docker run image_name apt-get install -y app_name

    小小科
  • Docker常用命令汇总

    一、查看docker信息 1、查看docker版本 docker version 2、显示docker系统的信息 docker info 二、对image的...

    小小科

扫码关注云+社区

领取腾讯云代金券