百科

uninstall是什么意思中文翻译,uninstall是什么

  

  照片由Michael Dziedzic在Unsplash上拍摄   

  

  使用Distroless镜子保护Kubernetes上的容器。   

  

  容器改变了我们看待技术基础设施的方式。这是我们运行应用程序方式的巨大飞跃。编排和云服务一起为我们提供了近乎无限的无缝可伸缩性。   

  

  根据定义,一个容器应该包含「应用程序」和它的「运行时依赖项」.然而,实际上,它们包含的远不止这些。标准容器基础映像包含包管理器、shell和其他可以在标准Linux发行版中找到的程序。   

  

  尽管这些都是构建容器映像所必需的,但它们不应该是最终映像的一部分。例如,一旦安装了包,就不再需要在容器中使用包管理工具,如apt。   

  

  这不仅会在您的容器中装满不必要的软件包和程序,还会为网络犯罪分子提供攻击特定程序漏洞的机会。   

  

  您应该总是知道容器的运行时中存在什么,并且应该精确地将它限制在应用程序所需的依赖项上。   

  

  除了那些必要的,你不应该安装任何东西。一些领先的技术巨头,如Google,在生产中运行容器方面有多年的经验,并且已经采用了这种方法。   

  

  谷歌现在通过提供无发行版图片向全世界开放这项功能。Google构建的这些映像的目标是只包含您的应用程序及其依赖项,同时,它们不会具有常规Linux发行版的所有功能,包括shell。   

  

  「这意味着虽然可以像以前一样运行应用程序的容器,但不能在容器运行的时候进入容器内」.这是一个重大的安全改进,因为您现在已经关闭了黑客通过shell进入您的容器的大门。   

  

  distroles基本映像Google为大多数流行的编程语言和平台提供了distroles的基本映像。   

  

  以下基本图像是正式发布的版本:   

  

  gcr . io/distrolless/static-debian 10g Cr . io/distrolless/base-debian 10g Cr . io/distrolless/Java-debian 10g Cr . io/distrolless/cc-debian 10g Cr . io/distrolless/nodejs-debian 10以下基本镜像还在实验阶段,   

  

  gcr . io/distrolless/python 2.7-debian 10g Cr . io/distrolless/python 3-debian 10g Cr . io/distrolless/Java/jetty-debian 10g Cr . io/distrolless/dot net构建distrolless映像Google内部使用Bazel构建容器映像,但我们也可以使用Docker来做同样的事情。关于使用无发行版映像的一个有争议的问题是:当我们有一个无发行版映像时,我们如何使用Dockerfile来构建我们的应用程序?   

  

  通常,Dockerfile从标准的操作系统基础映像开始,然后是创建适当的运行时构建所需的几个步骤。这包括这个包的安装,它需要一个像apt或者yum这样的包管理器。   

  

  有两种方法:   

  

  首先在Docker外部构建应用程序,然后使用Dockerfile中的ADD或COPY命令将二进制包复制到容器中。用多级码头建造。这是Docker 17.05及更高版本的一个新特性,它允许你将构建分成不同的阶段。第一阶段可以从标准的OS基本映像开始,它可以帮助您构建应用程序;第二阶段可以简单地从第一阶段获得构建文件,并使用发行版作为基本映像。为了理解它是如何工作的,让我们使用多阶段构建过程来做一个实践练习。   

  

  必要条件你需要具备以下几点:   

  

  Docker版本大于或等于17.05,用于为实践练习的第二部分构建可选的Kubernetes集群。如果想在docker中运行容器,可以使用等效的Docker命令。作为一个实际练习,将GitHub代码仓库分支到您的GitHub帐户中,然后克隆GitHub代码仓库并使用cd进入项目目录。   

  

  代码仓库包含一个Python Flask应用程序,当您调用API时,它将响应Hello World!   

  

  app.py文件如下所示:   

  

  fromflaskimportFlaskapp=Flask(_ _ name _ _)@ app . route('/')def hello(): return ' hello world!if__name__==   

39;__main__':app.run(host='0.0.0.0',debug=True)Dockerfile 包含两个阶段:

  

FROMpython:2.7-slimASbuildADD./appWORKDIR/appRUNpipinstall--upgradepipRUNpipinstall-r./requirements.txtFROMgcr.io/distroless/python2.7COPY--from=build/app/appCOPY--from=build/usr/local/lib/python2.7/site-packages/usr/local/lib/python2.7/site-packagesWORKDIR/appENVPYTHONPATH=/usr/local/lib/python2.7/site-packagesEXPOSE5000CMD构建阶段:

  

从 python:2.7-slim 的基础镜像开始将应用程序复制到 /app 目录下升级 pip 并安装依赖Distroless 阶段:

  

从 gcr.io/distroless/python2.7 的基础镜像开始将应用程序从构建阶段的 /app 目录复制到当前阶段的 /app 目录将 python 的 site-packages 从构建阶段复制到当前阶段的 site-packages 目录设置工作目录到 /app,将 python PATH 设置为 site-packages 目录,并暴露 5000 端口使用 CMD 指令运行 app.py由于 Disroless 镜像不包含 shell,所以应该在最后使用 CMD 指令。如果不这样做,Docker 将认为它是一个 shell CMD,并试图这样执行它,但这是不工作的。

  

构建镜像:

  

$dockerbuild-t<your_docker_repo>/flask-hello-world-distroless.SendingbuildcontexttoDockerdaemon95.74kBStep1/12:FROMpython:2.7-slimASbuild--->eeb27ee6b893Step2/12:ADD./app--->a01dc81df193Step3/12:WORKDIR/app--->Runningin48ccf6b990e4Removingintermediatecontainer48ccf6b990e4--->2e5e335be678Step4/12:RUNpipinstall--upgradepip--->Runningin583be3d0b8ccCollectingpipDownloadingpip-20.1.1-py2.py3-none-any.whl(1.5MB)Installingcollectedpackages:pipAttemptinguninstall:pipFoundexistinginstallation:pip20.0.2Uninstallingpip-20.0.2:Successfullyuninstalledpip-20.0.2Successfullyinstalledpip-20.1.1Removingintermediatecontainer583be3d0b8cc...................................SuccessfullyinstalledJinja2-2.11.2MarkupSafe-0.23click-7.1.2flask-1.1.2itsdangerous-0.24werkzeug-1.0.1Removingintermediatecontainerc4d00b1abf4a--->01cbadcc531fStep6/12:FROMgcr.io/distroless/python2.7--->796952c43cc4Step7/12:COPY--from=build/app/app--->92657682cdccStep8/12:COPY--from=build/usr/local/lib/python2.7/site-packages/usr/local/lib/python2.7/site-packages--->faafd06edeacStep9/12:WORKDIR/app--->Runningin0cf545aa0e62Removingintermediatecontainer0cf545aa0e62--->4c4af4333209Step10/12:ENVPYTHONPATH=/usr/local/lib/python2.7/site-packages--->Runningin681ae3cd51ccRemovingintermediatecontainer681ae3cd51cc--->564f48eff90aStep11/12:EXPOSE5000--->Runningin7ff5c073d568Removingintermediatecontainer7ff5c073d568--->ccc3d211d295Step12/12:CMD--->Runningin2b2c2f111423Removingintermediatecontainer2b2c2f111423--->76d13d2f61cdSuccessfullybuilt76d13d2f61cdSuccessfullytagged<your_docker_repo>/flask-hello-world-distroless:latest登录到 DockerHub 并推送镜像:

  

dockerlogindockerpush<your_docker_repo>/flask-hello-world-distroless:latest登录到 DockerHub(或者你的私有镜像仓),你应该会看到容器镜像可以使用:

     

distroless-2

  

如果你看一下压缩后的大小,它只有 23.36 MB。如果你使用 slim 发行版作为基础镜像,它将占用 56 MB。

     

distroless-2

  

你已经减少了超过一半的容器占用空间。That’s amazing!

  

在 Kubernetes 中运行容器为了测试构建是否有效,让我们在 Kubernetes 集群中运行容器。如果你没有 Kubernetes,你可以运行等价的 Docker 命令来做相同的活动,因为 Kubectl 和 Docker 命令是相似的。

  

我在代码仓中创建了一个 kubernetes.yaml 文件,该文件包含使用我们构建的镜像的 Deployment 和 负载均衡的 Service。

  

---apiVersion:apps/v1kind:Deploymentmetadata:name:flask-deploymentspec:selector:matchLabels:app:flaskreplicas:2template:metadata:labels:app:flaskspec:containers:-name:flaskimage:bharamicrosystems/flask-hello-world-distrolessports:-containerPort:5000---apiVersion:v1kind:Servicemetadata:name:flask-servicespec:selector:app:flaskports:-port:80targetPort:5000type:LoadBalancer这是一个非常简单的设置。负载均衡器监听端口 80 并映射到目标端口 5000。这些 Pods 在默认的 5000 端口上监听 Flask 应用程序。

  

应用:

  

$kubectlapply-fkubernetes.yamldeployment.apps/flask-deploymentcreatedservice/flask-servicecreated我们查看一下所有的资源,看看我们已经创建了什么:

  

$kubectlgetallNAMEREADYSTATUSRESTARTSAGEpod/flask-deployment-576496558b-hnbxt1/1Running047spod/flask-deployment-576496558b-hszpq1/1Running073sNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S)AGEservice/flask-serviceLoadBalancer10.8.9.16335.184.113.12080:31357/TCP86sservice/kubernetesClusterIP10.8.0.1<none>443/TCP26mNAMEREADYUP-TO-DATEAVAILABLEAGEdeployment.apps/flask-deployment2/22288sNAMEDESIREDCURRENTREADYAGEreplicaset.apps/flask-deployment-576496558b22289s我们看到存在两个 Pods、一个 Deployment、一个带有外部 IP 的 LoadBalancer 服务和一个 ReplicaSet。

  

让我们访问应用程序:

  

$curlhttp://35.184.113.120HelloWorld!我们得到了 Hello World!。这表明 Flask 应用程序在正常工作。

  

使用 Shell 对应用程序进行访问正如我在引言中所描述的,Disroless 容器中没有 shell,因此不可能进入到容器内。然而,让我们试着在容器中执行 exec:

  

$kubectlexec-itflask-deployment-576496558b-hnbxt/bin/bashOCIruntimeexecfailed:execfailed:container_linux.go:349:startingcontainerprocesscaused"exec:\"/bin/bash\":stat/bin/bash:nosuchfileordirectory":unknowncommandterminatedwithexitcode126我们无法连接到容器上。

  

容器日志呢?如果拿不到容器日志,我们就失去了调试应用程序的方法。

  

让我们试着去拿日志:

  

$kubectllogsflask-deployment-576496558b-hnbxt*Runningonhttp://0.0.0.0:5000/*Restartingwithreloader10.128.0.4--"GET/HTTP/1.1"200-10.128.0.3--"GET/HTTP/1.1"200-所以容器日志是可以被获取到的!

  

结论使用 Distroless 作为基础镜像是一种令人兴奋的保护容器安全的方式。由于镜像小并且仅包含应用程序和依赖项,因此它为应用程序提供了最小的攻击面。它在更大程度上提高了应用程序的安全性,所以它是保护容器安全的好方法。

  

谢谢阅读!我希望你喜欢这篇文章。

  

原文链接本文翻译自 https://betterprogramming.pub/how-to-harden-your-containers-with-distroless-docker-images-c2abd7c71fdb