前言
现代部署应用很多都是使用docker,因为docker的易用性和快速部署,资源的消耗等优势。现在很少用裸机直接部署。然后k8s是更进一步,是一个容器编排管理工具。由于实际生产部署k8s和运维比较的复杂。本篇目的是为了新手能快速体验k8s部署应用。避免安装虚拟机,服务器等前置环境问题。故在windows系统下进行。
本篇相关术语和概念
docker
dockerfile文件:可以理解为是部署应用的一个设计图纸,上面画出了如何构建应用的步骤
镜像:镜像是用来创建容器的基础。你可以将镜像理解为一个静态的文件系统快照,包含了应用程序及其依赖项
容器:根据镜像启动应用后。这个运行的应用/服务称作一个容器。使用 docker run
命令启动一个镜像时,Docker 会创建一个容器,加载镜像中的文件系统,并启动指定的进程
docker部署流程
k8s
docker安装
首先环境基础需要有docker。使用我们的老朋友docker desktop
下载
然后测试是否可用
配置docker的加速
国外的速度很慢,必须要换源一下
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false,
"features": {
"buildkit": true
},
"registry-mirrors": [
"https://docker.1panel.live"
]
}
springboot应用
先准备一个springboot应用,如果没有可以用idea的新建module。快速创建一个springboot应用
勾选web依赖
把相关的端口记下。默认是8080。
编写测试代码
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public String sayHello() {
return "Hello, World!";
}
}
编写dockerfile
先运行下package按钮,打包一下。
然后观察target的内容,可以看见默认规则是spring.application.name的应用名加上版本
docker配置文件
"docker镜像构建的图纸",采用分阶段构建,可以加快镜像分发,和镜像层的复用
# 第一阶段:构建并提取分层
FROM openjdk:17-slim AS builder
WORKDIR /java
ARG JAR_FILE=target/demo-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
RUN java -Djarmode=layertools -jar app.jar extract
# 第二阶段:构建最终镜像
FROM openjdk:17-slim
WORKDIR /java
COPY --from=builder /java/dependencies/ ./
COPY --from=builder /java/spring-boot-loader/ ./
COPY --from=builder /java/snapshot-dependencies/ ./
COPY --from=builder /java/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
EXPOSE 8080
构建镜像
在项目根目录执行构建镜像-t后面的代表构建的镜像名字
docker build -t demo-server .
运行镜像
根据镜像启动应用。demo-server ,-p映射容器内部8080端口到外部宿主机8082端口。左侧是宿主机,右侧是容器内部
直接启动
docker run -p 8082:8080 demo-server
后台启动
docker run -d -p 8082:8080 demo-server
好了,可以看到正常访问成功了
k8s安装
安装方式一
1.如果用docker desktop可以使用自带的k8s组件快速启动
但是这方式在以前可以,现在dockerhub被墙了。我们需要能访问就比较麻烦。因为需要拉取k8s相关镜像。然后出现一直在拉取的的情况。
解决方式可以参考:
安装方式二
minikube.sigs.k8s.io/docs/start/…
使用minikube安装,按照文档操作即可。支持跨平台。非常适合 Kubernetes 的学习和开发
先装个choco包管理器
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
安装minikube
choco install minikube
启动集群
minikube start
安装方式三
安装kind
choco install kind
创建集群
kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry.qcloud.com"]
kind create cluster --config kind-config.yaml --name k8s1
最后都要验证下看下是否可用
验证集群状态
kubectl cluster-info
查看节点
kubectl get nodes
安装habor
私有镜像仓库,后面要把我们的镜像传上去才能用
下载 Harbor 安装包
wget https://github.com/goharbor/harbor/releases/download/v2.11.2/harbor-online-installer-v2.11.2.tgz
解压安装包
sudo mkdir -p /opt/harbor
sudo tar xvf harbor-online-installer-v2.11.2.tgz -C /opt/harbor
cd /opt/harbor
配置 Harbor
把这个配置文件先改名下去掉tmpl后缀,修改上我们的hostname,port,密码信息
运行安装脚本
./prepare
./install.sh
配置证书(可选)
cd /opt/harbor/harbor/common/config/nginx/
编辑证书的配置。因为是docker里面的这个路径的证书。这点要注意一下
sudo docker-compose down
sudo docker-compose up -d
登录到私有仓库
换成自己的ip
docker login 192.168.1.100 -u admin -p Admin123
docker login -u admin -p 123456 47.xx.11.197:80
注意如果是没有自己配证书得,记得docker要配置一下不安全地址,不然无法拉取,差不多是
{ "insecure-registries" : ["47.xxx.11.197:80"] }
构建镜像
docker tag demo-server:latest 47.xx.11.197:80/library/demo-server:latest
上传镜像
把docker镜像加载到k8s的集群中
docker push 47.xx.11.197:80/library/demo-server:latest
然后就可以看见habor有我们传的镜像了
下面就是拉取这个镜像进行使用
kubectl create secret docker-registry my-harbor-secret \
--docker-server=47.120.11.197:80 \
--docker-username=admin \
--docker-password=123456
编写配置文件
在项目根目录下创建
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-server
spec:
replicas: 3
selector:
matchLabels:
app: demo-server
template:
metadata:
labels:
app: demo-server
spec:
containers:
- name: demo-server
image: 47.xx.11.197:80/library/demo-server:latest
ports:
- containerPort: 8080
service.yaml
apiVersion: v1
kind: Service
metadata:
name: demo-server-service
spec:
selector:
app: demo-server
ports:
- protocol: TCP
port: 8082
targetPort: 8080
type: LoadBalancer
在Kubernetes社区中,分离Deployment和Service是一种常见的最佳实践。这有助于团队成员之间的一致性和协作,所以写2个文件。
应用配置
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
观察启动情况
可以通过命令kubectl看服务情况
kubectl get deployment
kubectl get pods
获取访问地址和port
kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}"
kubectl get services demo-server-service -o jsonpath="{.spec.ports[0].nodePort}"
直接访问应用的api是否正常
移除配置
kubectl delete deployment demo-server
移除服务
kubectl delete service demo-server-service
移除所有
kubectl delete pods --all
kubectl delete deployments --all
CI/CD集成
这块是一般更应用的生态走的,通常和代码库gitlab,github等都有自带的ci/cd构建,但是很多都有限制条件。而jenkins是免费的无限制的。此次使用的jenkins来演示这个效果。jenkins在企业目前还是有很多的应用。
安装jenkins
sudo docker run --name jenkins -d -p 8081:8080 -p 50000:50000 \
-u 0 -v /home/jenkins_home:/var/jenkins_home -m 1024m \
--restart=always jenkins/jenkins:lts-jdk11
默认容器内是jenkins账户,root没有操作docker容器内目录的权限,-u 0 可以用外面的root账户
覆盖容器的账户设置
安装启动后首页有个localhost:8081有配置密码的,账户是jenkins
cat /var/jenkins_home/secrets/initialAdminPassword
创建 Jenkins 部署文件,大致如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: jenkins/jenkins:lts-jdk11
ports:
- containerPort: 8080
- containerPort: 50000
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "1000m"
securityContext:
runAsUser: 0
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-pvc
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 30000
- port: 50000
targetPort: 50000
selector:
app: jenkins
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
创建 Jenkinsfile
pipeline {
agent {
kubernetes {
label 'jenkins-slave'
defaultContainer 'jnlp'
yaml """
apiVersion: v1
kind: Pod
metadata:
name: jenkins-slave
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.11-4
args: ['$(JENKINS_SECRET)', '$(JENKINS_NAME)']
- name: maven
image: maven:3.8.1-jdk-11
command:
- cat
tty: true
"""
}
}
stages {
stage('Clone Repository') {
steps {
git branch: 'main', url: 'https://github.com/your-repo/your-project.git'
}
}
stage('Build') {
steps {
container('maven') {
sh 'mvn clean package'
}
}
}
stage('Test') {
steps {
container('maven') {
sh 'mvn test'
}
}
}
stage('Deploy') {
steps {
script {
if (env.BRANCH_NAME == 'main') {
sh 'kubectl apply -f k8s/deployment.yaml'
}
}
}
}
}
}
最后通过触发Pipeline就可以实现自动化的持续集成和持续交付