精华内容
下载资源
问答
  • <p>How would I go about starting an application in my host machine in order to read files and stdout from a running docker container? <p>Essentially I want to do this: <pre><code>docker start ...
  • docker logs : 获取容器的日志

    千次阅读 2018-09-20 10:34:00
    2019独角兽企业重金招聘Python工程师标准>>> ...

    查看容器的log信息

    docker logs : 获取容器的日志

    语法:docker logs [OPTIONS] CONTAINER
    

    1.OPTIONS说明

    -f : 跟踪log信息输出
    --since :显示某个开始时间的所有log信息
    -t : 显示时间戳
    --tail :仅列出最新N条容器log信息
    

    2.查看mytomcat的log信息

    docker logs -t -f mytomcat
    

    3.查看容器mytomcat从2018年9月20日后的最新10条log信息。

    docker logs --since="2018-09-20" --tail=10 mytomcat
    

    转载于:https://my.oschina.net/lwenhao/blog/2086043

    展开全文
  • 获取Kubernetes容器上下文环境

    千次阅读 2019-01-02 17:33:41
     下面我们将主要介绍运行在Kubernetes集群容器所能够感知到的上下文环境,以及容器是如何获知这些信息的。  首先,Kubernetes提供了一个能够让容器感知到集群正在发生的事情的方法:环境变量。作为容器环境...

    Kubernetes容器上下文环境

      下面我们将主要介绍运行在Kubernetes集群中的容器所能够感知到的上下文环境,以及容器是如何获知这些信息的。

      首先,Kubernetes提供了一个能够让容器感知到集群中正在发生的事情的方法:环境变量。作为容器环境组成的一部分,这些集群信息对于容器构建“集群环境感知”起着非常重要的作用。其次,Kubernetes容器环境还包括一系列与容器生命周期相关的容器钩子,其对应的回调函数hook handler可以作为单个容器可选定义项的一部分。这个容器钩子与操作系统传统进程模型的通知回调机制有些类似。其实,还有一个与容器环境相关的重要部分是容器可用的文件系统。通过前面的讨论可知,在Kubernetes中,容器的文件系统由一个容器镜像和若干个Volume组成。

      下面我们将着重讨论暴露给容器的集群信息和用于向容器发布对其生命周期管理信息的容器钩子这两种同容器上下文环境协作的方法。

    1、集群环境感知

      运行在Kubernetes集群中的一个容器在容器内部能够感知两种类型的环境变量信息,一种是与容器自身相关的信息,另一种是集群的信息。

    1.1容器自身信息

      容器能够感知到的与容器自身相关的信息包括运行该容器的pod的名字、pod所在的namespace、在pod资源配置文件中env字段定义的键/值对,等等。其中,pod的名字被设置成容器的的主机名,而且可以在容器内通过所有访问主机名的方式获得,例如,hostname命令或JAVA中InetAddress.getLocalHost()函数调用。pod的名字和namespace还可以通过downwardAPI进行访问。对容器而言,用户在pod资源配置文件中自定义的环境变量的可访问性与在Docker镜像中指定的环境变量是一样的。downwardAPI示例如下:

    复制代码

    [root@k8s-master downwardapi]# cat test-downwardapi.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: test-downwardaoi-volume
      labels:
        name: test-downwardaoi-volume
        zone: us-east
        cluster: test-cluster1
      annotations:
        build: two
        builder: zhenyuyaodidiao
    spec:
      containers:
        - name: test-hostpath
          image: registry:5000/back_demon:1.0
          volumeMounts:
           - name: podinfo
             mountPath: /home/laizy/podinfo
             readOnly: false
          command:
          - /run.sh
      volumes:
      - name: podinfo
        downwardAPI:
          items:
           - path: "pod_name"
             fieldRef:
               fieldPath: metadata.name
           - path: "pod_namespace"
             fieldRef:
               fieldPath: metadata.namespace
           - path: "pod_labels"
             fieldRef:
               fieldPath: metadata.labels
           - path: "pod_annotations"
             fieldRef:
               fieldPath: metadata.annotations
    
    [root@k8s-master downwardapi]# kubectl create -f test-downwardapi.yaml 
    pod "test-downwardaoi-volume" created
    
    [root@k8s-master downwardapi]# kubectl exec -ti test-downwardaoi-volume /bin/bash
    [root@test-downwardaoi-volume /]# cd /home/laizy/podinfo/
    [root@test-downwardaoi-volume podinfo]# ls
    pod_annotations  pod_labels  pod_name  pod_namespace
    [root@test-downwardaoi-volume podinfo]# cat pod_annotations 
    build="two"
    builder="zhenyuyaodidiao"
    kubernetes.io/config.seen="2017-03-22T09:42:11.832955302+08:00"
    kubernetes.io/config.source="api"
    [root@test-downwardaoi-volume podinfo]# cat pod_labels 
    cluster="test-cluster1"
    name="test-downwardaoi-volume"
    zone="us-east"
    [root@test-downwardaoi-volume podinfo]# cat pod_name
    test-downwardaoi-volume
    [root@test-downwardaoi-volume podinfo]# cat pod_name
    test-downwardaoi-volume
    [root@test-downwardaoi-volume podinfo]# cat pod_namespace 
    default
    [root@test-downwardaoi-volume podinfo]# exit
    exit

    复制代码

     

    1.2集群信息

      我们在前面已经讨论过Kubernetes服务发现的两种机制:DNS和环境变量。service环境变量属于集群信息,在容器创建时由Kubemetes集群API注人,在容器内以环境变量或域名的方式被访问。

    2.容器钩子

      容器钩子是Kubemetes针对容器生命周期管理引入的事件处理机制,它负责监听Kubemetes对容器生命周期的管理信息,并将这些信息以广播的形式通知给容器。然后执行相应的回调函数。

    2.1容器钩子类型

      Kubemetes支持两种类型的容器钩子,分别为PostStart和PreStop。

      PostStart。该钩子在容器被创建后立刻触发,通知容器它已经被创建。该钩子不需要向其所对应的hook handler传人任何参数。如果该钩子对应的hook handler执行失败,则该容器会被杀死,并根据该容器的重启策略决定是否要重启该容器。

      PreStop。该钩子在容器被删除前触发,其所对应的hook handler必须在删除该容器的请求发送给Docker daemon之前完成。在该钩子对应的hook handler完成后不论执行的结果如何,Docker daemon会发送一个SGTERN信号量给Docker daemon来删除该容器。同样地。该钩子也不需要传人任何参数

    2.2hook handler执行

      当一个容器管理hook发生时,管理系统将会在容器中调用注册的hook handler。其中hook handler通过在包含该容器的pod资源配置文件的Lifecycle字段中定义来完成注册。注意,当hook handler在执行时,其他对该容器所在pod的管理动作将被阻塞除非该容器异常退出。而如果你自定义的hook handler阻塞时,其他对pod的管理操作包括容器健康检查将不会发生,直到hook handler继续执行完毕。因此,一般建议用户自定义的hook handler代码尽可能地轻量化,尽管确实有一些场景的hook handler需要长时间运行(例如在容器时退出保存运行状态等)。

    2.3hook handler的执行方式

      hook handler是hook在容器内执行的回调函数,也即hook暴露给容器的方式。Kubemetes支持两种不同的hook handler类型,分别是Exec和HTTPGet。

        Exec。在容器的cgroup和namespace内启动一个新进程来执行指定的命令,由该命令消耗的资源全部要计人容器的消耗。正如在之前容器健康检查中提到的,如果Exec执行的命令最后在标准输出stdout的结果为0k,就代表handler执行成功,否则就被认为执行异常,并且Kuberlet将强制重新启动该容器。

        HTTPGet。向容器的指定接口发起一个HTTP请求作为handler的具体执行内容,并通过返回的HTTP状态码来判断该请求执行是否成功。

      综上,hook机制为用户提供了一种能够根据容器生命周期及其上下文的变化来触发不同操作的协作方法。这对于很多需要精细控制容器的场景是非常有用的,比如在容器结束前执行一些清理工作来保证其“优雅”退出。以下给出hook执行exec的示例:

    复制代码

    [root@k8s-master hook]# cat test-lifecycle-hostpath.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        name: test-lifecycle-hostpath
        role: master
      name: test-lifecycle-hostpath
    spec:
      containers:
        - name: test-lifecycle-hostpath
          image: registry:5000/back_demon:1.0
          lifecycle:
            postStart:
              exec:
                command:
                  - "touch"
                  - "/home/laizy/test/hostpath/post-start"
            preStop:
              exec:
                command:
                  - "touch"
                  - "/home/laizy/test/hostpath/pre-stop"
          volumeMounts:
           - name: testhost
             mountPath: /home/laizy/test/hostpath
             readOnly: false
          command:
          - /run.sh
      volumes:
      - name: testhost
        hostPath:
         path: /home/testhost
    [root@k8s-master hook]# date
    2017年 03月 22日 星期三 10:21:58 CST
    [root@k8s-master hook]# kubectl create -f test-lifecycle-hostpath.yaml 
    pod "test-lifecycle-hostpath" created
    [root@k8s-master hook]# kubectl get pod -o wide
    NAME                                READY     STATUS    RESTARTS   AGE       IP          NODE
    test-lifecycle-hostpath             1/1       Running   0          13s       10.0.9.3    k8s-node-3
    [root@k8s-master hook]# date
    2017年 03月 22日 星期三 10:22:52 CST
    [root@k8s-master hook]# kubectl delete pod test-lifecycle-hostpath 
    pod "test-lifecycle-hostpath" deleted

    复制代码

    在node3上查看外挂出来的路径上,生成了两个文件,post-start文件是在pod创建之后生成的;pre-stop文件是在pod删除之前生成的。

    [root@k8s-node-3 ~]# ll /home/testhost/
    总用量 0
    -rw-r--r--. 1 root root 0 3月  22 10:22 post-start
    -rw-r--r--. 1 root root 0 3月  22 10:23 pre-stop
    [root@k8s-node-3 ~]# 

     

    对应的httpGet示例简单示意如下:

    复制代码

    containers:
      - name: lifecycle
        image: busybox
        lifecycle:
          postStart:
            exec:
              command:
                - "touch"
                - "/var/log/lifecycle/post-start"
          preStop:
            httpGet:
              path: "/abort"
              port: 8080

    复制代码

     

    kubernetes 容器内获取Pod信息(包括:宿主主机IP)

    https://blog.csdn.net/kozazyh/article/details/79463688

    kubernetes 自从1.7开始,可以在pod 的container 内获取pod的spec,metadata 等信息。

    具体方法可以通过env获取:

          env:
            - name: MY_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: MY_POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: MY_POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: MY_POD_SERVICE_ACCOUNT
              valueFrom:
                fieldRef:
                  fieldPath: spec.serviceAccountName

    spec.nodeName : pod所在节点的IP、宿主主机IP

    status.podIP :pod IP

    metadata.namespace : pod 所在的namespace

    更多参数:https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/

    https://github.com/kubernetes/kubernetes/issues/24657

     

    kubernetes 通过环境变量暴露POD的信息给容器

    https://blog.csdn.net/qq_21816375/article/details/80232109

    有时候,容器需要获取pod的信息时,就可以通过设置环境保护来实现 
    例子 
    1.使用POD 的字段的值作为环境变量的值

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-envars-fieldref
    spec:
      containers:
        - name: test-container
          image: k8s.gcr.io/busybox
          command: [ "sh", "-c"]
          args:
          - while true; do
              echo -en '\n';
              printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;//对应下面的环境变量的值
              printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
              sleep 10;
            done;
          env:
            - name: MY_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: MY_POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: MY_POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: MY_POD_SERVICE_ACCOUNT
              valueFrom:
                fieldRef:
                  fieldPath: spec.serviceAccountName
      restartPolicy: Never

    2.使用容器的字段的值作为环境变量的值 
    例子

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-envars-resourcefieldref
    spec:
      containers:
        - name: test-container
          image: k8s.gcr.io/busybox:1.24
          command: [ "sh", "-c"]
          args:
          - while true; do
              echo -en '\n';
              printenv MY_CPU_REQUEST MY_CPU_LIMIT;
              printenv MY_MEM_REQUEST MY_MEM_LIMIT;
              sleep 10;
            done;
          resources:
            requests:
              memory: "32Mi"
              cpu: "125m"
            limits:
              memory: "64Mi"
              cpu: "250m"
          env:
            - name: MY_CPU_REQUEST
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: requests.cpu
            - name: MY_CPU_LIMIT
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: limits.cpu
            - name: MY_MEM_REQUEST
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: requests.memory
            - name: MY_MEM_LIMIT
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: limits.memory
      restartPolicy: Never

    参考: 
    environment-variable-expose-pod-information

    Kubernetes 配置Pod和容器(十五) 通过环境变量公开Pod信息到容器

    https://www.jianshu.com/p/577deb21ba1d

    这个章节展示了如何使用环境变量公开pod的信息到它自己运行的容器里面。环境变量可以公开Pod字段和容器字段。

    有两种方式用来公开Pod和容器字段给运行的容器:环境变量和DownwardAPIVolumeFiles。

    使用Pod字段作为环境变量的值

    在本次实验,创建包含一个容器的Pod。下面是这个Pod的配置文件:

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-envars-fieldref
    spec:
      containers:
        - name: test-container
          image: gcr.io/google_containers/busybox
          command: [ "sh", "-c"]
          args:
          - while true; do
              echo -en '\n';
              printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
              printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
              sleep 10;
            done;
          env:
            - name: MY_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: MY_POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: MY_POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: MY_POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            - name: MY_POD_SERVICE_ACCOUNT
              valueFrom:
                fieldRef:
                  fieldPath: spec.serviceAccountName
      restartPolicy: Never
    

    在这个配置文件,可以看到五个环境变量。env字段是个数组。数组里面的第一个元素指定了MY_NODE_NAME环境变量,它的值是从Pod的spec.nodeName里面获取的。类似的其他的环境变量获取pod的字段名称。

    注意:这些例子里面的字段是pod的字段。不是运行在pod里面的容器的字段。

    创建pod:

    kubectl create -f test.yaml
    

    验证运行在pod里面的容器:

    kubectl get pods
    

    查看容器的日志:

    kubectl logs dapi-envars-fieldref
    

    输出展示了选择的环境变量的值:

    minikube
    dapi-envars-fieldref
    default
    172.17.0.4
    default
    

    为何在日志里面是这些值,可以看配置文件的command和args。当容器启动的时候,把这个五个环境变量的值写入的标准输出里面。每十秒钟重复一次。

    下一步,通过shell进入Pod运行的容器里面:

    kubectl exec -it dapi-envars-fieldref -- sh
    

    在shell里面,查看环境变量:

    /# printenv
    

    输出展示了确定已经把pod字段的值分配给环境变量:

    MY_POD_SERVICE_ACCOUNT=default
    ...
    MY_POD_NAMESPACE=default
    MY_POD_IP=172.17.0.4
    ...
    MY_NODE_NAME=minikube
    ...
    MY_POD_NAME=dapi-envars-fieldref
    

    使用容器字段作为环境变量的值

    在上面的实验,使用pod字段作为环境变量的值。在下一个实验,可以使用容器字段作为环境变量的值。下面是Pod的配置文件:

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-envars-resourcefieldref
    spec:
      containers:
        - name: test-container
          image: gcr.io/google_containers/busybox:1.24
          command: [ "sh", "-c"]
          args:
          - while true; do
              echo -en '\n';
              printenv MY_CPU_REQUEST MY_CPU_LIMIT;
              printenv MY_MEM_REQUEST MY_MEM_LIMIT;
              sleep 10;
            done;
          resources:
            requests:
              memory: "32Mi"
              cpu: "125m"
            limits:
              memory: "64Mi"
              cpu: "250m"
          env:
            - name: MY_CPU_REQUEST
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: requests.cpu
            - name: MY_CPU_LIMIT
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: limits.cpu
            - name: MY_MEM_REQUEST
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: requests.memory
            - name: MY_MEM_LIMIT
              valueFrom:
                resourceFieldRef:
                  containerName: test-container
                  resource: limits.memory
      restartPolicy: Never
    

    在配置文件里面,可以看到四个环境变量。env字段是一个数组。数组的第一个元素指定了MY_CPU_REQUEST环境变量的值通过名字为test-container容器的request.cpu字段获取。类似的其他的环境变量通过他们对应的容器字段获取相应的值。

    创建Pod:

    kubectl create -f test.yaml
    

    验证Pod里面的容器已经运行:

    kubectl get pods
    

    查看容器日志:

    kubectl logs dapi-envars-resourcefieldref
    

    输出展示了选择的环境变量的值:

    1
    1
    33554432
    67108864
    
    展开全文
  • 深入理解Java容器

    万次阅读 多人点赞 2016-07-27 17:25:40
    1、容器的概念 在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集合,集合就是将...1、容器不是数组,不能通过下标的方式访问容器中的元素 2、数组的所有功能通过Arraylist容器

    1、容器的概念
    在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集合,集合就是将若干性质相同或相近的类对象组合在一起而形成的一个整体
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    2、容器与数组的关系
    之所以需要容器:
    1、数组的长度难以扩充
    2、数组中数据的类型必须相同
    容器与数组的区别与联系:
    1、容器不是数组,不能通过下标的方式访问容器中的元素
    2、数组的所有功能通过Arraylist容器都可以实现,只是实现的方式不同
    3、如果非要将容器当做一个数组来使用,通过toArray方法返回的就是一个数组
    示例程序:

    package IT;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    //数组的所有功能通过ArrayList容器都可以实现,只是实现的方式不同
    public class App
    {
         public static void main(String[] args)
         {
        	   ArrayList<Integer> arrayList = new ArrayList<Integer>();
        	   arrayList.add(12);
        	   arrayList.add(10);
        	   arrayList.add(35);
        	   arrayList.add(100);
        	   
        	   Iterator<Integer> iterator = arrayList.iterator();//获取容器的迭代器
        	   while(iterator.hasNext())
        	   {
        		   Integer value = iterator.next();//获取当前游标右边的元素,同时游标右移-->
        		   System.out.println(value);
        	   }
        	   System.out.println("通过ArrayList容器获取一个数组arr:");
        	   Object[] arr = arrayList.toArray();
        	   for(int i=0;i<arr.length;i++)
        	   {
        		   System.out.println(arr[i]);
        	   }
         }
    }
    

    输出结果:

    12
    10
    35
    100
    通过ArrayList容器获取一个数组arr:
    12
    10
    35
    100
    

    3、容器常用的几个方法

    boolean add(Object obj):向容器中添加指定的元素
    Iterator iterator():返回能够遍历当前集合中所有元素的迭代器
    Object[] toArray():返回包含此容器中所有元素的数组。
    Object get(int index):获取下标为index的那个元素
    Object remove(int index):删除下标为index的那个元素
    Object set(int index,Object element):将下标为index的那个元素置为element
    Object add(int index,Object element):在下标为index的位置添加一个对象element
    Object put(Object key,Object value):向容器中添加指定的元素
    Object get(Object key):获取关键字为key的那个对象
    int size():返回容器中的元素数
    

    在这里插入图片描述
    在这里插入图片描述
    实例程序:

    package IT;
    
    import java.util.ArrayList;
    
    public class App
    {
         public static void main(String[] args)
         {
        	   ArrayList<Integer> arrayList = new ArrayList<Integer>();
        	   arrayList.add(12);
        	   arrayList.add(10);
        	   arrayList.add(35);
        	   arrayList.add(100);
        	   System.out.println("原容器中的元素为:");
        	   System.out.println(arrayList);
        	   System.out.println("\n");
        	   
        	   /*******重置set(int index,Object element)*******/
        	   System.out.println("将下标为1位置的元素置为20,将下标为2位置的元素置为70");
               arrayList.set(1, 20);
               arrayList.set(2, 70);
               System.out.println("重置之后容器中的元素为:");
               System.out.println(arrayList);
               System.out.println("\n");
               
               /*******中间插队add(int index,Object element)*******/
               System.out.println("在下标为1的位置插入一个元素,-----插入元素:此时容器后面的元素整体向后移动");
               arrayList.add(1, 80);//在下标为1的位置插入一个元素,此时容量加1,-----位置后面的元素整体向后移动
               System.out.println("插入之后容器中的元素为:");
               System.out.println(arrayList);
               System.out.println("插入之后容器中的容量为:");
               System.out.println(arrayList.size());
               System.out.println("\n");
               
               
               /*******中间删除元素remove(int index)*******/
               System.out.println("将下标为3位置的元素70删除,-----删除元素:此时容器位置后面的元素整体向前移");
               arrayList.remove(3);
               System.out.println("删除之后容器中的元素为:");
               System.out.println(arrayList);
               System.out.println("删除之后容器中的容量为:");
               System.out.println(arrayList.size());
               
         }
    }
    

    运行结果:

    原容器中的元素为:
    [12, 10, 35, 100]
    
    
    将下标为1位置的元素置为20,将下标为2位置的元素置为70
    重置之后容器中的元素为:
    [12, 20, 70, 100]
    
    
    在下标为1的位置插入一个元素,-----插入元素:此时容器后面的元素整体向后移动
    插入之后容器中的元素为:
    [12, 80, 20, 70, 100]
    插入之后容器中的容量为:
    5
    
    
    将下标为3位置的元素70删除,-----删除元素:此时容器位置后面的元素整体向前移
    删除之后容器中的元素为:
    [12, 80, 20, 100]
    删除之后容器中的容量为:
    4
    

    4、容器的分类
    容器分为Set集、List列表、Map映射
    Set集合:由于内部存储结构的特点,Set集合中不区分元素的顺序(即使存放的类实现了compareTo方法,也是没用的),不允许出现重复的元素(用户自定义的类有的时候需要实现相应方法),TreeSet容器特殊,元素放进去的时候自然而然就有顺序了,Set容器可以与数学中的集合相对应:相同的元素不会被加入。
    在这里插入图片描述
    在这里插入图片描述
    List列表:由于内部存储结构的特点,List集合中区分元素的顺序,且允许包含重复的元素。List集合中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素—有序,可以重复
    Map映射:由于内部存储结构的特点,映射中不能包含重复的键值,每个键最多只能映射一个值,否则会出现覆盖的情况(后面的value值会将前面的value值覆盖掉),Map是一种把键对象和值对象进行映射的集合,即Map容器中既要存放数据本身,也要存放关键字:相同的元素会被覆盖
    在这里插入图片描述
    在这里插入图片描述
    注意:对于Set和Map来说,元素放进去之后是没有顺序的,如果希望元素放进去之后是有顺序的,可以用treeSet和treeMap存储数据。
    实例程序:

           var set2 = mutable.Set.empty[Int]
           set2 += 10
           set2 ++= List(50,100,200)
           set2 += 500
           println("Set输出的结果:")
           println(set2)
           var map3 = mutable.Map.empty[String,Double]
           map3 += "Spark"->90.0
           map3 += "Hadoop"->80.0
           map3 ++= List("Scala"->100.0,"Java"->60.0)
           println("Map输出的结果:")
           println(map3)
    

    运行结果:

    Set输出的结果:
    Set(100, 50, 500, 10, 200)
    Map输出的结果:
    Map(Hadoop -> 80.0, Spark -> 90.0, Scala -> 100.0, Java -> 60.0)
    

    实例程序:

           var treeSet = TreeSet(10,20,30,90,100,200,50)
           println(treeSet)
           /*键值对排序是根据key的值进行排序的,没有value的事情,让我联想到了MapReduce中排序的时候之所以根据k2
           而不是v2的值进行排序,这是因为哈希映射内部决定的,而不是MapReduce决定的
           呵呵!注意:排序区分大小写的哦!!!*/
           var treeSet2 = TreeSet[String]("Spark","Anang","Baby","Hello")
           println(treeSet2)
           var treeMap = TreeMap[String,Integer]("Java"->100,"Scala"->88,"Python"->60,"Anglebaby"->500)
           println(treeMap)
    

    运行结果:

    TreeSet(10, 20, 30, 50, 90, 100, 200)
    TreeSet(Anang, Baby, Hello, Spark)
    Map(Anglebaby -> 500, Java -> 100, Python -> 60, Scala -> 88)
    

    示例程序:

    class Student implements Comparable<Object>
    {
    	public int id;
    	public String nameString;
    	
    	public Student(int id,String name)
    	{
    		this.id = id;
    		this.nameString = name;
    	}
    	
    	
    	@Override 
    	public String toString()
    	{
    		return this.id + " " + this.nameString;
    	}
    	
    	
    	@Override
    	public int compareTo(Object obj)
    	{
    		Student stu = (Student)obj;
    		if (this.id > stu.id)
    		{
    			return 1;
    		}
    		else if (this.id == stu.id)
    		{
    			return 0;
    		}
    		else {
    			return -1;
    		}
    	}
    
    }
    
    
    public class Test_ArrayList_1
    {
        public static void main(String[] args)
        {
               HashSet<Integer> hashSet1 = new HashSet<Integer>();
    	       hashSet1.add(100);
    	       hashSet1.add(200);
    	       hashSet1.add(200);
    	       hashSet1.add(400);
    	       hashSet1.add(10);
    	       hashSet1.add(20);
    	       hashSet1.add(8000);
    	       hashSet1.add(1000);
    	       hashSet1.add(2000);
    	       hashSet1.add(2000);
    	       hashSet1.add(4000);
    	       hashSet1.add(100);
    	       hashSet1.add(200);
    	       hashSet1.add(8000);
               for (Integer integer : hashSet1)
    		   {
    			  System.out.println(integer);   //打印出的类不含有重复的元素
    		   }
               
               System.out.println("--------------------");
               
               
               HashSet<Student> hashSet2 = new HashSet<Student>();     //此时Student有一个问题,没有实现equals方法和hashCode方法.
               hashSet2.add(new Student(1000, "wtt"));
               hashSet2.add(new Student(2000, "wtt"));
               hashSet2.add(new Student(3000, "wtt"));
               hashSet2.add(new Student(3000, "wtt"));
               hashSet2.add(new Student(100, "wtt"));
               hashSet2.add(new Student(50, "wtt"));
               hashSet2.add(new Student(10, "wtt"));
               
               for (Student student : hashSet2)
    		   {
    			  System.out.println(student);          //尽管Student类实现了compareTo方法,也是没用的,每次打印出元素的顺序是不一样的.
    		   }
               
               System.out.println("--------------------");
               
        }
    }
    
    /*
     *  1000
    	2000
    	100
    	4000
    	20
    	200
    	10
    	400
    	8000
    	--------------------
    	3000 wtt
    	1000 wtt
    	100 wtt
    	10 wtt
    	3000 wtt
    	2000 wtt
    	50 wtt
    	--------------------
     * */
    
    

    这里写图片描述

    5、toString()方法的使用:凡是把类对象放到容器中,相应的类都应该实现Object类中的toString()方法;凡是Java中自带的数据类型,都已经重写完了toString()方法
    实例1:(未重写toString()方法之前)

    package IT;
    
    
    public class App
    {
         public static void main(String[] args)
         {
               //Java中自带的类
        	  System.out.println("-----凡是Java中自带的数据类型都已经重写完了toString()方法!---");
        	  System.out.println(new Integer(2).toString());
        	  System.out.println(new String("zhang").toString());
        	  //用户自定义的类Student
        	  System.out.println(new Student("zhangsan",99.8).toString());
        	  
         }
    }
    class Student
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
    }
    

    输出结果:

    -----凡是Java中自带的数据类型都已经重写完了toString()方法!---
    2
    zhang
    IT.Student@1af2f973
    

    实例2:(重写完toString()方法之后)

    package IT;
    
    import java.util.ArrayList;
    
    public class App
    {
         public static void main(String[] args)
         {
             ArrayList<Student> arr = new ArrayList<Student>();
             arr.add(new Student("zhangsan",89.8));
             arr.add(new Student("lisi",90));
             arr.add(new Student("wangwu",60.6));
             
             System.out.println(arr);
         }
    }
    class Student
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    }
    

    输出结果:

    [zhangsan	89.8, lisi	90.0, wangwu	60.6]
    

    6、Comparable接口中的compareTo()方法:凡是需要进行比较排序的类都应该实现Comparable接口中的compareTo()方法;凡是把类对象放到以树为内部结构的容器中都应该实现Comparable接口中的compareTo()方法
    在这里插入图片描述
    实例1:

    package IT;
    
    import java.util.ArrayList;
    import java.util.Collections;
    
    public class App
    {
         public static void main(String[] args)
         {
             ArrayList<Student> arr = new ArrayList<Student>();
             arr.add(new Student("zhangsan",89.8));
             arr.add(new Student("lisi",90));
             arr.add(new Student("wangwu",60.6));
             arr.add(new Student("wangting",85.6));
             
             Collections.sort(arr);
             
             for (Student student : arr)
    		{
    			System.out.println(student);
    		}
             
         }
    }
    class Student implements  Comparable<Student>
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    	public int compareTo(Student obj)
    	{
    	      return (int) (this.score - obj.score);//比较的标准为score进行升序
    	}
    }
    

    输出结果:

    wangwu	60.6
    wangting	85.6
    zhangsan	89.8
    lisi	90.0
    

    实例2:

    package IT;
    
    
    import java.util.TreeSet;
    
    public class App
    {
         public static void main(String[] args)
         {
                TreeSet<Student> treeSet = new TreeSet<Student>();
                treeSet.add(new Student("wangwu",60.6));
                treeSet.add(new Student("lisi",90.0));
                treeSet.add(new Student("wangting",85.6));
                treeSet.add(new Student("zhangsan",60.6));
                
                for (Student student : treeSet)
    			{
    				System.out.println(student);
    			}
             
         }
    }
    class Student implements  Comparable<Student>
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    	public int compareTo(Student obj)
    	{
    	      if(this.score > obj.score)
    	    	  return 1;
    	      else
    	    	  return -1;
    	}
    }
    

    输出结果:

    zhangsan	60.6
    wangwu	60.6
    wangting	85.6
    lisi	90.0
    

    7、凡是把类对象放到以哈希表为内部存储结构的容器中,相应的类必须要实现equals方法和hashCode方法,这样才符合哈希表真实的逻辑功能.(对于咱们自己定义的类,如果你没有重写hashcode方法,我们可以通过hashcode方法获取该对象的内存地址)
    在这里插入图片描述
    简而言之:哈希表先根据它的hashcode方法提供的哈希码找到存储的位置,在从位置所关联的链表里面寻找是否有相同的对象,如果有相同的对象,则不存放,如果没有,则存放进去。
    在这里插入图片描述
    在这里插入图片描述
    如果你还不懂,看我这篇文章吧:https://wenku.baidu.com/view/a1f1c88ce518964bcf847cd0
    实例程序1:(为重写之前)

    package IT;
    
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Set;
    
    public class App
    {
         public static void main(String[] args)
         {
               //Java中自带的数据类型
        	  System.out.println("先测试Java中自带的数据类型:");
        	  HashMap<String, Double> hashMap1 = new HashMap<String,Double>();
        	  hashMap1.put("zhangsan", 96.0);
        	  hashMap1.put("lisi", 88.6);
        	  hashMap1.put("wangwu", 98.6);
        	  hashMap1.put("wangting",  87.5);
        	  hashMap1.put("zhangsan", 96.0);
        	  hashMap1.put("lisi", 88.6);
        	  hashMap1.put("wangwu", 98.6);
        	  hashMap1.put("wangting",  87.5);
        	  
        	  Set<String> keySet = hashMap1.keySet();
        	  Iterator<String> iterator = keySet.iterator();
        	  while(iterator.hasNext())
        	  {
        		  String key = iterator.next();
        		  System.out.println(key+"\t"+hashMap1.get(key));
        	  }
        	  System.out.println("Java中自带的数据类型:相同的对象会覆盖!");
        	  System.out.println("\n");
        	  //用户自定义的数据类型:为重写之前
        	  System.out.println("测试用户自定义的数据类型--未重写两个方法之前:");
        	  HashMap<Student, String> hashMap2 = new HashMap<Student,String>();
        	  hashMap2.put(new Student("zhangsan",88.8), "beijing");
        	  hashMap2.put(new Student("lisi",88.8), "beijing");
        	  hashMap2.put(new Student("wangwu",66.9), "beijing");
        	  hashMap2.put(new Student("zhangsan",88.8), "beijing");
        	  hashMap2.put(new Student("lisi",88.8), "beijing");
        	  hashMap2.put(new Student("wangwu",66.9), "beijing");
        	  Set<Student> keySet2 = hashMap2.keySet();
        	  Iterator<Student> iterator2 = keySet2.iterator();
        	  while(iterator2.hasNext())
        	  {
        		  Student key = iterator2.next();
        		  System.out.println(key+"\t"+hashMap2.get(key));
        	  }
        	  System.out.println("如果没有重写:导致相同的对象不会被覆盖!");
        	  
        	 
         }
    }
    class Student implements  Comparable<Student>
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    	public int compareTo(Student obj)
    	{
    	      if(this.score > obj.score)
    	    	  return 1;
    	      else
    	    	  return -1;
    	}
    }
    

    输出结果:

    先测试Java中自带的数据类型:
    wangting	87.5
    wangwu	98.6
    lisi	88.6
    zhangsan	96.0
    Java中自带的数据类型:相同的对象会覆盖!
    
    
    测试用户自定义的数据类型--为重写两个方法之前:
    zhangsan	88.8	beijing
    wangwu	66.9	beijing
    lisi	88.8	beijing
    wangwu	66.9	beijing
    zhangsan	88.8	beijing
    lisi	88.8	beijing
    如果没有重写:导致相同的对象不会被覆盖!
    

    实例程序2:重写之后

    package IT;
    
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Set;
    
    public class App
    {
         public static void main(String[] args)
         {
        	  //用户自定义的数据类型:为重写之后
        	  System.out.println("测试用户自定义的数据类型--重写两个方法之后:");
        	  HashMap<Student, String> hashMap2 = new HashMap<Student,String>();
        	  hashMap2.put(new Student("zhangsan",88.8), "beijing");
        	  hashMap2.put(new Student("lisi",88.8), "beijing");
        	  hashMap2.put(new Student("wangwu",66.9), "beijing");
        	  hashMap2.put(new Student("zhangsan",88.8), "beijing");
        	  hashMap2.put(new Student("lisi",88.8), "beijing");
        	  hashMap2.put(new Student("wangwu",66.9), "beijing");
        	  Set<Student> keySet2 = hashMap2.keySet();
        	  Iterator<Student> iterator2 = keySet2.iterator();
        	  while(iterator2.hasNext())
        	  {
        		  Student key = iterator2.next();
        		  System.out.println(key+"\t"+hashMap2.get(key));
        	  }
        	  System.out.println("重写过后:相同的对象会被覆盖!");
        	  
        	 
         }
    }
    class Student implements  Comparable<Student>
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    	public int compareTo(Student obj)
    	{
    	      if(this.score > obj.score)
    	    	  return 1;
    	      else
    	    	  return -1;
    	}
    	@Override
    	public int hashCode()
    	{
    		return (int) (this.name.hashCode()*score);//保证相同对象映射到同一个索引位置
    	}
    	@Override
    	public boolean equals(Object obj)
    	{
    		Student cc = (Student)obj;
    		return this.name==cc.name&&this.score==cc.score;
    	}
    }
    

    输出结果:

    测试用户自定义的数据类型--重写两个方法之后:
    wangwu	66.9	beijing
    zhangsan	88.8	beijing
    lisi	88.8	beijing
    重写过后:相同的对象会被覆盖!
    

    8、重要的一个逻辑:逻辑上来讲,只要两个对象的内容相同,其地址(hashCode()返回值)以及这两个对象就应该相同(equals()),
    实例程序(为重写之前):

    package IT;
    
    public class App
    {
         public static void main(String[] args)
         {
        	 //Java中自带的数据类型
        	 System.out.println(new Integer(1).equals(new Integer(1)));
        	 System.out.println(new Integer(1).hashCode()==new Integer(1).hashCode());
        	 System.out.println(new String("zhang").equals(new String("zhang")));
        	 System.out.println(new String("zhang").hashCode()==new String("zhang").hashCode());
        	 
             System.out.println("\n");
             
             //用户自定义的数据类型
             
        	 System.out.println(new Student("zhangsan",98.8).equals(new Student("zhangsan",98.8)));
        	 System.out.println(new Student("zhangsan",98.8).hashCode());
        	 System.out.println(new Student("zhangsan",98.8).hashCode());
        	 
         }
    }
    class Student implements  Comparable<Student>
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    	public int compareTo(Student obj)
    	{
    	      if(this.score > obj.score)
    	    	  return 1;
    	      else
    	    	  return -1;
    	}
    }
    

    输出结果:

    true
    true
    true
    true
    
    
    false
    488676694
    1211729930
    

    重写之后:

    package IT;
    
    public class App
    {
         public static void main(String[] args)
         {
        	 System.out.println(new Student("zhangsan",98.8).equals(new Student("zhangsan",98.8)));
        	 System.out.println(new Student("zhangsan",98.8).hashCode());
        	 System.out.println(new Student("zhangsan",98.8).hashCode());
        	  
        	 
         }
    }
    class Student implements  Comparable<Student>
    {
         public String name;
         public double score;
         public Student(String name,double score)
         {
        	 this.name = name;
        	 this.score = score;
         }
         public String toString()
         {
        	 return this.name+"\t"+this.score;
         }
    	public int compareTo(Student obj)
    	{
    	      if(this.score > obj.score)
    	    	  return 1;
    	      else
    	    	  return -1;
    	}
    	@Override
    	public int hashCode()
    	{
    		return (int) (this.name.hashCode()*score);
    	}
    	@Override
    	public boolean equals(Object obj)
    	{
    		Student cc = (Student)obj;
    		return this.name==cc.name&&this.score==cc.score;
    	}
    }
    

    输出结果:

    true
    -2147483648
    -2147483648
    

    上面的5、6、7、8可以归结为4个"凡是",1个“逻辑”:
    1、凡是把类对象放到容器中,相应的类都应该实现Object类中的toString()方法;
    2、凡是需要进行比较排序的类都应该实现Comparable接口中的compareTo()方法;凡是把类对象放到以树为内部结构的容器中都应该实现Comparable接口中的compareTo()方法
    3、凡是把类对象放到以哈希表为内部存储结构的容器中,相应的类必须要实现equals方法和hashCode方法,这样才符合哈希表真实的逻辑功能.
    4、逻辑上来讲,只要两个对象的内容相同,其地址(hashCode()返回值)以及这两个对象就应该相同(equals())。
    9、哈希冲突的相关概念
    在这里插入图片描述
    本质上讲就是:hash(对象1.hashCode())=hash2(对象2.hashCode()),即第一个对象的hashCode()方法返回的哈希码值带入到哈希函数后得到的索引位置与第二个对象的hashCode()方法返回的哈希码值带入到哈希函数后得到的索引位置相同,这就是哈希冲突。
    最常见的哈希算法是取模法。
    下面简单讲讲取模法的计算过程。
    比如:数组的长度是5。这时有一个数据是6。那么如何把这个6存放到长度只有5的数组中呢。按照取模法,计算6%5,结果是1,那么就把6放到数组下标是1的位置。那么,7
    就应该放到2这个位置。到此位置,哈斯冲突还没有出现。这时,有个数据是11,按照取模法,11%5=1,也等于1。那么原来数组下标是1的地方已经有数了,是6。这时又计算出1这个位置,那么数组1这个位置,就必须储存两个数了。这时,就叫哈希冲突。冲突之后就要按照顺序来存放了。
    如果数据的分布比较广泛,而且储存数据的数组长度比较大。
    那么哈希冲突就比较少。否则冲突是很高的。
    10、iterator接口的作用
    在这里插入图片描述
    在这里插入图片描述
    重要方法:

    boolean hasNext():是用来判断当前游标(迭代器)的后面是否存在元素,如果存在返回真,否则返回假
    Object next():先返回当前游标右边的元素,然后游标后移一个位置
    void remove():不推荐使用iterator的remove()方法,而是推荐使用容器自带的remove方法。
    

    在这里插入图片描述
    实例程序:

    package IT;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Set;
    
    public class App
    {
         public static void main(String[] args)
         {
        	  HashMap<String, Double> hashMap = new HashMap<String,Double>();
        	  hashMap.put("zhangsan", 88.6);
        	  hashMap.put("lisi", 69.0);
        	  hashMap.put("wanqwu", 100.0);
        	  hashMap.put("lisi", 69.0);
        	  
        	  Set<String> keySet = hashMap.keySet();
        	  Iterator<String> iterator = keySet.iterator();
        	  while(iterator.hasNext())
        	  {
        		  String key = iterator.next();//获取迭代器右边的元素,同时右移
        		  System.out.println(key+hashMap.get(key));
        	  }
        	  
        	 
         }
    }
    

    思考题:

    package IT;
    
    
    import java.util.TreeSet;
    
    public class App
    {
         public static void main(String[] args)
         {
                 TreeSet<Student> treeSet = new TreeSet<Student>();
               
             
                 treeSet.add(new Student("zhangsan",98));
                 treeSet.add(new Student("zhangsan",98));
                 System.out.println(treeSet.size());
                 System.out.println(treeSet);
        	 
                 //本程序中并没有重写equals方法,但是treeSet将识别出两个new Student("zhangsan",98)为相同的,因为内部数据结构吗?
                 System.out.println(new Student("zhangsan",98).equals(new Student("zhangsan",98)));
     
         }
    }
    class Student implements Comparable<Object>
    {
    	  public String name;
    	  public double score;
    	  public Student(String name,double score)
    	  {
    		  this.name = name;
    		  this.score = score;
    	  }
    	  public String toString()
    	  {
    		  return name + "\t" + score;
    	  }
    	@Override
    	public int compareTo(Object obj)
    	{
    		Student cc = (Student)obj;
    		return (int) (this.score - cc.score);
    	}
    
    }
    

    程序3:

    public class Test_iterator
    {
        public static void main(String[] args)
    	{
    		ArrayList<Integer> arrayList = new ArrayList<Integer>();
    		arrayList.add(10);
    		arrayList.add(20);
    		arrayList.add(30);
    		
    		Iterator<Integer> iterator = arrayList.iterator();
    		
    		
    		while (iterator.hasNext())
    		{
    			Integer aaInteger = iterator.next();
    			System.out.println(aaInteger);
    			
    		}
    	}
    }
    
    
    /**
     *  10
    	20
    	30
     */
    

    上面的讲解如有问题,欢迎留言指正!

    展开全文
  • k8s已经成为当今容器化的标准,人们在享受容器带来的高效与便利的同时,也遇到一些烦恼:客户端和容器服务器之间可能存在多种不同形式的代理服务器,那容器中如何获取到客户端真实的源ip呢?下面我们就几种场景类型...
    摘要:客户端和容器服务器之间可能存在多种不同形式的代理服务器,那容器中如何获取到客户端真实的源ip呢?

    k8s已经成为当今容器化的标准,人们在享受容器带来的高效与便利的同时,也遇到一些烦恼:客户端和容器服务器之间可能存在多种不同形式的代理服务器,那容器中如何获取到客户端真实的源ip呢?下面我们就几种场景类型如何能获取到源ip进行讨论。

    原理介绍:

    四层转发:

    Nodeport:nodeport访问方式,是将容器端口映射到节点端口,如果“服务亲和”选择“集群级别”需要经过一次服务转发,无法实现获取客户端源ip,而“节点模式”不经过转发,可以获取客户端源ip。

    ELB:ELB访问方式,是通过华为云ELB产品来实现负载均衡,“服务亲和”也是需要选择“节点级别”,其中“共享型”ELB需要在节点安装TOA插件,而“独享型”ELB默认透传源ip,不需要安装TOA插件。

    七层转发:

    Ingress:应用在七层访问时,客户端源ip默认保存在HTTP头部的“X-Forwarded-For”字段,无需做其他操作。

    具体操作:

    一、负载均衡 ( LoadBalancer )

    负载均衡( LoadBalancer )的Service模式下,支持容器中获取源IP需要满足以下前提条件:

    1. 服务亲和选择“节点级别”而不是“集群级别”。

    2. 在pod所在的节点安装TOA插件。(“独享型”ELB无需进行以下操作)

    安装TOA插件步骤如下:

    1) 准备编译环境:

    执行如下命令,安装gcc编译器。

    ]# yum install gcc

    执行如下命令,安装make工具。

    ]# yum install make

    2)编译内核模块

    a) 下载TOA内核模块源代码。

    ]# wget https://github.com/Huawei/TCP_option_address/archive/master.zip b)     执行如下命令,进入源码目录,编译模块。

    ]# unzip master.zip
    ]# cd TCP_option_address-master/src/
    ]# make

    编译过程未提示warning或者error,说明编译成功,检查当前目录下是否已经生成toa.ko文件。

    说明:如果报错提示“config_retpoline=y but not supported by the compiler, Compiler update recommended”,表明gcc版本过老,建议将gcc升级为较新版本。

    3)加载内核模块

    执行如下命令,加载内核模块。

    ]# insmod toa.ko

    执行如下命令,验证模块加载情况,查看内核输出信息。

    ]# dmesg | grep TOA

    若提示信息包含“TOA: toa loaded”,说明内核模块加载成功。

    4) 自动加载内核模块

    为了使TOA内核模块在系统启动时生效,可以将加载TOA内核模块的命令加到客户的启动脚本中。

    在“/etc/sysconfig/modules/”目录下新建toa.modules文件。该文件包含了TOA内核模块的加载脚本,请参考如下示例:

    #!/bin/sh
    /sbin/modinfo -F filename /root/toa/toa.ko > /dev/null 2>&1
    if [ $? -eq 0 ]; then
    /sbin/insmod /root/TCP_option_address-master/src/toa.ko
    fi

    注意:其中“/root/TCP_option_address-master/src/toa.ko”为TOA内核模块文件的路径,客户需要将其替换为自己编译的TOA内核模块路径。

    执行以下命令,为toa.modules启动脚本添加可执行权限。

    ]# chmod +x /etc/sysconfig/modules/toa.modules

    这种情况下可以从四层负载均衡上获取到客户端的源IP(可以通过netstat查看)。

    测试要点:这种情况下可以使用netstat看到客户端连接到POD的IP地址。

    二、节点访问 ( NodePort )

    节点访问(NodePort)类型的Service的服务亲和选择“节点级别”而不是“集群级别”,即Service的 spec.externalTrafficPolicy 需要设置为 Local

    图1 服务亲和选择节点级别

    三、七层负载均衡(Ingress)

    七层负载均衡的模式下,不能在四层负载均衡上获取客户端IP(不能通过netstat查看客户端IP),需要对应用服务器进行配置,然后通过七层负载均衡的http头中的x-forward-for获取。

    真实的来访者IP会被负载均衡放在HTTP头部的X-Forwarded-For字段,格式如下:

    X-Forwarded-For: 来访者真实IP, 代理服务器1-IP,  代理服务器2-IP, ...

    测试要点:从容器中获取http请求头”x-forward-for”,获取的IP为客户端的IP。

     

    点击关注,第一时间了解华为云新鲜技术~

    展开全文
  • Python有关网页操作的标准库有很多 这次使用两个流行的BeautifulSoup库和HTMLSession库的方法,在你需要在自己的程序插入指定网页的指定容器的内容时,可以插入下面的内容,因为你需要的信息可能是一直在变动的...
  • Go标准容器之Ring

    千次阅读 2017-06-01 12:59:38
    简介Go的标准包Container包含了常用的容器类型,包括conatiner/list,container/heap,container/ring,本篇讲解container/ring的使用。ring包ring包提供了环形链表的操作。它仅导出了一个类型,Ring:// Ring表示...
  • 添加一个 sidecar 容器(使用busybox 镜像)到已有的 pod 11-factor-app 确保 sidecar 容器能够输出 /var/log/11-factor-app.log 的信息 使用 volume 挂载 /var/log 目录,确保 sidecar 能访问 11-factor-app....
  • C++标准库-顺序容器

    千次阅读 2020-06-30 03:23:09
    标准的三种顺序容器3.容器构造方法二、容器的选择三、容器的操作1.顺序容器中的类型别名2.迭代器3.容器内的修改 一、 顺序容器概述 1.定义 容器就是特定类型对象的集合。顺序容器为程序员提供了控制元素存储和...
  • OCI 和 runc:容器标准化和 docker

    千次阅读 2018-04-25 08:39:44
    OCI 和容器标准容器技术随着 docker 的出现炙手可热,所有的技术公司都积极拥抱容器,促进了 docker 容器的繁荣发展。容器一词虽然口口相传,但却没有统一的定义,这不仅是个技术概念的问题,也给整个社区带来一个...
  • Java集合容器面试题(2020最新版)

    万次阅读 多人点赞 2020-03-01 11:08:34
    文章目录集合容器概述什么是集合集合的特点集合和数组的区别使用集合框架的好处常用的集合类有哪些?List,Set,Map三者的区别?List、Set、Map 是否继承自 Collection 接口?List、Map、Set 三个接口存取元素时,各...
  • 一、依附容器依附操作attach通常用在由docker start或者docker restart启动的交互型容器中。由于docker start启动的交互型容器并没有具体终端可以依附,而容器本身是可以接收用户交互的,这时就需要通过attach命令来...
  • 在 Docker 容器中运行应用程序

    千次阅读 2017-11-01 10:49:00
    案例说明 运行 3 个容器,实现对网站的监控...容器mailer: 该容器中运行一个 mailer 程序,运行于后台,当接收到事件后会向管理员发送邮件。 容器agent: 该容器运行一个 watcher 程序,以交互模式运行,用于不断地监...
  • 从事Java Web编程的朋友都知道,一个web...这些程序都遵从一个标准的Web工程标准,他们启动时都会去主动读取指定位置的web.xml文件,web.xml的各个节点都是既定的标准,Web容器会去按照规则读取配置信息将各种Cl...
  • 1.安装Docker yum install -y docker-io执行报错:[root@server1 ~]# yum install -y docker-io Loaded plugins: fastestmirror Determining fastest mirrors * base: mirrors.btte.net * extras: mirrors.btte.net...
  • c++iterator迭代器和vector容器

    千次阅读 2017-10-07 19:29:21
    好文章转载分享!... ... vector容器 ...vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string对象一样,标准库负责管理存储元素的相关内存。...一个容器中的所有对象都必须是同一种类型的。
  • Docker 容器

    千次阅读 2018-05-29 17:41:15
    启动容器 新建并启动 启动已终止容器 后台运行 终止容器 进入容器 attach 命令 exec 命令 -i -t 参数 导出和导入容器 导出容器 导入容器快照 删除容器 清理所有处于终止状态的容器 启动容器 ...
  • 容器日志处理及实现

    千次阅读 2017-04-28 11:05:11
    stdout,stderr 标准输出 这种形式的日志输出我们可以直接使用docker logs查看日志, k8s 集群同样集群可以使用kubectl logs类似的形式查看日志。 日志文件记录 这种日志输出我们无法从以上方法查看日志内容,只能...
  • 阅读完这篇博文后,你将能够使用Django,PostgreSQL,Redis和RabbitMQ配置Celery,然后在Docker容器中运行它们。 今天,你将学习如何建立一个分布式任务处理系统来快速建立原型。你将使用Django,PostgreSQL,Redis...
  • Kubernets:容器日志收集方案

    千次阅读 2020-03-14 13:46:35
    日志的形式变得更加复杂,不仅有物理机/虚拟机上的日志,还有容器标准输出容器内的文件、容器事件、Kubernetes 事件等等信息需要采集; 环境的动态性变强,在 Kubernetes ,机器的宕机、下线、上...
  • C++ STL map 容器的说明和使用技巧

    万次阅读 多人点赞 2014-07-22 10:04:02
    Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!   1、map简介 map是一类关联式容器。它的特点是增加和删除节点...
  • C++容器类详解

    万次阅读 多人点赞 2015-12-18 15:05:55
    C++容器类包括“顺序存储结构”和“关联存储结构”,前者包括vector,list,deque等;后者包括set,map,multiset,multimap等。若需要存储的元素数在编译器间就可以确定,可以使用数组来存储,否则,就需要用到...
  • Docker容器日志配置简介

    千次阅读 2019-04-05 20:39:24
    通常,我们可以使用docker logs来查看容器的日志信息,这是因为docker帮我们将容器内主进行打印到标准输出到信息记录了下来,以便于在需要时获取容器的运行信息。 Docker提供多种容器日志记录机制,这种日志机制称之...
  • 容器在C++的详细说明(vector)

    千次阅读 2012-07-18 14:30:17
    标准STL序列容器:vector、string、deque和list。 标准STL关联容器:set、multiset、map和multimap。 非标准序列容器slist和rope。slist是一个单向链表,rope本质上是一“重型”string。 非标准的关联容器hash_...
  • Qt容器类介绍,遍历容器

    千次阅读 2017-04-19 16:27:30
    顺序容器:是指容器中的数据都为一个接一个的线性存储。如:QList、QLinkedList、QVector、QStack、QQueue; 关联容器容器中数据以<键,值>模式存储。如:QMap、QMultiMap、QHash、QMultiHash、QSet;下表为常见...
  • docker(5):容器

    千次阅读 2021-04-27 20:17:07
    启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。 1.1 新建并启动 所需要...
  • Docker 的 devicemapper 存储驱动程序利用此框架的精简配置和快照功能进行镜像和容器管理。本文将 Device Mapper 存储驱动程序称为 devicemapper,将内核框架称为 Device Mapper。 在支持这个特性的系统,对 ...
  • 侵入式容器

    千次阅读 2017-12-22 20:34:50
    与侵入式容器相对应的是非侵入式容器标准容器和指针容器都属于非侵入式容器,这类容器不要求对容纳的元素做任何修改即可容纳,较温和,用起来也简单方便。链表、二叉树等数据结构都属于侵入式容器
  • 我们知道,每个Pod在被成功创建出来之后,都会被系统分配唯一的名字、IP地址,并且处于某个Namespace,那么我们如何在Pod的容器获取Pod的这些重要信息呢?答案就是使用Downward API。 Down...
  • 为了能够适应容器云平台的管理模式和管理理念,应用系统需要完成容器化的改造过程。对于新开发的应用,建议直接基于微服务架构进行容器化的应用开发;对于已经运行多年的传统应用系统,也应该逐步将其改造成能够部署...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,428
精华内容 33,371
热门标签
关键字:

获取容器中的标准输出