Docker镜像制作

一、通过Dockerfile制作jar镜像

 1、定义Dockerfile文件

提前准备好wenjay-eureka.jar文件

FROM java

VOLUME /tmp/java

ADD wenjay-eureka.jar eureka.jar

RUN bash -c 'touch /eureka.jar'

EXPOSE 7001

# Image创建容器时的初始化内存,最大内存,及启动时使用的profile. -c为清除以前启动的数据
ENTRYPOINT ["java","-Xms1024m","-Xmx1024m","-jar","/eureka.jar","--spring.profiles.active=dev","--spring.security.user.name=wenjay","--spring.security.user.password=wenjay","--server.port=7001","--eureka.instance.hostname=wenjay-eureka-01","-c"]

2、执行docker的镜像制作命令

使用docker build -t wenjay.io:5000/eureka .

注意后面的点号不能丢,代表当前目录,如果Dockerfile在其他位置,请根据实际目录调整

[root@wenjay define]# docker build -t wenjay.io:5000/eureka .
Sending build context to Docker daemon  53.62MB
Step 1/6 : FROM java
latest: Pulling from library/java
5040bd298390: Pull complete
fce5728aad85: Pull complete
76610ec20bf5: Pull complete
60170fec2151: Pull complete
e98f73de8f0d: Pull complete
11f7af24ed9c: Pull complete
49e2d6393f32: Pull complete
bb9cdec9c7f3: Pull complete
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:latest
 ---> d23bdf5b1b1b
Step 2/6 : VOLUME /tmp/java
 ---> Running in 930fcee8e0b8
Removing intermediate container 930fcee8e0b8
 ---> da6c7c06b7a5
Step 3/6 : ADD wenjay-eureka.jar eureka.jar
 ---> 57ce21a3bd08
Step 4/6 : RUN bash -c 'touch /eureka.jar'
 ---> Running in 8051cad00d86
Removing intermediate container 8051cad00d86
 ---> b504f84903c1
Step 5/6 : EXPOSE 7001
 ---> Running in ca6d71dc8657
Removing intermediate container ca6d71dc8657
 ---> ac95d51897e5
Step 6/6 : ENTRYPOINT ["java","-Xms1024m","-Xmx1024m","-jar","/eureka.jar","--spring.profiles.active=dev","--spring.security.user.name=wenjay","--spring.security.user.password=wenjay","--server.port=7001","--eureka.instance.hostname=wenjay-eureka-01","-c"]
 ---> Running in 3e0610609dae
Removing intermediate container 3e0610609dae
 ---> 5cc9276293b4
Successfully built 5cc9276293b4
Successfully tagged wenjay.io:5000/eureka:latest
[root@wenjay define]#

3、查看镜像的详细

使用docker inspect <镜像名称>

[root@wenjay define]# docker inspect 545dcef31a62
[
    {
        "Id": "545dcef31a62e000c6e11be58d180e3cfbc32c023c95731829b076d8e5335e00",
        "Created": "2021-12-28T08:35:22.760988429Z",
        "Path": "java",
        "Args": [
            "-Xms1024m",
            "-Xmx1024m",
            "-jar",
            "/eureka.jar",
            "--spring.profiles.active=dev",
            "--spring.security.user.name=wenjay",
            "--spring.security.user.password=wenjay",
            "--server.port=7001",
            "--eureka.instance.hostname=wenjay-eureka-01",
            "-c"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 13839,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-12-28T08:35:23.373647837Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:5cc9276293b4eeeeed2af18440240f37857f2c1a3aca9b195f9e65fd7b487cf6",
        "ResolvConfPath": "/var/lib/docker/containers/545dcef31a62e000c6e11be58d180e3cfbc32c023c95731829b076d8e5335e00/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/545dcef31a62e000c6e11be58d180e3cfbc32c023c95731829b076d8e5335e00/hostname",
        "HostsPath": "/var/lib/docker/containers/545dcef31a62e000c6e11be58d180e3cfbc32c023c95731829b076d8e5335e00/hosts",
        "LogPath": "/var/lib/docker/containers/545dcef31a62e000c6e11be58d180e3cfbc32c023c95731829b076d8e5335e00/545dcef31a62e000c6e11be58d180e3cfbc32c023c95731829b076d8e5335e00-json.log",
        "Name": "/loving_lehmann",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {
                    "max-size": "100m"
                }
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/23fc55466091669de39ae1f69f0248a5b45777c8b88fe876b0eb3e1742f80c87-init/diff:/var/lib/docker/overlay2/84bb40e8f02d6b159422dacc85e70811071a37193db69cae49066b74f78e7762/diff:/var/lib/docker/overlay2/39f9b31cd3aa93318c71717a1e8ff4f6c564327da5331b5982e24bc041985556/diff:/var/lib/docker/overlay2/31acefccd18d2890de5a3db1318ca4e1d5c51d0111a5ed9da870db560c1c1be3/diff:/var/lib/docker/overlay2/a72bcc970ad750a59021de24970d04599840ee524df891e5da4df3eaa00f9947/diff:/var/lib/docker/overlay2/24cf63c94d5aa4237a440528b95cd02b6bd83e629eca0320c37c53d03afd9f0b/diff:/var/lib/docker/overlay2/7051c06f42b4f2ab8aac0b211d0f0748f0173993b247963c7b5470f419f2fa79/diff:/var/lib/docker/overlay2/d5d78732c72cf93fa6b92430dc2e5a1c393c1a6f511864e7845542e5888ee67b/diff:/var/lib/docker/overlay2/053a5e6c86ddbf641fff52d6005ee8c1cf9da303fea6aae02ade7e6447d208e1/diff:/var/lib/docker/overlay2/e5891927a4f34465335db6a46425f84eaf1d090724b5346d8aed6d0154028f1f/diff:/var/lib/docker/overlay2/06e6db7800a7e0f65c5b30ef6bf7482ac295dc5e4a2eaf457d7e922b74f11f7b/diff",
                "MergedDir": "/var/lib/docker/overlay2/23fc55466091669de39ae1f69f0248a5b45777c8b88fe876b0eb3e1742f80c87/merged",
                "UpperDir": "/var/lib/docker/overlay2/23fc55466091669de39ae1f69f0248a5b45777c8b88fe876b0eb3e1742f80c87/diff",
                "WorkDir": "/var/lib/docker/overlay2/23fc55466091669de39ae1f69f0248a5b45777c8b88fe876b0eb3e1742f80c87/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "volume",
                "Name": "f78738490fae81343a5ca20c8bb2662714d3ac6b266f09cf64ce9f240debaee5",
                "Source": "/var/lib/docker/volumes/f78738490fae81343a5ca20c8bb2662714d3ac6b266f09cf64ce9f240debaee5/_data",
                "Destination": "/tmp/java",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
            "Hostname": "545dcef31a62",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "7001/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "LANG=C.UTF-8",
                "JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64",
                "JAVA_VERSION=8u111",
                "JAVA_DEBIAN_VERSION=8u111-b14-2~bpo8+1",
                "CA_CERTIFICATES_JAVA_VERSION=20140324"
            ],
            "Cmd": null,
            "Image": "wenjay.io:5000/eureka",
            "Volumes": {
                "/tmp/java": {}
            },
            "WorkingDir": "",
            "Entrypoint": [
                "java",
                "-Xms1024m",
                "-Xmx1024m",
                "-jar",
                "/eureka.jar",
                "--spring.profiles.active=dev",
                "--spring.security.user.name=wenjay",
                "--spring.security.user.password=wenjay",
                "--server.port=7001",
                "--eureka.instance.hostname=wenjay-eureka-01",
                "-c"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "5112280ce667a5856f5ca3a2d370e223e6c9188fe4fe283a72fec895e98b7216",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "7001/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/5112280ce667",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "c24e59964de108de8063d3596b050c3e7203b7b93b39fa0a3f646cb20331fcca",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.6",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:06",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "54d1fceedd268f2a1dccde75b614c4fb31c488b4b220f8879a422369e0f845e3",
                    "EndpointID": "c24e59964de108de8063d3596b050c3e7203b7b93b39fa0a3f646cb20331fcca",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.6",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:06",
                    "DriverOpts": null
                }
            }
        }
    }
]
[root@wenjay define]#

4、验证镜像

docker run启动镜像

[root@wenjay define]# docker run -d -p 8080:7001 -v /opt/eureka:/tmp/java --name wenjay_eureka  wenjay.io:5000/eureka
3d569f2b63e36f5331d653d3b6d747650d36c78a17586035fafe469a22fdac4b
[root@wenjay define]#

[root@wenjay define]# docker logs wenjay_eureka
2021-12-28 08:44:25.572  INFO 1 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$4518bad] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2021-12-28 08:44:25.756  INFO 1 --- [           main] com.wenjay.eureka.EurekaApplication      : The following profiles are active: dev
2021-12-28 08:44:26.889  WARN 1 --- [           main] o.s.boot.actuate.endpoint.EndpointId     : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format.
2021-12-28 08:44:27.245  INFO 1 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=73abebd2-fee3-3511-b85d-7a0c81e6d174
2021-12-28 08:44:27.455  INFO 1 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$4518bad] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2021-12-28 08:44:27.909  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 7001 (http)
2021-12-28 08:44:27.932  INFO 1 --- [           main] o.a.coyote.http11.Http11NioProtocol      : Initializing ProtocolHandler ["http-nio-7001"]
2021-12-28 08:44:27.953  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-12-28 08:44:27.953  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]

页面访问eureka

 

5、进入容器内部查看

/var/local/logs/logs/wenjay-eureka为java包eureka.jar配置参数设定的日志目录

[root@wenjay define]# nsenter --target 14361 --mount --uts --ipc --net --pid
root@3d569f2b63e3:/# cd /var/local/logs/logs/wenjay-eureka/
root@3d569f2b63e3:/var/local/logs/logs/wenjay-eureka# ls
error.log  server.log
root@3d569f2b63e3:/var/local/logs/logs/wenjay-eureka#

6、其他

1、如何进入容器:

  • docker attach [容器ID]
  • nsenter 

 先用inspect获得容器的第一个进程的PID:
docker inspect  --format "{{.State.Pid}}" wenjay_registry

使用命令nsenter 进入nsenter --target 11935 --mount --uts --ipc --net --pid

2、nsenter命令简介:

nsenter命令是一个可以在指定进程的命令空间下运行指定程序的命令。它位于util-linux包中。

用途

一个最典型的用途就是进入容器的网络命令空间。相当多的容器为了轻量级,是不包含较为基础的命令的,比如说ip addresspingtelnetsstcpdump等等命令,这就给调试容器网络带来相当大的困扰:只能通过docker inspect ContainerID命令获取到容器IP,以及无法测试和其他网络的连通性。这时就可以使用nsenter命令仅进入该容器的网络命名空间,使用宿主机的命令调试容器网络。

此外,nsenter也可以进入mntutsipcpiduser命令空间,以及指定根目录和工作目录。

使用

首先看下nsenter命令的语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
nsenter [options] [program [arguments]]

options:
-t, --target pid:指定被进入命名空间的目标进程的pid
-m, --mount[=file]:进入mount命令空间。如果指定了file,则进入file的命令空间
-u, --uts[=file]:进入uts命令空间。如果指定了file,则进入file的命令空间
-i, --ipc[=file]:进入ipc命令空间。如果指定了file,则进入file的命令空间
-n, --net[=file]:进入net命令空间。如果指定了file,则进入file的命令空间
-p, --pid[=file]:进入pid命令空间。如果指定了file,则进入file的命令空间
-U, --user[=file]:进入user命令空间。如果指定了file,则进入file的命令空间
-G, --setgid gid:设置运行程序的gid
-S, --setuid uid:设置运行程序的uid
-r, --root[=directory]:设置根目录
-w, --wd[=directory]:设置工作目录

如果没有给出program,则默认执行$SHELL。

示例:

运行一个nginx容器,查看该容器的pid:

1
2
[root@staight ~]# docker inspect -f {{.State.Pid}} nginx
5645

然后,使用nsenter命令进入该容器的网络命令空间:

1
2
3
4
5
6
7
8
9
10
[root@staight ~]# nsenter -n -t5645
[root@staight ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

进入成功~

在Kubernetes中,在得到容器pid之前还需获取容器的ID,可以使用如下命令获取:

1
2
[root@node1 test]# kubectl get pod test -oyaml|grep containerID
  - containerID: docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85

或者更为精确地获取containerID:

1
2
[root@node1 test]# kubectl get pod test -o template --template='{{range .status.containerStatuses}}{{.containerID}}{{end}}'
docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85

原理

namespace

namespace是Linux中一些进程的属性的作用域,使用命名空间,可以隔离不同的进程。

Linux在不断的添加命名空间,目前有:

  • mount:挂载命名空间,使进程有一个独立的挂载文件系统,始于Linux 2.4.19
  • ipc:ipc命名空间,使进程有一个独立的ipc,包括消息队列,共享内存和信号量,始于Linux 2.6.19
  • uts:uts命名空间,使进程有一个独立的hostname和domainname,始于Linux 2.6.19
  • net:network命令空间,使进程有一个独立的网络栈,始于Linux 2.6.24
  • pid:pid命名空间,使进程有一个独立的pid空间,始于Linux 2.6.24
  • user:user命名空间,是进程有一个独立的user空间,始于Linux 2.6.23,结束于Linux 3.8
  • cgroup:cgroup命名空间,使进程有一个独立的cgroup控制组,始于Linux 4.6

Linux的每个进程都具有命名空间,可以在/proc/PID/ns目录中看到命名空间的文件描述符。

1
2
3
4
5
6
7
8
9
10
[root@staight ns]# pwd
/proc/1/ns
[root@staight ns]# ll
total 0
lrwxrwxrwx 1 root root 0 Sep 23 19:53 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 23 19:53 uts -> uts:[4026531838]

clone

clone是Linux的系统调用函数,用于创建一个新的进程。

clone和fork比较类似,但更为精细化,比如说使用clone创建出的子进程可以共享父进程的虚拟地址空间,文件描述符表,信号处理表等等。不过这里要强调的是,clone函数还能为新进程指定命名空间。

clone的语法:

1
2
3
4
5
6
 #define _GNU_SOURCE
#include <sched.h>

int clone(int (*fn)(void *), void *child_stack,
        int flags, void *arg, ...
        /* pid_t *ptid, void *newtls, pid_t *ctid */ );

其中flags即可指定命名空间,包括:

  • CLONE_NEWCGROUP:cgroup
  • CLONE_NEWIPC:ipc
  • CLONE_NEWNET:net
  • CLONE_NEWNS:mount
  • CLONE_NEWPID:pid
  • CLONE_NEWUSER:user
  • CLONE_NEWUTS:uts

使用示例:

1
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);

setns

clone用于创建新的命令空间,而setns则用来让当前线程(单线程即进程)加入一个命名空间。

语法:

1
2
3
4
5
6
7
8
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>

int setns(int fd, int nstype);

fd参数是一个指向一个命名空间的文件描述符,位于/proc/PID/ns/目录。

nstype指定了允许进入的命名空间,一般可设置为0,表示允许进入所有命名空间。

因此,往往该函数的用法为:

  1. 调用setns函数:指定该线程的命名空间。
  2. 调用execvp函数:执行指定路径的程序,创建子进程并替换父进程。

这样,就可以指定命名空间运行新的程序了。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                        } while (0)

int
main(int argc, char *argv[])
{
    int fd;

    if (argc < 3) {
        fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    fd = open(argv[1], O_RDONLY); /* Get file descriptor for namespace */
    if (fd == -1)
        errExit("open");

    if (setns(fd, 0) == -1)       /* Join that namespace */
        errExit("setns");

    execvp(argv[2], &argv[2]);    /* Execute a command in namespace */
    errExit("execvp");
}

使用示例:

1
./ns_exec /proc/3550/ns/uts /bin/bash

nsenter

那么,最后就是nsenter了,nsenter相当于在setns的示例程序之上做了一层封装,使我们无需指定命名空间的文件描述符,而是指定进程号即可。

指定进程号PID以及需要进入的命名空间后,nsenter会帮我们找到对应的命名空间文件描述符/proc/PID/ns/FD,然后使用该命名空间运行新的程序。

参考文档

容器内抓包定位网络问题:容器内抓包定位网络问题 · TKE Handbook

man-page:nsenter:nsenter(1) - Linux manual page

man-page:clone:clone(2) - Linux manual page

man-page:setns:setns(2) - Linux manual page

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值