kubernetes-加密 Secrets-程序员宅基地

技术标签: 云原生  kubernetes  容器  

1 前言

默认 Secrets 对象的值是 base64 编码的内容,这个可以反编码得到原文的,不能起到加密重要密文的作用。
在这里插入图片描述

解决方法是使用开源的 Sealed Secrets

2 认识 Sealed Secrets

github 地址: https://github.com/bitnami-labs/sealed-secrets

有两部分总成:

  • 集群里的: controller / operator
  • 客户端程序: kubeseal

kubeseal 程序使用非对称加密来加密,只有控制器才能解密。

这些加密的秘密被编码在SealedSecret资源中,您可以将其视为创建秘密的配方。
它的 YAML 资源文件大概是这样的:

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: mysecret
  namespace: mynamespace
spec:
  encryptedData:
    foo: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq.....

经过 kubernetes 已安装的 controller 解密后相当于下面的内容:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
  namespace: mynamespace
data:
  foo: YmFy  # <- base64 编码的 "bar"

当这个 SealedSecret 的 secret 被创建的几秒钟之后,它会出现在 kubernetes 中;随后你可以像使用 kubernetes 原生的 secret 一样使用它。例如,从 Pod 引用它。

部署

获取最新的版本 https://github.com/bitnami-labs/sealed-secrets/releases

选择自己喜欢的部署方式即可。
这里选择手动非工具部署

需要下载

  • controller.yml 集群端 控制器
  • kubeseal 客户端程序

controller.yml

---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-controller
  name: sealed-secrets-controller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations: {
    }
  labels:
    name: secrets-unsealer
  name: secrets-unsealer
rules:
- apiGroups:
  - bitnami.com
  resources:
  - sealedsecrets
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - bitnami.com
  resources:
  - sealedsecrets/status
  verbs:
  - update
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - get
  - list
  - create
  - update
  - delete
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-controller
  name: sealed-secrets-controller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: secrets-unsealer
subjects:
- kind: ServiceAccount
  name: sealed-secrets-controller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-service-proxier
  name: sealed-secrets-service-proxier
  namespace: kube-system
rules:
- apiGroups:
  - ""
  resourceNames:
  - sealed-secrets-controller
  resources:
  - services
  verbs:
  - get
- apiGroups:
  - ""
  resourceNames:
  - 'http:sealed-secrets-controller:'
  - http:sealed-secrets-controller:http
  - sealed-secrets-controller
  resources:
  - services/proxy
  verbs:
  - create
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-service-proxier
  name: sealed-secrets-service-proxier
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: sealed-secrets-service-proxier
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:authenticated
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-key-admin
  name: sealed-secrets-key-admin
  namespace: kube-system
rules:
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - create
  - list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-controller
  name: sealed-secrets-controller
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: sealed-secrets-key-admin
subjects:
- kind: ServiceAccount
  name: sealed-secrets-controller
  namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-controller
  name: sealed-secrets-controller
  namespace: kube-system
spec:
  ports:
  - port: 8080
    targetPort: 8080
  selector:
    name: sealed-secrets-controller
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-controller-metrics
  name: sealed-secrets-controller-metrics
  namespace: kube-system
spec:
  ports:
  - port: 8081
    targetPort: 8081
  selector:
    name: sealed-secrets-controller
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations: {
    }
  labels:
    name: sealed-secrets-controller
  name: sealed-secrets-controller
  namespace: kube-system
spec:
  minReadySeconds: 30
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      name: sealed-secrets-controller
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations: {
    }
      labels:
        name: sealed-secrets-controller
    spec:
      containers:
      - args: []
        command:
        - controller
        env: []
        image: docker.io/bitnami/sealed-secrets-controller:0.26.1
        imagePullPolicy: IfNotPresent
        livenessProbe:
          httpGet:
            path: /healthz
            port: http
        name: sealed-secrets-controller
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 8081
          name: metrics
        readinessProbe:
          httpGet:
            path: /healthz
            port: http
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          readOnlyRootFilesystem: true
        stdin: false
        tty: false
        volumeMounts:
        - mountPath: /tmp
          name: tmp
      imagePullSecrets: []
      securityContext:
        fsGroup: 65534
        runAsNonRoot: true
        runAsUser: 1001
        seccompProfile:
          type: RuntimeDefault
      serviceAccountName: sealed-secrets-controller
      terminationGracePeriodSeconds: 30
      volumes:
      - emptyDir: {
    }
        name: tmp
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: sealedsecrets.bitnami.com
spec:
  group: bitnami.com
  names:
    kind: SealedSecret
    listKind: SealedSecretList
    plural: sealedsecrets
    singular: sealedsecret
  scope: Namespaced
  versions:
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: SealedSecret is the K8s representation of a "sealed Secret" -
          a regular k8s Secret that has been sealed (encrypted) using the controller's
          key.
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: SealedSecretSpec is the specification of a SealedSecret
            properties:
              data:
                description: Data is deprecated and will be removed eventually. Use
                  per-value EncryptedData instead.
                format: byte
                type: string
              encryptedData:
                additionalProperties:
                  type: string
                type: object
                x-kubernetes-preserve-unknown-fields: true
              template:
                description: Template defines the structure of the Secret that will
                  be created from this sealed secret.
                properties:
                  data:
                    additionalProperties:
                      type: string
                    description: Keys that should be templated using decrypted data
                    nullable: true
                    type: object
                  immutable:
                    description: Immutable, if set to true, ensures that data stored
                      in the Secret cannot be updated (only object metadata can be
                      modified). If not set to true, the field can be modified at
                      any time. Defaulted to nil.
                    type: boolean
                  metadata:
                    description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
                    nullable: true
                    properties:
                      annotations:
                        additionalProperties:
                          type: string
                        type: object
                      finalizers:
                        items:
                          type: string
                        type: array
                      labels:
                        additionalProperties:
                          type: string
                        type: object
                      name:
                        type: string
                      namespace:
                        type: string
                    type: object
                    x-kubernetes-preserve-unknown-fields: true
                  type:
                    description: Used to facilitate programmatic handling of secret
                      data.
                    type: string
                type: object
            required:
            - encryptedData
            type: object
          status:
            description: SealedSecretStatus is the most recently observed status of
              the SealedSecret.
            properties:
              conditions:
                description: Represents the latest available observations of a sealed
                  secret's current state.
                items:
                  description: SealedSecretCondition describes the state of a sealed
                    secret at a certain point.
                  properties:
                    lastTransitionTime:
                      description: Last time the condition transitioned from one status
                        to another.
                      format: date-time
                      type: string
                    lastUpdateTime:
                      description: The last time this condition was updated.
                      format: date-time
                      type: string
                    message:
                      description: A human readable message indicating details about
                        the transition.
                      type: string
                    reason:
                      description: The reason for the condition's last transition.
                      type: string
                    status:
                      description: 'Status of the condition for a sealed secret. Valid
                        values for "Synced": "True", "False", or "Unknown".'
                      type: string
                    type:
                      description: 'Type of condition for a sealed secret. Valid value:
                        "Synced"'
                      type: string
                  required:
                  - status
                  - type
                  type: object
                type: array
              observedGeneration:
                description: ObservedGeneration reflects the generation most recently
                  observed by the sealed-secrets controller.
                format: int64
                type: integer
            type: object
        required:
        - spec
        type: object
    served: true
    storage: true
    subresources:
      status: {
    }

基本使用

以某种方式创建一个json/yaml编码的Secret:

echo -n bar | kubectl create secret generic mysecret --dry-run=client --from-file=foo=/dev/stdin -o yaml >mysecret.yml

内容如下:

apiVersion: v1
data:
  foo: YmFy
kind: Secret
metadata:
  creationTimestamp: null
  name: mysecret

生成加密的 secret 资源文件

kubeseal -f mysecret.yml -w mysealedsecret.yml

数据被加密后的资源文件如下:

---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: mysecret
  namespace: default
spec:
  encryptedData:
    foo: AgA4KaUIHoNRNv8ZN1H1+dZfRyHFahVcTMMgRjoTkbL8dYmImstmw9oxrahaL8OOji5inMZ+AYP2UGJjUzflWN5SNOWpFGLN5LGHG2tinp1TWt14wCI20XqbVkGsbEwiQeh8Nudb32EgCJ0/Z4dYsa3zBR1jAbklyNv3s8sUnvDN/yvijMJYqxU3kbnHqQhiwt9SohTw445GCv1YlOe7ZqmB1MR2uK+3tRx7WUWpGe8A84uxZEJYMps/S5gxbGUMp5uvIm55S3fEYsWxqus6ssVMUoBAyCaVKCkftfRQBBd2bpBTiiQ8cnAw2BRVaGtDCHKqbZ/FY/uhllUOHxfQxzWwtDh1k3hQgXLnvG8krJytZ4OqZmkWYsOYPgakwZcZeLpBryEJv5CuwG/5RCOM5Cxjlwqph2Kfah0kULNdoAe4GbwvW1bK0PI/9SKZbrhiQ/o6GfR30W9aos3ucNbZihRA9P6er8sWbguzN3qYvdqbrSdrJ+VAyjty7lEBR/BTlUo5NdjbLuYTOhGbhcvCi7TYXThklRjisNzbS1pd/CMIm8difwEudnXmx44+hsqoK8MLgYXXEdSriJuHMeql881pxP2HQjXabr4MJkTKO7hznc4/vNnP+QtNbvjL01f1XDxIUrzsv1D3T45pBYYIfvJGb9rcskyunjJvhyJ2LUAlWY6f3uKUTwBwSIcoEX4V6WuuKYc=
  template:
    metadata:
      creationTimestamp: null
      name: mysecret
      namespace: default

创建资源对象到集群中

kubectl apply -f mysealedsecret.yml

查看资源对象

kubectl get secret mysecret

输出如下内容:

NAME       TYPE     DATA   AGE
mysecret   Opaque   1      17m

查看对象详情

 kubectl describe secret mysecret

输出如下内容:

Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
foo:  3 bytes

请注意,SealedSecret 和 Secret 必须具有相同的命名空间和名称。这是一个防止同一集群上的其他用户重新使用您的密封机密的功能。

在 Pod 中使用
busybox.yml 文件内容:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mypod
      image: busybox
      command:
        - cat
        - "/etc/mysecret/foo"
      volumeMounts:
        - name: foo
          mountPath: "/etc/mysecret"
          readOnly: true
  volumes:
    - name: foo
      secret:
        secretName: mysecret

创建这个 Pod:

kubectl apply -f busybox.yml

在这里插入图片描述
这个 SealedSecret对象的创建不验证用户。换句话说,任何人都可以创建一个Sealed Secret 对象。
这个和原生的 Secret 对象是一样的设计,都是通过集群的 RBAC 机制控制使用的权限。

管理现有的 Secret

如果希望 Sealed Secrets 控制器管理现有的 Secret,您可以使用 Sealed Secret 对您的 Secret 添加 sealedsecrets.bitnami.com/managed: "true" annotations(注解)。
当解封具有相同名称和命名空间的 Sealed Secret 时,现有的 Secret 将被覆盖,并且 Sealed Secrets 将拥有该 Secret 的所有权(因此,当删除 Sealed Secret 时,该 Secret 也将被删除)。

例如有一个现有的 Secret 对象 test-secret, 他的 YAML 文件内容如下:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret
data:
  foo: MTIz

给原有的 Secret 添加注释

apiVersion: v1
kind: Secret
metadata:
  name: testsecret
  annotations:
    sealedsecrets.bitnami.com/managed: "true"
data:
  foo: MTIz

应用一下

kubectl apply -f test-seal.yml

查看运行中的 testsecret 对象的信息
在这里插入图片描述
查看运行中的 testsecret 对象 YAML 内容
在这里插入图片描述

接着,我创建同名的 Sealed Secrets 对象

这里我偷懒了,没通过创建新的密码创建 Sealed Secrets 对象,而是沿用原来的 Secrets 对象中的密码。
正确的做法是使用新的密码创建 Sealed Secrets 对象去覆盖原来的 Secrets 对象。

kubeseal -f test-secret.yml -w test-seal.yml

kubectl  apply -f test-seal.yml

后面就可以使用这个含有加密秘密内容的 YAML 文件 test-seal.yml ,给到 开发使用了,即使可以查看文件中的内容,但因为里面的敏感数据已经被加密,真正的密码也可以得到有效的保护。

并且,此时再查看 Secret 实力对象 testsecret,会发现对象已经被覆盖。
在这里插入图片描述
在这里插入图片描述

如果此时,删除 Sealed Secret 对象, 对应的这个 Secret 实例对象 testsecret 也会被删除。
在这里插入图片描述

验证密文的有效性

加入你得到一个有加密密文的 YAML 文件

---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: testsecret
  namespace: default
spec:
  encryptedData:
    foo: AgAK7TTRNORyvO6nQFq9w0Unj6e+/NHPyipdtbuwdfhyvnZavLpmUIcbHnj/wj/QFvbFiAtc2NoTG2g/sZIZJ8/ZgJi4a7lrNJbCFKcSdxDSyPcAdP0K9SjiSqcpFxw1zVw0NJOtV2q8khcY+aDkk7QWdxio8+0qdSpb5KvbB+eCAByxVdixHJXd8Ul2s/6CqRCkm3DGwwvvvV/1ogoUWMidaZXK/Ju4RopAaKYrnJ0fSpDrR8vRZEC6wJD6HRXc5cXeVXJ8g3SXgAQ1tjRuJkBxF+5S8jODihioBVLbq++6FxXJ/4bepy7NFcY/K7ldnp/B6xngqFiawYuUlPnI+iscE6YkSlSFFGohrgj6xByGVf7jCNBbbOY9itgu8AY/zrAUCedgr8c+xtPfX7cwGlGicD5sw/M1mpRXE0T6uH3H3MTazHk2KZvXTk290pOF6bYrzoV5AsG6I37+fAhDDJs1WFtj47kk0eaiwKJuSPeSVxlQyKqP50oemhK3aXJCOz6ryZUppSD8ufRRqGJls+lN8oFLZakfR6sjYY5zQFLaHIw5vo9egn7dSdUdKch3lP5D4pSohSdHrSYJnEplA4XImRu68X5phJyih6IWPRrOtDv4wZ9+B3qSVMTD5YdyEPirt4azb6pY7Xk4NvCDQctgWP4FRzdjVzu2FNru6t8cC+Gz7fwIJXMr1dkH4W/e8I4UldU=
  template:
    metadata:
      creationTimestamp: null
      name: testsecret
      namespace: default

如果你想验证文件内的加密密文是否有效,或者是否得到破坏。可以使用如下命令验证

cat test-seal.yml | kubeseal --validate

如果正常,则没有任何返回。如果有问题,则会返回如下内容:

error: unable to decrypt sealed secret: testsecret

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_22648091/article/details/137140137

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文