0%

创建一个注解AuthToken

所有使用这个注解的方法,均要通过权限验证才能访问。

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthToken {
    /**
     * 是否只能管理员权限才能访问,默认所有用户都可以访问
     */
    boolean admin() default false;
}

创建一个拦截器AuthInterceptor

所有请求都通过拦截器

public class AuthInterceptor extends HandlerInterceptorAdapter {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        AuthToken authToken = method.getAnnotation(AuthToken.class);
        //需要验证的Method
        if (authToken != null) {
            boolean isAdmin = authToken.admin();
            //todo
            return true;
        }
        //无需验证
        return true;
    }
 
}

注册拦截器

@Configuration
public class AuthConfigurer implements WebMvcConfigurer {
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(AuthInterceptor()).addPathPatterns("/**");
    }
 
    @Bean
    public AuthInterceptor AuthInterceptor() {
        return new AuthInterceptor();
    }
}

controller方法上添加注解

#需要管理员权限才能访问的
@AuthToken(admin = true)
 
#普通用户和管理员都能访问的
@AuthToken
 
#不加注解是所有人都可以访问的,不安全

环境准备

  1. 安装docker-ce(过程省略)
  2. 安装docker-compose(过程省略)
  3. 安装harbor

下载Harbor离线安装包

  1. 下载地址:http://harbor.orientsoft.cn/,找个最新的,本文使用v1.5.0版本
  2. 使用 tar xvf harbor-offline-installer-v1.5.0.tgz
  3. 进入到解压后的目录,harbor/

配置harbor.cfg【关键配置】

#hostname设置访问地址,可以使用ip、域名,不可以设置为127.0.0.1或localhost
hostname = harbor.deri.com
 
# 访问协议,默认是http,也可以设置https,如果设置https,则nginx ssl需要设置on
ui_url_protocol = http
 
#配置admin用户的密码,默认Harbor12345
harbor_admin_password = Harbor12345
 
#是否只允许admin用户创建项目,everyone是所有人都可以
project_creation_restriction = adminonly
 
# 是否开启自注册
self_registration = on
 
# Token有效时间,默认30分钟
token_expiration = 30

配置docker-compose.yml

如果需要修改访问端口,默认80443,也可以不修改.

##此处粘贴部分配置  
  proxy:
    image: vmware/nginx-photon:v1.5.0
    container_name: nginx
    restart: always
    volumes:
      - ./common/config/nginx:/etc/nginx:z
    networks:
      - harbor
    ports:
      - 80:80
      - 443:443
      - 4443:4443
    depends_on:
      - mysql
      - registry
      - ui
      - log
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "proxy"

启动harbor

harbor/目录下,执行./install.shharbor会根据当前目录下docker-compose.yml配置,下载相关镜像,并启动。

配置本地hosts文件

配置hosts文件,增加部署机器的 IP 和 域名【域名是harbor.cfg中的hostname

Windows: C:\Windows\System32\drivers\etc\hosts 
Linux: /etc/hosts

访问Harbor

浏览器输入hostname,用户名密码:admin/Harbor12345

Harbor首页

上传镜像

创建项目

注意选择访问级别
Harbor创建项目

使用docker login登录到私有仓库

[root@node4 ~]# docker login harbor.deri.com
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
 
Login Succeeded

这里有个问题

执行上面的一步肯定会报错:Error response from daemon: Get https://harbor.deri.com/v2/users/: dial tcp 192.168.41.139:443: getsockopt: connection refused,原因是docker认为这个仓库不可信,需要在/etc/docker/daemon.json不存在就新建)增加insecure-registries配置,注意是标准的json格式!

{
  "insecure-registries": ["harbor.deri.com"]
}

然后重启docker服务

sudo systemctl daemon-reload
sudo systemctl restart docker

重启harbor服务

#到harbor/目录下执行
docker-compose down -v
docker-compose up -d

本地随便找个镜像

修改其tag,如

docker tag hub.c.163.com/library/mysql:5.7 harbor.deri.com/deri/mysql:5.7

注意tag格式:域名/项目名/镜像名:版本

上传镜像

docker push harbor.deri.com/deri/mysql:5.7

登录UI查看

harbor镜像仓库

从私有镜像仓库拉取镜像

docker pull harbor.deri.com/deri/mysql:5.7

退出登录

docker logout harbor.deri.com

使用结束!接下来创建项目、用户了。

有时候我们需要将k8s集群外的服务引入到集群内部来,便于集群内部服务调用,我可以使用Endpoints.

引入外部myql

编写k8s-mysql-endpoints.yaml

为外部Mysql创建Endpoints

apiVersion: v1
kind: Endpoints
metadata:
  name: mysql
  namespace: default
subsets:
  - addresses:
      - ip: 192.168.1.11
    ports:
      - port: 20030
  1. 可以使用命令kubectl get endpoints查看是否创建完成
  2. kubectl describe endpoints mysql 查看具体描述

编写k8s-mysql-service.yaml

编写k8s-mysql-service.yaml,为endpoints发布成内部pod可以调用的服务

注意metadata.namek8s-mysql-endpoints.yamlmetadata.name保持一致,此处均为mysql.

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 20030
  1. 可以使用命令 kubectl get svc 查看是否服务创建完成
  2. kubectl describe svc mysql 查看具体服务描述

测试endpoints是否生效

为了方便测试endpoints是否生效,我们修改上述的k8s-mysql-service.yaml配置

  1. 我们将type类型改为NodePort,这样可以设定宿主机上的映射端口号nodePort:30030,这样直接通过宿主机IP:30030就可以调用到mysql服务。
  2. 注意删除了创建好的service,对应的endpoints也会删除掉,需要重新创建!测试的时候注意!
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: NodePort
  ports:
  - port: 20030
    targetPort: 20030
    protocol: TCP
    nodePort: 30030

使用Navicat测试

使用Navicat测试,输入宿主机IP和端口30030(用户名密码还是外部数据库原本的用户名密码),测试连接!成功!证明了通过Endpoints机制可以将外部服务发布成k8s内部的服务!

发布外部的redis服务也是同理,只需要修改nameportip等参数即可!

consul具体配置、ACL配置可以参考Consul系列文章

首先创建k8s-consul-config.json文件

注意token需要自己创建一个,这里加密处理了

{
    "datacenter":"dc8",
    "primary_datacenter":"dc8",
    "acl":{
        "enabled":true,
        "default_policy":"deny",
        "enable_token_persistence":true,
        "enable_key_list_policy":true,
        "tokens":{
            "master":"14d54c5e-24ca-****-*******-*********"
        }
    }
}

创建configmap

kubectl  create configmap consul --from-file=k8s-consul-config.json

上述命令创建一个名称为consul,内容为一个文件,文件名为k8s-consul-config.jsonconfigmap可以挂载在volume下.

修改 k8s-consul-statefulset.yaml文件

注意内容:

  1. 在配置最后挂载了volumes-configmap,就是我们刚刚创建的consul
  2. - “-config-file=/etc/consul/config/k8s-consul-config.json” 配置了我们保存的consul ACL相关配置
  3. requiredDuringSchedulingIgnoredDuringExecution,我们增加了这个配置,保证了consul的pod不会在同一台机器上运行【反亲和特性】,因为我们将consul/data挂载的是hostPath,如果一台机器启动多个会有冲突导致consul启动卡住。
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: consul
spec:
  serviceName: consul
  replicas: 3
  template:
    metadata:
      labels:
        app: consul
        component: server
    spec:
      serviceAccountName: consul
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - consul
              topologyKey: kubernetes.io/hostname
      terminationGracePeriodSeconds: 10
      containers:
      - name: consul
        image: consul:1.6.0
        args:
          - "agent"
          - "-server"
          - "-bootstrap-expect=3"
          - "-ui"
          - "-data-dir=/consul/data"
          - "-config-file=/etc/consul/config/k8s-consul-config.json"
          - "-bind=0.0.0.0"
          - "-client=0.0.0.0"
          - "-advertise=$(PODIP)"
          - "-retry-join=consul-0.consul.$(NAMESPACE).svc.cluster.local"
          - "-retry-join=consul-1.consul.$(NAMESPACE).svc.cluster.local"
          - "-retry-join=consul-2.consul.$(NAMESPACE).svc.cluster.local"
          - "-domain=cluster.local"
          - "-disable-host-node-id"
        volumeMounts:
          - name: data
            mountPath: /consul/data
          - name: config
            mountPath: /etc/consul/config
        env:
          - name: PODIP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        ports:
          - containerPort: 8500
            name: ui-port
          - containerPort: 8400
            name: alt-port
          - containerPort: 53
            name: udp-port
          - containerPort: 8443
            name: https-port
          - containerPort: 8080
            name: http-port
          - containerPort: 8301
            name: serflan
          - containerPort: 8302
            name: serfwan
          - containerPort: 8600
            name: consuldns
          - containerPort: 8300
            name: server
      volumes:
        - name: data
          hostPath:
            path: /root/consul/data
        - name: config
          configMap:
            name: consul

最后根据上面的配置重新创建consul的StatefulSet,启动完成后根据之前consul的知识,我们需要使用master token登录到ui,创建Agent token,然后修改configmap中acl配置,增加agent token,具体可以参考之前的文章。然后删除consul的pod,让k8s重新创建新的pod,使我们新的configmap生效即可。

用途 命令
查看集群状态 kubectl cluster-info
查看集群详细状态 kubectl cluster-info dump
查看节点 kubectl get nodes
查看节点更多信息 kubectl get nodes -o wide
标志一个节点不可调度 kubectl cordon -nodeName
标志一个节点可调度 kubectl uncordon -nodeName
查看token列表 kubeadm token list
创建token kubeadm token create
删除节点 kubectl drain <node name> --delete-local-data --force --ignore-daemonsets/kubectl delete node <node name>
创建一个deployment kubectl create deployment nginx --image=nginx
查看deployments kubectl get deployment(deployments)
创建一个service kubectl create service nodeport nginx --tcp 80:80
查看services kubectl get svc(service/services)
删除一个deployment kubectl delete deployments/nginx
删除一个service kubectl delete services/nginx
同时删除deployment和service kubectl delete deployments/nginx services/nginx
从yaml文件创建deployment kubectl create -f deployment.yaml
查看pods kubectl get pods(pod)
查看pod更多信息 kubectl get pods -o wide
查看具体pod信息 kubectl describe pods/kube-node-59bf664cbf-2qzgd
修改deployment kubectl edit deployments/test
从yaml创建service kubectl create -f service.yaml
快捷创建service(expose) kubectl expose deployment kube-node --type=NodePort
查看service具体信息 kubectl describe services/kube-node
查看namespace kubectl get namespace
创建namespace kubectl create namespace -name
删除namespace kubectl delete namespace -name
根据配置文件创建configmap kubectl create configmap my-config --from-file=path/to/bar/kubectl create configmap my-config --from-file=key1=/path/file1.txt --from-file=key2=/path/to/bar/file2.txt
从字符串创建configmap kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
从env文件创建configmap kubectl create configmap my-config --from-env-file=path/to/bar.env
扩容 kubectl scale deployment nginx-deployment --replicas 10
自动扩容 kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
更新镜像 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
回滚 kubectl rollout undo deployment/nginx-deployment
查看默认配置项,如pod.spec kubectl explain pod.spec

以上都是亲自用过的,没用过的自己查表,附上kubectl命令表

kubectl命令自动补全

CentOS Linux系统上,您可能需要安装默认情况下未安装的bash-completion软件包。

yum install bash-completion -y

执行source <(kubectl completion bash)命令在您目前正在运行的shell中开启kubectl自动补全功能。

可以将上述命令添加到shell配置文件中,这样在今后运行的shell中将自动开启kubectl自动补全:

echo "source <(kubectl completion bash)" >> ~/.bashrc

快速生成YAML样例

# 用run命令生成
kubectl run --image=nginx my-deploy -o yaml --dry-run > my-deploy.yaml
# 用get命令导出
kubectl get statefulset/foo -o=yaml --export > new.yaml
# Pod亲和性下面字段的拼写忘记了
kubectl explain pod.spec.affinity.podAffinity

问题1:ip问题

consul
使用容器方式在主机上部署后,consul节点的ip为容器IP,如上图所示,主机外不能访问到该服务,需要配置内网或公网IP。

使用docker

使用docker run命令启动consul只需要在run后增加 --net = "host" ,这相当于使用主机上的IP。

#注意1是要指定net为host,2是网卡为主机上的网卡,该网卡主机外服务能访问到,可以使用ifconfig看看网卡具体的名字
docker run --net = "host" --name ** -e CONSUL_BIND_INTERFACE='eth0' ....(省略)

使用docker-compose

使用docker-compose启动docker,需要指定network_modehost

#原本配置,eth0为容器内网卡
  consul_server_2:
    container_name: consul_server_2
    image: consul:1.6.0
    networks: 
      consul:
        ipv4_address: 172.20.0.3
    volumes:
      - /docker/consul/server2/config:/consul/config
      - /docker/consul/server2/data:/consul/data
    environment:
      - CONSUL_BIND_INTERFACE=eth0
      - TZ=Asia/Shanghai
      - CONSUL_HTTP_TOKEN=db98c304-4d38-8660-fafe-6a4be56a40d0
    restart: always
    command: [
      'agent'
    ]
 
 
#优化后,映射端口不需要了,因为是直接使用主机ens33网卡了
  consul_server_1:
    container_name: consul_server_1
    image: consul:1.6.0
    network_mode: host
    volumes:
      - /docker/consul/server1/config:/consul/config
      - /docker/consul/server1/data:/consul/data
    environment:
      - CONSUL_BIND_INTERFACE=ens33
      - TZ=Asia/Shanghai
      - CONSUL_HTTP_TOKEN=db98c304-4d38-8660-fafe-6a4be56a40d0
    restart: always
    command: [
      'agent'
    ]

这样启动后consul服务的ip会变成主机的ip,外面的服务可以访问,跨机器部署consul集群通信也不会有问题了
consul

但是以上办法一台机器只能启动一个consul容器,多了会有端口占用的问题,如果想要单机部署多个consul节点,可以考虑修改consul端口。

//新增ports.json放到consul的配置目录下即可。配置目录下所有.json配置都会加载
//默认端口参考官网:https://www.consul.io/docs/agent/options.html#ports
{
  "ports": {
    "dns":9600,
    "http":9500,
    "serf_lan":9301,
    "serf_wan":9302,
    "server":9300
  }
}

启动后同一台机器上两个consul都启动了,占用不同端口,类似可以继续增加consul节点数量,他们的IP都是一样的

consul
consul

问题2:跨机器加入集群报错

#client
2019/10/11 03:48:01 [INFO] agent: (LAN) joining: [192.168.41.128]
consul_client_2    | ==> 1 error occurred:
consul_client_2    | 	* Failed to join 192.168.41.128: No installed keys could decrypt the message
 
#server端
consul_server_1    |     2019/10/11 03:48:18 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48362
consul_server_1    |     2019/10/11 03:48:18 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48364
consul_server_1    |     2019/10/11 03:48:31 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48438
consul_server_1    |     2019/10/11 03:48:31 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48440
consul_server_1    |     2019/10/11 03:48:57 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48598
consul_server_1    |     2019/10/11 03:48:57 [ERR] memberlist: failed to receive: No installed keys could decrypt the message from=192.168.41.129:48600
所有consul节点加入配置
"encrypt":"Cwqvm4elg0SIaF6xanFxZ3OFYadEiQtZ71xY1mJTUbk="
 
此encrypt官方解释是用与集群通信加密的,生成方式 consul keygen
 
依然报错不能解决
//所有节点加入以下配置,删除encrypt,下面的配置字面意思,出入的通信都不在验证,问题解决,不在报错
    "encrypt_verify_incoming":false
    "encrypt_verify_outgoing":false

上面的配置是把验证功能关掉了,有安全隐患,官网还有另一个配置disable_keyring_file,(https://github.com/hashicorp/consul/issues/4163)有人可以解决,但是我尝试没有成功,后面继续研究有没有两全其美的办法。。

start_join、retry_join的格式

-join-启动时要加入的另一个代理的地址。可以多次指定,以指定要加入的多个代理。如果Consul无法加入任何指定地址,则代理启动将失败。默认情况下,代理在启动时不会加入任何节点。请注意,retry_join在Consul群集部署自动化时,使用 更为合适的方法有助于减轻节点启动竞争条件。
 
 
-retry-join-与类似,-join但如果第一次尝试失败,则允许重试连接。在您知道该地址最终可用的情况下,这很有用。该列表可以包含IPv4,IPv6或DNS地址。在Consul 1.1.0及更高版本中,可以将其设置为 go-sockaddr 模板。如果Consul在非默认的Serf LAN端口上运行,则也必须指定此端口。IPv6必须使用“括弧式”语法。如果给出了多个值,则按照列出的顺序尝试并重试它们,直到第一个成功。这里有些例子:
 
# Using a DNS entry
$ consul agent -retry-join "consul.domain.internal"
 
# Using IPv4,只有IP
$ consul agent -retry-join "10.0.4.67"
 
# Using IPv6,带端口
$ consul agent -retry-join "[::1]:8301"
 
#配置文件中格式
    "start_join":[
        "192.168.41.128:8301"
    ],
    "retry_join":[
        "192.168.41.128:8301"
    ],

问题:No installed keys could decrypt the message 报错解决

新加入的consul节点需要配置encrypt,这个值是需要跟server端一样的,值保存在/consul/data/serf/local.keyring文件中,如果文件中已存在内容,是不是会更新的,需要删掉,或者手动填入,然后重启服务。如果文件中已经有了,那么启动配置中encrypt参数就可以删了,不会产生影响。-disable-keyring-file这个参数作用是是否持久化这个encrypt,默认持久化,可以选择不持久化,缺点是就要在启动配置里显式填写,优点是更好的排查所有节点是否一样。例如文件中和你启动参数中不一样,问题就出来了。

可以先在原有的集群中找到local.keyring文件中找到该encrypt,所有节点保持一致即可。