热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

k8s实践记录(三)

感谢在关注的朋友们,久等了!k8s实践记录,不

11.如何挂载配置文件到pod?

配置文件一般用configmap
类型挂载,需要先创建一个配置文件的configmap,然后在pod中引用这个configmap的名字即可。

[root@master-1 yamlfiles]# cat test-configmap/ui.properties 
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

[root@master-1 yamlfiles]# cat test-configmap/game.properties 
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30

data
部分就是配置文件game.properties
的具体数据,一个configmap可以同时存放多个配置文件

[root@master-1 yamlfiles]# kubectl  create configmap test-configmap --from-file test-configmap/
configmap/test-configmap created
[root@master-1 yamlfiles]# kubectl  get configmaps -o yaml
apiVersion: v1
items:
- apiVersion: v1
  data:
    game.properties: |-
      enemies=aliens
      lives=3
      enemies.cheat=true
      enemies.cheat.level=noGoodRotten
      secret.code.passphrase=UUDDLRLRBABAS
      secret.code.allowed=true
      secret.code.lives=30
    ui.properties: |
      color.good=purple
      color.bad=yellow
      allow.textmode=true
      how.nice.to.look=fairlyNice
  kind: ConfigMap
  metadata:
    creationTimestamp: "2020-07-13T02:27:36Z"
    name: test-configmap
    namespace: default
    resourceVersion: "426653"
    selfLink: /api/v1/namespaces/default/configmaps/test-configmap
    uid: 233933da-905e-480d-beef-a00ee19fb190
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

在pod中引用这个configmap

[root@master-1 yamlfiles]# cat test-configmap.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-configmap-pod
  labels:
    app: test-configmap-pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-configmap-pod
  template:
    metadata:
      labels:
        app: test-configmap-pod
    spec:
      containers:
      - name: test-configmap-pod
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /tmp/nginx/testconfigmap
          name: test-configmap
      - name: test-configmap-pod-share
        image: redis
        ports:
        - containerPort: 6379
        volumeMounts:
        - mountPath: /tmp/redis/testconfigmap
          #subPath: test-configmap-subpath
          name: test-configmap
      volumes:
      - name: test-configmap
        configMap:
          name: test-configmap

[root@master-1 yamlfiles]# kubectl  apply -f test-configmap.yaml 
deployment.apps/test-configmap-pod created

[root@master-1 yamlfiles]# kubectl get pod
NAME                                 READY   STATUS              RESTARTS   AGE
test-configmap-pod-7f448b6fc-k55w2   2/2     Running             0          19s

进入容器,查看到两个文件的确挂载进去了

[root@master-1 yamlfiles]# kubectl  exec -it test-configmap-pod-7f448b6fc-k55w2 /bin/bash
Defaulting container name to test-configmap-pod.
Use 'kubectl describe pod/test-configmap-pod-7f448b6fc-k55w2 -n default' to see all of the containers in this pod.

root@test-configmap-pod-7f448b6fc-k55w2:/# ls /tmp/nginx/testconfigmap/
game.properties  ui.properties
root@test-configmap-pod-7f448b6fc-k55w2:/# cat /tmp/nginx/testconfigmap/game.properties 
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true

需要注意的是,不能将configmap挂载到pod的子目录,即不能使用subPath
,不然配置文件就挂载不进去。将subPath
注释去掉,重新创建pod,进入容器发现的确没有挂载进去,而没有使用subPath
的容器就挂载进去了。

[root@master-1 yamlfiles]# kubectl  apply -f  test-configmap.yaml 
deployment.apps/test-configmap-pod configured

[root@master-1 yamlfiles]# kubectl  exec -it test-configmap-pod-56545959fb-lsrt2 /bin/bash
Defaulting container name to test-configmap-pod.
Use 'kubectl describe pod/test-configmap-pod-56545959fb-lsrt2 -n default' to see all of the containers in this pod.
root@test-configmap-pod-56545959fb-lsrt2:/# ls /tmp/nginx/testconfigmap/
root@test-configmap-pod-56545959fb-lsrt2:/# exit

[root@master-1 yamlfiles]# kubectl  exec -it test-configmap-pod-56545959fb-lsrt2 -c test-configmap-pod-share /bin/bash
root@test-configmap-pod-56545959fb-lsrt2:/data# ls /tmp/redis/testconfigmap/
root@test-configmap-pod-56545959fb-lsrt2:/data# ls /tmp/redis/testconfigmap/
game.properties  test-configmap-subpath  ui.properties

configmap还可以以env方式挂载到pod

        #volumeMounts:
        #- mountPath: /tmp/redis/testconfigmap
        #  name: test-configmap
        env:
          - name: CONFIGMAP_ENV
            valueFrom:
              configMapKeyRef:
                name: test-configmap
                key: game.properties

volumeMounts
方式改为env
apply
后进入对应容器即可查看变量,但只能读取到文件中的一行。

[root@master-1 yamlfiles]# kubectl  exec -it test-configmap-pod-674dc6685c-v48jw -c  test-configmap-pod-share /bin/bash
root@test-configmap-pod-674dc6685c-v48jw:/data# env|grep -i env
CONFIGMAP_ENV=enemies=aliens
_=/usr/bin/env

configmap注意点

参考:https://developer.aliyun.com/lesson_1651_18356?spm=5176.10731542.0.0.3ad220beJOP4PG#_18356

  • ConfigMap 文件的大小。虽然说 ConfigMap 文件没有大小限制,但是在 ETCD 里面,数据的写入是有大小限制的,现在是限制在 1MB 以内;

  • 第二个注意点是 pod 引入 ConfigMap 的时候,必须是相同的 Namespace 中的 ConfigMap,我这里测试是默认都是 default,所以不会报错;

  • 第三个是 pod 引用的 ConfigMap。假如这个 ConfigMap 不存在,那么这个 pod 是无法创建成功的,其实这也表示在创建 pod 前,必须先把要引用的 ConfigMap 创建好;

  • 第四点就是使用 envFrom 的方式。把 ConfigMap 里面所有的信息导入成环境变量时,如果 ConfigMap 里有些 key 是无效的,比如 key 的名字里面带有数字,那么这个环境变量其实是不会注入容器的,它会被忽略。但是这个 pod 本身是可以创建的。这个和第三点是不一样的方式,是 ConfigMap 文件存在基础上,整体导入成环境变量的一种形式;

  • 最后一点是:什么样的 pod 才能使用 ConfigMap?这里只有通过 K8s api 创建的 pod 才能使用 ConfigMap,比如说通过用命令行 kubectl 来创建的 pod,肯定是可以使用 ConfigMap 的,但其他方式创建的 pod,比如说 kubelet 通过 manifest 创建的 static pod,它是不能使用 ConfigMap 的。

12.在容器中如何引用pod的label等元数据?

[root@master-1 yamlfiles]# cat test-downwardapi.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-downwardapi
  labels:
    app: test-downwardapi
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-downwardapi
  template:
    metadata:
      labels:
        zone: cn-shenzhen
        app: test-downwardapi
      annotations:
        company: vickey-wu.com
        author: vickey-wu
    spec:
      containers:
      - name: test-downwardapi
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /tmp/nginx/testdownwardapi
          #subPath: testdownwardapi-subpath
          name: test-downwardapi
      - name: test-downwardapi-share
        image: redis
        ports:
        - containerPort: 6379
        volumeMounts:
        - mountPath: /tmp/redis/testdownwardapi
          name: test-downwardapi
      volumes:
        - name: test-downwardapi
          downwardAPI:
            items:
              - path: 'pod-labels'
                fieldRef:
                  fieldPath: metadata.labels
              - path: 'pod-annotations'
                fieldRef:
                  fieldPath: metadata.annotations

k8s通过挂载downwardAPI
类型的卷来实现将pod的元数据(非deployment的元数据)存放到pod的容器的指定目录中。要注意的是,downwardAPI
configmap
一样不能挂载subPath
,不然挂载失败。

[root@master-1 yamlfiles]# kubectl  apply -f test-downwardapi.yaml 
deployment.apps/test-downwardapi created
[root@master-1 yamlfiles]# kubectl  get pod
NAME                               READY   STATUS    RESTARTS   AGE
test-downwardapi-98d688c4d-86bds   2/2     Running   0          8s

[root@master-1 yamlfiles]# kubectl  exec -it test-downwardapi-98d688c4d-86bds /bin/bash
Defaulting container name to test-downwardapi.
Use 'kubectl describe pod/test-downwardapi-98d688c4d-86bds -n default' to see all of the containers in this pod.

root@test-downwardapi-98d688c4d-86bds:/# cat /tmp/nginx/testdownwardapi/pod-labels 
app="test-downwardapi"
pod-template-hash="98d688c4d"
zOne="cn-shenzhen"

root@test-downwardapi-98d688c4d-86bds:/# cat /tmp/nginx/testdownwardapi/pod-annotations 
author="vickey-wu"
company="vickey-wu.com"
kubernetes.io/config.seen="2020-07-13T13:48:31.839008328+08:00"
kubernetes.io/config.source="api"

可以看到pod的labels, annotations
分别被存放到文件pod-labels, pod-annotations
,除了自己加的还有些k8s自动加的。

13.如何挂载密码等敏感信息到pod?

方法一:使用--from-file
创建secret
,不需要提前加密,k8s创建时自动加密。

[root@master-1 yamlfiles]# mkdir test-secret
[root@master-1 yamlfiles]# echo 'admin' > test-secret/username.txt 
[root@master-1 yamlfiles]# echo '123123' > test-secret/passwd.txt 

[root@master-1 yamlfiles]# kubectl  create secret generic test-secret --from-file test-secret/
secret/test-secret created

查看secret
发现已经是经过了base64
加密的结果。测试加解密结果一致。

[root@master-1 yamlfiles]# kubectl  get secrets test-secret -o yaml
apiVersion: v1
data:
  passwd.txt: MTIzMTIz
  username.txt: YWRtaW4K
kind: Secret
metadata:
  creationTimestamp: "2020-07-13T08:11:53Z"
  name: test-secret
  namespace: default
  resourceVersion: "457050"
  selfLink: /api/v1/namespaces/default/secrets/test-secret
  uid: 5e48fc43-d2ab-4a8f-a21b-d6db9ea64955
type: Opaque


[root@master-1 yamlfiles]# echo -n 'admin'|base64       # 加密
YWRtaW4=
[root@master-1 yamlfiles]# echo -n 'MTIzMTIz'|base64 --decode        # 解密
123123

方法二:从yaml文件创建secret
,需要提前使用base64
加密,否则报错v1.Secret.Data: base64Codec: invalid input

[root@master-1 yamlfiles]# cat test-secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: test-secret-2
type: Opaque
data:
  #username: admin
  #password: 123123
  username: YWRtaW4=
  password: MTIzMTIz
#stringData:
#  username: root
#  password: '123456'

[root@master-1 yamlfiles]# kubectl  get secrets test-secret-2 -o yaml
apiVersion: v1
data:
  password: MTIzMTIz
  username: YWRtaW4=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"MTIzMTIz","username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"test-secret-2","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2020-07-13T07:56:45Z"
  name: test-secret-2
  namespace: default
  resourceVersion: "455729"
  selfLink: /api/v1/namespaces/default/secrets/test-secret-2
  uid: 5977d545-b84e-4045-93ad-6d5e6342327c
type: Opaque

或者使用stringData
字段,它可以不用提前加密,创建时自动加密。当data
stringData
同时存在时,优先使用stringData
字段
的值。将前面的yaml文件的stringData
取消注释,kubectl apply
后发现账号密码都变为了stringData
的值

[root@master-1 yamlfiles]# kubectl  apply -f test-secret.yaml 
secret/test-secret-2 configured

[root@master-1 yamlfiles]# kubectl  get secrets test-secret-2 -o yaml
apiVersion: v1
data:
  password: MTIzNDU2
  username: cm9vdA==
...


[root@master-1 yamlfiles]# echo -n 'cm9vdA=='|base64 --decode 
root
[root@master-1 yamlfiles]# echo -n 'MTIzNDU2'|base64 --decode 
123456

进入正题,将secret挂载到pod

[root@master-1 yamlfiles]# cat test-secret-pod-as-file.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-secret-pod
  labels:
    app: test-secret-pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-secret-pod
  template:
    metadata:
      labels:
        app: test-secret-pod
    spec:
      containers:
      - name: test-secret-pod
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /tmp/nginx/testsecret
          #subPath: test-secret-subpath
          name: test-secret
          readOnly: true
      - name: test-secret-pod-share
        image: redis
        ports:
        - containerPort: 6379
        volumeMounts:
        - mountPath: /tmp/redis/testsecret
          name: test-secret
          readOnly: true
      volumes:
      - name: test-secret
        secret:
          secretName: test-secret-2
          defaultMode: 0400             # default 0644

进入容器发现已挂载成功,权限也是设置的0400
,需要注意的是,secret, configmap, downwardAPI
都不支持挂载到subPath

[root@master-1 yamlfiles]# kubectl  get pod
NAME                               READY   STATUS    RESTARTS   AGE
test-secret-pod-5847c484d7-nwswp   2/2     Running   0          5s

[root@master-1 yamlfiles]# kubectl exec  -it test-secret-pod-5847c484d7-nwswp /bin/bash
Defaulting container name to test-secret-pod.
Use 'kubectl describe pod/test-secret-pod-5847c484d7-nwswp -n default' to see all of the containers in this pod.


root@test-secret-pod-5847c484d7-nwswp:/# cat /tmp/nginx/testsecret/username 
root
root@test-secret-pod-5847c484d7-nwswp:/# cat /tmp/nginx/testsecret/password 
123456


root@test-secret-pod-5847c484d7-nwswp:/data# ls -la /tmp/redis/testsecret/
lrwxrwxrwx. 1 root root  15 Jul 13 09:27 password -> ..data/password
lrwxrwxrwx. 1 root root  15 Jul 13 09:27 username -> ..data/username

root@test-secret-pod-5847c484d7-nwswp:/data# ls -al /tmp/redis/testsecret/..data/
-r--------. 1 root root   6 Jul 13 09:27 password
-r--------. 1 root root   4 Jul 13 09:27 username

前面是将secret作为文件挂载,下面实践下将secret作为环境变量挂载到pod中的容器

[root@master-1 yamlfiles]# cat test-secret-pod-as-env.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-secret-pod
  labels:
    app: test-secret-pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-secret-pod
  template:
    metadata:
      labels:
        app: test-secret-pod
    spec:
      containers:
      - name: test-secret-pod
        image: nginx
        ports:
        - containerPort: 80
        env:
          - name: SECRET_USERNAME
            valueFrom:
              secretKeyRef:
                name: test-secret-2
                key: username
          - name: SECRET_PASSWORD
            valueFrom:
              secretKeyRef:
                name: test-secret-2
                key: password

进入容器,打印变量可以看到就是上面创建的test-secret-2
账号密码root, 123456

[root@master-1 yamlfiles]# kubectl apply -f  test-secret-pod-as-env.yaml 
deployment.apps/test-secret-pod created

[root@master-1 yamlfiles]# kubectl get pod
NAME                               READY   STATUS        RESTARTS   AGE
test-secret-pod-56c8ffdb7c-qtf6d   1/1     Running       0          8s

[root@master-1 yamlfiles]# kubectl exec -it test-secret-pod-56c8ffdb7c-qtf6d /bin/bash
root@test-secret-pod-56c8ffdb7c-qtf6d:/# echo $SECRET_PASSWORD
123456
root@test-secret-pod-56c8ffdb7c-qtf6d:/# echo $SECRET_USERNAME
root

secret注意点

参考:https://developer.aliyun.com/lesson_1651_18356?spm=5176.10731542.0.0.3ad220beJOP4PG#_18356

  • 第一个是 Secret 的文件大小限制。这个跟 ConfigMap 一样,也是 1MB;

  • 第二个是 Secret 采用了 base-64 编码,但是它跟明文也没有太大区别。所以说,如果有一些机密信息要用 Secret 来存储的话,还是要很慎重考虑。也就是说谁会来访问你这个集群,谁会来用你这个 Secret,还是要慎重考虑,因为它如果能够访问这个集群,就能拿到这个 Secret。如果是对 Secret 敏感信息要求很高,对加密这块有很强的需求,推荐可以使用 Kubernetes 和开源的 vault做一个解决方案,来解决敏感信息的加密和权限管理。

  • 第三个就是 Secret 读取的最佳实践,建议不要用 list/watch,如果用 list/watch 操作的话,会把 namespace 下的所有 Secret 全部拉取下来,这样其实暴露了更多的信息。推荐使用 GET 的方法,这样只获取你自己需要的那个 Secret。

14.如何将各种挂载卷放到pod的同一个容器目录下

projected
卷类型就是用来实现这个目的的。

[root@master-1 yamlfiles]# cat test-projected.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-projected-pod
  labels:
    app: test-projected-pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-projected-pod
  template:
    metadata:
      labels:
        app: test-projected-pod
    spec:
      containers:
      - name: test-projected-pod
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /tmp/nginx/testprojected
          #subPath: test-projected-subpath
          name: test-projected
      - name: test-projected-pod-share
        image: redis
        ports:
        - containerPort: 6379
        volumeMounts:
        - mountPath: /tmp/redis/testprojected
          name: test-projected
      volumes:
      - name: test-projected
        projected:
          sources:
          - configMap:
              name: test-configmap
              items:
                - key: game.properties
                  path: configmap-game
          - secret:
              name: test-secret
              items:
                - key: username.txt
                  path: secret-username.txt
          - secret:
              name: test-secret-2
              items:
                - key: username
                  path: secret-username-2
          - downwardAPI:
              items:
                - path: "labels"
                  fieldRef:
                    fieldPath: metadata.labels
                - path: "cpus"
                  resourceFieldRef:
                    containerName: test-projected-pod
                    resource: limits.cpu

[root@master-1 yamlfiles]# kubectl apply -f  test-projected.yaml 
deployment.apps/test-projected-pod created

[root@master-1 yamlfiles]# kubectl get pod 
NAME                                  READY   STATUS    RESTARTS   AGE
test-projected-pod-7dbff4f4bd-rnbh8   2/2     Running   0          18s

进入容器查看,configmap, downwardAPI, 两个secret
类型的卷都挂载到/tmp/nginx/testprojected/
目录下了,内容也OK。

[root@master-1 yamlfiles]# kubectl exec -it test-projected-pod-7dbff4f4bd-rnbh8 /bin/bash
Defaulting container name to test-projected-pod.
Use 'kubectl describe pod/test-projected-pod-7dbff4f4bd-rnbh8 -n default' to see all of the containers in this pod.

root@test-projected-pod-7dbff4f4bd-rnbh8:/# ls /tmp/nginx/testprojected/
configmap-game    cpus  labels  secret-username-2  secret-username.txt

root@test-projected-pod-7dbff4f4bd-rnbh8:/# cat /tmp/nginx/testprojected/configmap-game 
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30

root@test-projected-pod-7dbff4f4bd-rnbh8:/# cat /tmp/nginx/testprojected/labels         
app="test-projected-pod"
pod-template-hash="7dbff4f4bd"

root@test-projected-pod-7dbff4f4bd-rnbh8:/# cat /tmp/nginx/testprojected/cpus 
2

root@test-projected-pod-7dbff4f4bd-rnbh8:/# cat /tmp/nginx/testprojected/secret-username.txt 
admin

root@test-projected-pod-7dbff4f4bd-rnbh8:/# cat /tmp/nginx/testprojected/secret-username-2   
root

15 如何对容器使用资源做限制?

    spec:
      containers:
      - image: nginx
        #resources: {}
        resources: 
          requests:
            memory: "64Mi"
            cpu: "250m"
            ephemeral-storage: "2Gi"
          limits:
            memory: "64Mi"
            cpu: "250m"
            ephemeral-storage: "2Gi"

对容器使用资源做限制的字段:requests
limits
。根据这两个字段对 pod 的服务质量进行一个分类,分别是 Guaranteed、Burstable 和 BestEffort。如果集群资源不够,将按照先去除 BestEffort,再去除 Burstable 的一个顺序来驱逐 pod 的。

  • Guaranteed :pod 里面每个容器都必须有内存和 CPU 的 request 以及 limit 的一个声明,且 request 和 limit 必须是一样的,这就是 Guaranteed;

  • Burstable:Burstable 至少有一个容器存在内存和 CPU 的一个 request;

  • BestEffort:只要不是 Guaranteed 和 Burstable,那就是 BestEffort。

16 如何对pod做权限限制?

To Be Continue ~



推荐阅读
  • Envoy 流量分配策略优化
    在本研究中,我们对Envoy的流量分配策略进行了优化,旨在提高系统的稳定性和性能。实验环境包括一个前端代理服务(Envoy,IP地址为172.31.57.10)和五个后端服务。通过调整Envoy的配置,实现了更高效的流量分发和负载均衡,显著提升了整体系统的响应速度和可靠性。 ... [详细]
  • 本文详细介绍了如何在 Ubuntu 14.04 系统上搭建仅使用 CPU 的 Caffe 深度学习框架,包括环境准备、依赖安装及编译过程。 ... [详细]
  • Gradle 是 Android Studio 中默认的构建工具,了解其基本配置对于开发效率的提升至关重要。本文将详细介绍如何在 Gradle 中定义和使用共享变量,以确保项目的一致性和可维护性。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • Maven + Spring + MyBatis + MySQL 环境搭建与实例解析
    本文详细介绍如何使用MySQL数据库进行环境搭建,包括创建数据库表并插入示例数据。随后,逐步指导如何配置Maven项目,整合Spring框架与MyBatis,实现高效的数据访问。 ... [详细]
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • 在Spring Boot项目中,通过YAML配置文件为静态变量设置值的方法与实践涉及以下几个步骤:首先,创建一个新的配置类。需要注意的是,自动生成的setter方法默认是非静态的,因此需要手动将其修改为静态方法,以确保静态变量能够正确初始化。此外,建议使用`@Value`注解或`@ConfigurationProperties`注解来注入配置属性,以提高代码的可读性和维护性。 ... [详细]
  • Android目录遍历工具 | AppCrawler自动化测试进阶(第二部分):个性化配置详解
    终于迎来了“足不出户也能为社会贡献力量”的时刻,但有追求的测试工程师绝不会让自己的生活变得乏味。与其在家消磨时光,不如利用这段时间深入研究和提升自己的技术能力,特别是对AppCrawler自动化测试工具的个性化配置进行详细探索。这不仅能够提高测试效率,还能为项目带来更多的价值。 ... [详细]
  • 往期文章Prom ... [详细]
  • 看官_在GitHub Actions上进行Flutter 的测试和部署
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了在GitHubActions上进行Flutter的测试和部署相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Spring Security基础配置详解
    本文详细介绍了Spring Security的基础配置方法,包括如何搭建Maven多模块工程以及具体的安全配置步骤,帮助开发者更好地理解和应用这一强大的安全框架。 ... [详细]
  • Python3爬虫入门:pyspider的基本使用[python爬虫入门]
    Python学习网有大量免费的Python入门教程,欢迎大家来学习。本文主要通过爬取去哪儿网的旅游攻略来给大家介绍pyspid ... [详细]
  • 本文探讨了如何在 Spring MVC 框架下,通过自定义注解和拦截器机制来实现细粒度的权限管理功能。 ... [详细]
  • 本文探讨了Python类型注解使用率低下的原因,主要归结于历史背景和投资回报率(ROI)的考量。文章不仅分析了类型注解的实际效用,还回顾了Python类型注解的发展历程。 ... [详细]
  • 本文详细介绍了在 Red Hat Linux 系统上安装 GCC 4.4.2 的步骤,包括必要的依赖库的安装及常见问题的解决方法。 ... [详细]
author-avatar
羊锐forever_837
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有