一站式服务,从入门到入土,嘴对嘴一口口喂您,不要一分钱,全部免费送。 先谢赞,人在美国,刚下飞机,已跟小姨子私奔。
后面会再写一篇k8s调k8sApiService.createDeployments()接口通过已上传的镜像实现自动化部署的教程,这样我们就可以实现使用k8s无限套娃(我部署我自己,或者说是我部署我自己的克隆人),敬请期待。
那么我们开始正题吧:
1.开放docker.service
加上:-H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock --insecure-registry=172.16.0.131
vi /lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -D --tlsverify=true --tlscert=/home/user/certs/server-cert.pem --tlskey=/home/user/certs/server-key.pem --tlscacert=/home/user/certs/ca.pem -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock --insecure-registry=172.16.0.131 systemctl daemon-reload service docker restart//重启启动docker systemctl status docker/2.Docker签名认证,生成docker ce.pem等证书
第一步: 首先,我们需要选择一个放证书的文件夹,这个文件夹很多文章,包括官网都建议创建一个.docker文件夹,我个人认为,这个文件夹在哪里不重要,只要能保证服务器安全,防火墙有效,就可以了。 在/home/user/下面创建了一个/certs/文件夹。用$pwd,就可以看到该文件夹是/home/user/certs/。转到该文件夹, 执行如下命令:$ openssl genrsa -aes256 -out ca-key.pem 4096, 生成CA私钥,并设置pass phrase,我设置的就是123456,比较简单,因为是测试环境。但是要记住这个密码,后边命令还会用到。 再输入:$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem, 生成CA公钥,也就是证书。还让你输入国家名,省名啥的,这些都是随便填一个就行,因为密钥算法会把这些信息加密进密钥的。值得一提的是Common Name,说是要你填写,server FQDN或your name,意味着可以随便写,但是我在这里建议,写Docker所在服务器的IP,这个很重要。这个IP后边还会用到,我这里是192.168.99.101,在生产环境下,用使用你docker宿主机的DNS name替换下面的填入Common name,如api.google.com等,这个IP不难拿到,你用$ifconfig命令就可以拿到。我在这里填CDH是错误的 第二步: 生成服务器私钥,命令如下: $openssl genrsa -out server-key.pem 4096 再用私钥生成服务器公钥请求文件,也就是证书,命令如下: $openssl req -subj "/CN=172.16.0.131" -sha256 -new -key server-key.pem -out server.csr, 这里的172.16.0.131同样是Docker所在服务器的IP,用自己的Docker服务器替换上去。 下面我们可以用CA来签署证书了。这里我们可以填写IP地址或则DNS name,如,我们需要允许10.10.10.20和127.0.0.1连接: $echo subjectAltName = IP:10.10.10.20, IP:127.0.0.1 > extfile.cnf, 上述命令有点像一个过滤器,如果地址填的不全,远程API就无法访问该Docker,那么我们就把,地址填的全一些,我的命令是这样滴: $echo subjectAltName = DNS:172.16.0.131, IP: 172.16.0.131, IP:0.0.0.0, IP:127.0.0.1 > extfile.cnf 然后,将上述多个生成信息,写入文件。用如下命令。 $openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf 再看客户端私钥: $openssl genrsa -out key.pem 4096 下一步再生成客户端证书请求文件: $openssl req -subj '/CN=client' -new -key key.pem -out client.csr 用CA为客户端签署证书文件: $openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf 这时候,还需要输入密码,我的密码是admin123,输上去即可。 第三步:使用证书 还是要回到我们上文提到的docker.service文件中,那个文件里需要添加上你为它生成的文件的路径和文件名。 ExecStart=/usr/bin/dockerd -D --tlsverify=true --tlscert=/home/user/certs/server-cert.pem --tlskey=/home/user/certs/server-key.pem --tlscacert=/home/user/certs/ca.pem -H tcp://0.0.0.0:2376 -H fd:// 这里把所有的认证文件都加上了准确的路径。 再重新装载配置文件 $sudo systemctl daemon-reload,回车 $sudo service docker restart,回车 $sudo service docker status,来查看进程状态。参考:https://blog.csdn.net/yaofeng_hyy/article/details/80923941?utm_source=blogxgwz2
或者使用脚本自动生成:安全的docker-api的使用(java)
3.部署这个微服务时,需要用到 ce.pem等证书,所以在Dockerfile里构建容器时需要copy进容器,或者也可以选择yaml挂载证书。
#基础镜像,如果本地仓库没有,会从远程仓库拉取 FROM openjdk:8-jdk-alpine #容器中创建目录 RUN mkdir -p /usr/local/pasq RUN mkdir -p /usr/local/pasq/file #编译后的jar包copy到容器中创建到目录内 COPY k8s-0.0.1-SNAPSHOT.jar /usr/local/pasq/k8s.jar COPY key.pem /usr/local/pasq/key.pem COPY ca-key.pem /usr/local/pasq/ca-key.pem COPY ca.pem /usr/local/pasq/ca.pem COPY cert.pem /usr/local/pasq/cert.pem #指定容器启动时要执行的命令 ENTRYPOINT ["java","-jar","/usr/local/pasq/k8s.jar"]4.yaml挂载文件路径,里面会存储程序里生成的jar和Dockerfile
deployment.yaml:注意volumeMounts和volumes里的name要相同
apiVersion: apps/v1 kind: Deployment metadata: name: k8s062908-deploy namespace: default spec: replicas: 1 selector: matchLabels: app: k8s062908 release: stabel template: metadata: labels: app: k8s062908 release: stabel env: test spec: containers: - name: k8s062908 #这里注意是命名空间+仓库名称 image: registry.cn-hangzhou.aliyuncs.com/xxxxx/k8s062908:1.0 #本地有的话取本地,没有的话取远程仓库 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 #容器内挂载点 volumeMounts: - mountPath: /usr/local/pasq/file name: vm-patha volumes: - name: vm-patha hostPath: path: /usr/local/pasq/fileservice.yaml正常写就行
apiVersion: v1 kind: Service metadata: name: k8s062908 namespace: default spec: type: NodePort selector: app: k8s062908 release: stabel ports: - name: http port: 8080 targetPort: 8080 nodePort: 310285.编写上传附件接口
<body> <p>单文件上传</p> <form method="POST" enctype="multipart/form-data" action="/api/v1/loadToRepository/yangsenjohnson/2.0/" id="fm"> 文件:<input type="file" name="file"/> </form> <button id="submit" style="height: 40px;width: 80px;margin-top: 20px">提交</button> <script> var s = document.getElementById("submit"); s.onclick = function(){ var fm = document.getElementById("fm"); fm.submit(); } </script> </body>起一个新线程:
try { String imageName = (("".equals(registryAddress) || registryAddress == null) ? "" : (registryAddress + "/")) + project + "/" + file.getOriginalFilename().split("\\.")[0] + ":" + version; String rUsername = new String(registryUserName.getBytes("ISO-8859-1"), "utf-8"); if (file.isEmpty()) { System.out.println("upload Jar isEmpty loadImageToRepository"); } new UploadThread( registryAddress, dockerHost, rUsername, registryPassword, file.getOriginalFilename(), imageName, file.getInputStream(), file, dockerCertPath, dockerPath, dockerVersion) .start(); } catch (IOException e) { System.err.println("获取文件流失败"); }6.通过k8s API的readNamespacedSecret获取保存的docker密钥
7.通过docker-java的dockerClient.pushImageCmd接口进行推送镜像至阿里云镜像仓库
1)file文件流只能读取一次,需要放在最前面处理,之前放在后面的buildImageCmd之前处理时,file.isEmpty()会为空,这样file.transferTo(dest)时会找不到临时文件,
// 获取上传的文件名 start file文件流只能读取一次,需要放在最前面处理 String fileName = file.getOriginalFilename(); System.out.println("upload Jar filename1 " + fileName); String filepath = dockerPath; System.out.println("upload Jar filepath 1" + filepath); File dest = new File(filepath + "/" + fileName); System.out.println("upload Jar path1: " + filepath + "/" + fileName); if (dest.isFile()) { System.out.println("upload Jar isFile1 "); } System.out.println("upload Jar 21: "); try { if (!dest.isDirectory()) { // 如果文件夹不存在就新建 dest.mkdirs(); } if (dest.isAbsolute()) { System.out.println("upload Jar isAbsolute1:"); } System.out.println("upload Jar 21: "); file.transferTo(dest); System.out.println("upload Jar to path success"); } catch (IOException e) { e.printStackTrace(); System.out.println("upload Jar to path failed" + e.getMessage()); } // end file文件流只能读取一次,需要放在最前面处理2)将docker的信息注入authConfig
//如果registryAddress为空则为dockerhub,不需要拼接registryAddress AuthConfig authConfig = new AuthConfig(); // new AuthConfig().withUsername(registryUserName).withPassword(registryPassword); if(("".equals(registryAddress)||registryAddress==null)){ authConfig.withUsername(registryUserName).withPassword(registryPassword); }else{ authConfig.withUsername(registryUserName).withPassword(registryPassword) .withRegistryAddress(registryAddress); }3)实例化dockerClient
DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder() .withDockerHost(dockerHost) .withDockerTlsVerify(true) .withDockerCertPath(dockerCertPath) .withDockerConfig(dockerCertPath) .withApiVersion(dockerVersion) .withRegistryUrl("https://index.docker.io/v1/") .withRegistryUsername("username") .withRegistryPassword("password") .withRegistryEmail("email") .build(); DockerCmdExecFactory dockerCmdExecFactory = new JerseyDockerCmdExecFactory() .withReadTimeout(60000) .withConnectTimeout(1000) .withMaxTotalConnections(100) .withMaxPerRouteConnections(10); DockerClient dockerClient = DockerClientBuilder.getInstance(dockerClientConfig) .withDockerCmdExecFactory(dockerCmdExecFactory) .build();4)加载镜像
// 加载镜像 LoadImageCmd loadImageCmd = dockerClient.loadImageCmd(inputStream); loadImageCmd.exec();5)生成Dockerfile
ForFile forFile = new ForFile(dockerPath); if (new File(file.getOriginalFilename()).exists()) { System.out.println(file.getOriginalFilename() + " exists "); } if (new File(dockerPath + "/" + file.getOriginalFilename()).exists()) { System.out.println(dockerPath + "/" + file.getOriginalFilename() + " exists "); } if (new File("./" + file.getOriginalFilename()).exists()) { System.out.println("./" + file.getOriginalFilename() + " exists "); } String filecontent = "FROM openjdk:8-jdk-alpine\n" + "RUN mkdir -p /usr/local/pasq\n" + "RUN mkdir -p /usr/local/pasq/file\n" + "COPY " // + "./" + file.getOriginalFilename() + " /usr/local/pasq/file/" + file.getOriginalFilename() + "\n" + "ENTRYPOINT [\"java\",\"-jar\",\"/usr/local/pasq/file/" + file.getOriginalFilename() + "\"]"; System.out.println(filecontent); File docFileDir = forFile.createFile("Dockerfile", filecontent); /** * 创建文件 * * @param fileName 文件名称 * @param filecontent 文件内容 * @return 是否创建成功,成功则返回true */ public static File createFile(String fileName, String filecontent) { Boolean bool = false; filenameTemp = path + "/" + fileName; // 文件路径+名称+文件类型 File file = new File(filenameTemp); try { // 如果文件不存在,则创建新的文件 if (!file.exists()) { file.createNewFile(); bool = true; System.out.println("success create file,the file is " + filenameTemp); } // 创建文件成功后,写入内容到文件里 writeFileContent(filenameTemp, filecontent); } catch (Exception e) { e.printStackTrace(); } return file; }6)根据Dockerfile构建镜像(看网上的教程都没有这一步,但实际开发过程中发现,没有build只有loadImageCmd的话无法构建jar包,所以需要buildImageCmd)
BuildImageResultCallback callback = new BuildImageResultCallback() { @Override public void onNext(BuildResponseItem item) { System.out.println("BuildResponseItem" + item); super.onNext(item); } }; String imageid = originalImageName; BuildImageCmd buildImageCmd = dockerClient.buildImageCmd(docFileDir); imageid = buildImageCmd.exec(callback).awaitImageId(); System.out.println("imageid:" + imageid);7)获取build返回的imageid后,打tag
dockerClient.tagImageCmd(imageid, imageName.split(":")[0], imageName.split(":")[1]).exec();8)pushImageCmd
// push至镜像仓库 PushImageResultCallback pushImageResultCallback = new PushImageResultCallback() { @Override public void onNext(PushResponseItem item) { System.out.println("id:" + item.getId() + " status: " + item.getStatus()); super.onNext(item); } @Override public void onComplete() { System.out.println("Image pushed completed!"); super.onComplete(); } @Override public void onError(Throwable throwable) { System.out.println("Image pushed onError!"); super.onError(throwable); } }; dockerClient .pushImageCmd(imageName.split(":")[0]) .withTag(imageName.split(":")[1]) .withAuthConfig(authConfig) .exec(pushImageResultCallback) .awaitSuccess();参考:https://blog.csdn.net/u012843873/article/details/84318793