写点什么

如何检查 Docker 镜像是否存在漏洞

  • 2023-04-14
    北京
  • 本文字数:9281 字

    阅读完需:约 30 分钟

如何检查 Docker 镜像是否存在漏洞

定期检查管道中的漏洞是非常重要的。执行步骤之一是对你的 Docker 镜像进行漏洞扫描。在本文中,你将学习如何执行漏洞扫描,如何修复漏洞,以及如何将其添加到你的 Jenkins 管道中。

 

在几年前的一篇博文中,描述了如何扫描 Docker 镜像的漏洞。后续的博文展示了如何将扫描添加到 Jenkins 管道中。然而,之前博文中使用的 Anchore Engine 已经不被支持了,我认为另一个解决方案是使用由 Anchore 提供的 grype

 

如今,我们必须保持最新的安全修复措施。许多安全漏洞是公开的,可以很容易地被利用。因此,为尽量减少被攻击,尽快修复安全漏洞是必须的。但如何跟上这个步伐呢?你主要关注的是业务,不希望有一个全职工作来修复安全漏洞。这就是为什么自动扫描你的应用程序和你的 Docker 镜像很重要。Grype 可以帮助扫描 Docker 镜像、检查操作系统的漏洞,也会检查特定语言的包,如 Java JAR 文件的漏洞,并会报告它们。它还可以扫描文件和目录,因此可以用来扫描你的源代码。

 

在本文中,我创建了一个包含 Spring Boot 应用程序的有漏洞的 Docker 镜像,并将安装和使用 grype,以便扫描镜像并修复漏洞。本文中使用的资源可以在 GitHub 上找到。

 

了解本文,所需的前提条件是:

 

  • 基本的 Linux 知识

  • 基本的 Docker 知识

  • 基本的 Java 和 Spring Boot 知识

 

易受攻击的应用程序

 

打开 Spring Initializr,选择 Maven 构建、Java 17、Spring Boot 2.7.6,以及 Spring Web 依赖。这不会是一个非常脆弱的应用程序,因为 Spring 已经确保你使用最新的 Spring Boot 版本。因此,将 Spring Boot 的版本改为 2.7.0。可以用以下命令构建 Spring Boot 应用程序,它将为你创建 jar 文件:

 

$ mvn clean verify
复制代码

 

你要扫描一个 Docker 镜像,因此需要创建一个 Dockerfile。你将使用一个非常基本的 Dockerfile,它只包含创建镜像所需的最低指令。如果你想创建生产就绪的 Docker 镜像,请阅读《Docker 最佳实践》(Docker Best Practices)和《Spring Boot Docker 最佳实践》(Spring Boot Docker Best Practices)。

 

FROM eclipse-temurin:17.0.1_12-jre-alpineWORKDIR /opt/appARG JAR_FILECOPY target/${JAR_FILE} app.jarENTRYPOINT ["java", "-jar", "app.jar"]
复制代码

 

在撰写本文时,Java 17 的最新 eclipse-temurin 基础镜像是 17.0.5_8 版本。同样,使用较旧的才能使其易受攻击。

 

为了构建 Docker 镜像,将使用 Spotify 的 dockerfile-maven-plugin 的分支。因此,将下面的代码片段添加到 pom 文件中。

 

<plugin>  <groupId>com.xenoamess.docker</groupId>  <artifactId>dockerfile-maven-plugin</artifactId>  <version>1.4.25</version>  <configuration>    <repository>mydeveloperplanet/mygrypeplanet</repository>    <tag>${project.version}</tag>    <buildArgs>      <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>    </buildArgs>  </configuration></plugin>
复制代码

 

使用该插件的好处是,你可以轻松地重复使用配置。创建 Docker 镜像只需一条 Maven 命令即可完成。

 

可以通过调用以下命令来构建 Docker 镜像:

 

mvn dockerfile:build
复制代码

 

现在,你已经准备好开始使用 grype 了。

 

安装

 

可以通过执行以下脚本来安装 grype:

 

$ curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
复制代码

 

通过执行以下命令验证安装:

 

$ grype versionApplication:          grypeVersion:              0.54.0Syft Version:         v0.63.0BuildDate:            2022-12-13T15:02:51ZGitCommit:            93499eec7e3ce2704755e9f51457181b06b519c5GitDescription:       v0.54.0Platform:             linux/amd64GoVersion:            go1.18.8Compiler:             gcSupported DB Schema:  5
复制代码

 

扫描镜像

 

扫描 Docker 镜像的方法是调用 grype,然后是 docker:,表示你想从 Docker 守护程序、镜像和标签中扫描一个镜像。

 

$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOTApplication:          grypeVersion:              0.54.0Syft Version:         v0.63.0 Vulnerability DB        [updated] Loaded image             Parsed image             Cataloged packages      [50 packages] Scanned image           [42 vulnerabilities]NAME              INSTALLED  FIXED-IN   TYPE          VULNERABILITY        SEVERITY busybox           1.34.1-r3  1.34.1-r5  apk           CVE-2022-28391       High      jackson-databind  2.13.3                java-archive  CVE-2022-42003       High      jackson-databind  2.13.3                java-archive  CVE-2022-42004       High      jackson-databind  2.13.3     2.13.4     java-archive  GHSA-rgv9-q543-rqg4  High      jackson-databind  2.13.3     2.13.4.1   java-archive  GHSA-jjjh-jjxp-wpff  High      java              17.0.1+12             binary        CVE-2022-21248       Low       java              17.0.1+12             binary        CVE-2022-21277       Medium    java              17.0.1+12             binary        CVE-2022-21282       Medium    java              17.0.1+12             binary        CVE-2022-21283       Medium    java              17.0.1+12             binary        CVE-2022-21291       Medium    java              17.0.1+12             binary        CVE-2022-21293       Medium    java              17.0.1+12             binary        CVE-2022-21294       Medium    java              17.0.1+12             binary        CVE-2022-21296       Medium    java              17.0.1+12             binary        CVE-2022-21299       Medium    java              17.0.1+12             binary        CVE-2022-21305       Medium    java              17.0.1+12             binary        CVE-2022-21340       Medium    java              17.0.1+12             binary        CVE-2022-21341       Medium    java              17.0.1+12             binary        CVE-2022-21360       Medium    java              17.0.1+12             binary        CVE-2022-21365       Medium    java              17.0.1+12             binary        CVE-2022-21366       Medium    libcrypto1.1      1.1.1l-r7             apk           CVE-2021-4160        Medium    libcrypto1.1      1.1.1l-r7  1.1.1n-r0  apk           CVE-2022-0778        High      libcrypto1.1      1.1.1l-r7  1.1.1q-r0  apk           CVE-2022-2097        Medium    libretls          3.3.4-r2   3.3.4-r3   apk           CVE-2022-0778        High      libssl1.1         1.1.1l-r7             apk           CVE-2021-4160        Medium    libssl1.1         1.1.1l-r7  1.1.1n-r0  apk           CVE-2022-0778        High      libssl1.1         1.1.1l-r7  1.1.1q-r0  apk           CVE-2022-2097        Medium    snakeyaml         1.30                  java-archive  GHSA-mjmj-j48q-9wg2  High      snakeyaml         1.30       1.31       java-archive  GHSA-3mc7-4q67-w48m  High      snakeyaml         1.30       1.31       java-archive  GHSA-98wm-3w3q-mw94  Medium    snakeyaml         1.30       1.31       java-archive  GHSA-c4r9-r8fh-9vj2  Medium    snakeyaml         1.30       1.31       java-archive  GHSA-hhhw-99gj-p3c3  Medium    snakeyaml         1.30       1.32       java-archive  GHSA-9w3m-gqgf-c4p9  Medium    snakeyaml         1.30       1.32       java-archive  GHSA-w37g-rhq8-7m4j  Medium    spring-core       5.3.20                java-archive  CVE-2016-1000027     Critical  ssl_client        1.34.1-r3  1.34.1-r5  apk           CVE-2022-28391       High      zlib              1.2.11-r3  1.2.12-r0  apk           CVE-2018-25032       High      zlib              1.2.11-r3  1.2.12-r2  apk           CVE-2022-37434       Critical 
复制代码

 

这个输出告诉你什么?

 

  • NAME:易受攻击的包的名称

  • INSTALLED:安装的是哪个版本

  • FIXED-IN:在哪个版本中修复了漏洞

  • TYPE:依赖项的类型,例如 JDK 的二进制等

  • VULNERABILITY:漏洞的标识符;通过此标识符,你可以获得有关 CVE 数据库中漏洞的更多信息

  • SEVERITY:不言自明,可以是可忽略、低、中、高或严重

 

当你仔细观察输出结果时,你会发现并非每个漏洞都有确认的修复方法。那么,在这种情况下,你该怎么办呢?Grype 提供了一个选项,以便只显示已经确认修复的漏洞。添加--only-fixed 标志就可以了。

 

$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed Vulnerability DB        [no update available] Loaded image             Parsed image             Cataloged packages      [50 packages] Scanned image           [42 vulnerabilities] NAME              INSTALLED  FIXED-IN   TYPE          VULNERABILITY        SEVERITY busybox           1.34.1-r3  1.34.1-r5  apk           CVE-2022-28391       High      jackson-databind  2.13.3     2.13.4     java-archive  GHSA-rgv9-q543-rqg4  High      jackson-databind  2.13.3     2.13.4.1   java-archive  GHSA-jjjh-jjxp-wpff  High      libcrypto1.1      1.1.1l-r7  1.1.1n-r0  apk           CVE-2022-0778        High      libcrypto1.1      1.1.1l-r7  1.1.1q-r0  apk           CVE-2022-2097        Medium    libretls          3.3.4-r2   3.3.4-r3   apk           CVE-2022-0778        High      libssl1.1         1.1.1l-r7  1.1.1n-r0  apk           CVE-2022-0778        High      libssl1.1         1.1.1l-r7  1.1.1q-r0  apk           CVE-2022-2097        Medium    snakeyaml         1.30       1.31       java-archive  GHSA-3mc7-4q67-w48m  High      snakeyaml         1.30       1.31       java-archive  GHSA-98wm-3w3q-mw94  Medium    snakeyaml         1.30       1.31       java-archive  GHSA-c4r9-r8fh-9vj2  Medium    snakeyaml         1.30       1.31       java-archive  GHSA-hhhw-99gj-p3c3  Medium    snakeyaml         1.30       1.32       java-archive  GHSA-9w3m-gqgf-c4p9  Medium    snakeyaml         1.30       1.32       java-archive  GHSA-w37g-rhq8-7m4j  Medium    ssl_client        1.34.1-r3  1.34.1-r5  apk           CVE-2022-28391       High      zlib              1.2.11-r3  1.2.12-r0  apk           CVE-2018-25032       High      zlib              1.2.11-r3  1.2.12-r2  apk           CVE-2022-37434       Critical 
复制代码

 

请注意,Java JDK 的漏洞已经消失,尽管 Java 17 JDK 存在一个较新的更新。然而,这可能不是一个大问题,因为其他(非 java-archive)的漏洞显示基础镜像已经过时了。

 

修复漏洞

 

在这种情况下,修复漏洞是很容易的。首先,你需要更新 Docker 基础镜像。改变 Docker 镜像中的第一行:

 

FROM eclipse-temurin:17.0.1_12-jre-alpine
复制代码

 

改成:

 

FROM eclipse-temurin:17.0.5_8-jre-alpine
复制代码

 

构建镜像并再次运行扫描:

 

$ mvn dockerfile:build...$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed Vulnerability DB        [no update available] Loaded image             Parsed image             Cataloged packages      [62 packages] Scanned image           [14 vulnerabilities]NAME              INSTALLED  FIXED-IN  TYPE          VULNERABILITY        SEVERITY jackson-databind  2.13.3     2.13.4    java-archive  GHSA-rgv9-q543-rqg4  High      jackson-databind  2.13.3     2.13.4.1  java-archive  GHSA-jjjh-jjxp-wpff  High      snakeyaml         1.30       1.31      java-archive  GHSA-3mc7-4q67-w48m  High      snakeyaml         1.30       1.31      java-archive  GHSA-98wm-3w3q-mw94  Medium    snakeyaml         1.30       1.31      java-archive  GHSA-c4r9-r8fh-9vj2  Medium    snakeyaml         1.30       1.31      java-archive  GHSA-hhhw-99gj-p3c3  Medium    snakeyaml         1.30       1.32      java-archive  GHSA-9w3m-gqgf-c4p9  Medium    snakeyaml         1.30       1.32      java-archive  GHSA-w37g-rhq8-7m4j  Medium 
复制代码

 

正如你在输出中所看到的,只有 java-archive 的漏洞仍然存在。其他漏洞已经被解决了。

 

接下来,修复 Spring Boot 依赖性漏洞,在 POM 中将 Spring Boot 的版本从 2.7.0 更改为 2.7.6。

 

<parent>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-parent</artifactId>  <version>2.7.6</version>  <relativePath/> <!-- lookup parent from repository --></parent>
复制代码

 

构建 JAR 文件,构建 Docker 镜像,然后再次运行扫描:

 

$ mvn clean verify...$ mvn dockerfile:build...$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed Vulnerability DB        [no update available] Loaded image             Parsed image             Cataloged packages      [62 packages] Scanned image           [10 vulnerabilities]NAME       INSTALLED  FIXED-IN  TYPE          VULNERABILITY        SEVERITY snakeyaml  1.30       1.31      java-archive  GHSA-3mc7-4q67-w48m  High      snakeyaml  1.30       1.31      java-archive  GHSA-98wm-3w3q-mw94  Medium    snakeyaml  1.30       1.31      java-archive  GHSA-c4r9-r8fh-9vj2  Medium    snakeyaml  1.30       1.31      java-archive  GHSA-hhhw-99gj-p3c3  Medium    snakeyaml  1.30       1.32      java-archive  GHSA-9w3m-gqgf-c4p9  Medium    snakeyaml  1.30       1.32      java-archive  GHSA-w37g-rhq8-7m4j  Medium 
复制代码

 

所以,你修复了 jackson-databind 的漏洞,但没有修复 snakeyaml 的漏洞。那么,snakeyaml 1.30 是在哪个依赖中被使用的?你可以通过 Maven 的 dependency:tree 命令来了解。为简洁起见,这里只显示部分输出:

 

$ mvnd dependency:tree... com.mydeveloperplanet:mygrypeplanet:jar:0.0.1-SNAPSHOT[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.6:compile[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.7.6:compile[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.7.6:compile[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.6:compile[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.7.6:compile[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.11:compile[INFO] |  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.11:compile[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.17.2:compile[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.36:compile[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile[INFO] |  |  \- org.yaml:snakeyaml:jar:1.30:compile...
复制代码

 

输出显示,这个依赖是 spring-boot-starter-web 依赖的一部分。那么,你如何解决这个问题呢?严格来说,Spring 必须要解决这个问题。但如果你不想等待解决方案,你可以自己解决。

 

解决方案 1: 不需要依赖项。这是最简单的解决方案,风险也低。只需在 pom 中从 spring-boot-starter-web 依赖项中排除该依赖项即可。

 

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  <exclusions>    <exclusion>      <groupId>org.yaml</groupId>      <artifactId>snakeyaml</artifactId>    </exclusion>  </exclusions></dependency>
复制代码

 

构建 JAR 文件,构建 Docker 镜像,然后再次运行扫描:

 

$ mvn clean verify...$ mvn dockerfile:build...$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed Vulnerability DB        [no update available] Loaded image             Parsed image             Cataloged packages      [61 packages] Scanned image           [3 vulnerabilities]No vulnerabilities found
复制代码

 

再也没发现任何漏洞了。

 

解决方案 2:你确实需要这个依赖关系。你可以通过 pom 中的 dependencyManagement 来替换这个过渡性依赖。这就有点麻烦了,因为更新后的横向依赖没有经过 spring-boot-starter-web 依赖的测试。你要不要这样做,需要权衡一下。在 pom 中添加以下部分。

 

<dependencyManagement>  <dependencies>    <dependency>      <groupId>org.yaml</groupId>      <artifactId>snakeyaml</artifactId>      <version>1.32</version>    </dependency>  </dependencies></dependencyManagement>
复制代码

 

构建 JAR 文件,构建 Docker 镜像,然后再次运行扫描:

 

$ mvn clean verify...$ mvn dockerfile:build...$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed Vulnerability DB        [no update available] Loaded image             Parsed image             Cataloged packages      [62 packages] Scanned image           [3 vulnerabilities]No vulnerabilities found
复制代码

 

同样,再也没发现漏洞了。

 

解决方案 3:这是在你不想做任何事情或是否有误报通知时的解决方案。创建一个 .grype.yaml 文件,在其中排除高严重性的漏洞,然后用 --config 标志执行扫描,后面是包含排除项的 .grype.yaml 文件。

 

.grype.yaml 文件如下所示:

 

ignore:  - vulnerability: GHSA-3mc7-4q67-w48m
复制代码

 

再次运行扫描:

 

$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed Vulnerability DB        [no update available] Loaded image             Parsed image             Cataloged packages      [62 packages] Scanned image           [10 vulnerabilities]NAME       INSTALLED  FIXED-IN  TYPE          VULNERABILITY        SEVERITY snakeyaml  1.30       1.31      java-archive  GHSA-98wm-3w3q-mw94  Medium    snakeyaml  1.30       1.31      java-archive  GHSA-c4r9-r8fh-9vj2  Medium    snakeyaml  1.30       1.31      java-archive  GHSA-hhhw-99gj-p3c3  Medium    snakeyaml  1.30       1.32      java-archive  GHSA-9w3m-gqgf-c4p9  Medium    snakeyaml  1.30       1.32      java-archive  GHSA-w37g-rhq8-7m4j  Medium 
复制代码

 

High 漏洞就不再显示了。

 

持续集成

 

现在你知道如何手动扫描你的 Docker 镜像了。然而,你可能想把扫描镜像作为持续集成管道的一部分。在本节中,将提供一个使用 Jenkins 作为 CI 平台时的解决方案。

 

要回答的第一个问题是,当发现漏洞时,你将如何得到通知。到现在为止,你只能通过查看标准输出来注意到这些漏洞。这不是一个 CI 管道的解决方案。你想得到通知,这可以通过失败的构建来实现。Grype 有 --fail-on <severity>标志来达到这个目的。你可能不想在发现严重程度为 negligible 的漏洞时让管道失败。

 

让我们看看当你手动执行这个时,会发生什么。首先,在 Spring Boot 应用程序和 Docker 镜像中再次引入漏洞。

 

构建 JAR 文件,构建 Docker 镜像,用标志 --fail-on 运行扫描。

 

$ mvn clean verify...$ mvn dockerfile:build...$ grype docker:mydeveloperplanet/mygrypeplanet:0.0.1-SNAPSHOT --only-fixed --fail-on high...1 error occurred:        * discovered vulnerabilities at or above the severity threshold
复制代码

 

这里没有显示所有的输出,只显示了重要的部分。而且,正如你所看到的,在输出的最后,显示了一条信息,表明扫描产生了一个错误。这将导致你的 Jenkins 管道失败,因此,开发人员会被通知出了问题。

 

为了将其添加到您的 Jenkins 管道中,有几个选项。这里选择创建 Docker 镜像,并从 Maven 中执行 grype Docker 扫描。grype 没有单独的 Maven 插件,但你可以使用 exec-maven-plugin 来实现这一目的。在 POM 的 build-plugins 部分添加以下内容。

 

<build>  <plugins>    <plugin>      <groupId>org.codehaus.mojo</groupId>      <artifactId>exec-maven-plugin</artifactId>      <version>3.1.0</version>      <configuration>        <executable>grype</executable>          <arguments>            <argument>docker:mydeveloperplanet/mygrypeplanet:${project.version}</argument>            <argument>--scope</argument>            <argument>all-layers</argument>            <argument>--fail-on</argument>            <argument>high</argument>            <argument>--only-fixed</argument>            <argument>-q</argument>          </arguments>      </configuration>    </plugin>  </plugins></build>
复制代码

 

这里添加了两个额外的标志:

 

  • --scope all-layers。这将扫描 Docker 镜像中涉及的所有层。

  • --q:这将使用安静的日志,只显示漏洞和可能出现的故障。

 

你可以用下面的命令来调用它:

 

$ mvnd exec:exec
复制代码

 

你可以把它添加到你的 Jenkinsfile 中的 withMaven 包装器中:

 

withMaven() {  sh 'mvn dockerfile:build dockerfile:push exec:exec'}
复制代码

结论

 

在本文中,你了解了如何通过 grype 来扫描你的 Docker 镜像。Grype 有一些有趣的、用户友好的特性,允许你有效地将它们添加到你的 Jenkins 管道中,另外安装 grype 也很容易。与 Anchor Engine 相比,Grype 绝对是一个很大的改进。

 

作者简介:

 

Gunter Rotsaert,系统工程师,居住在荷兰的比利时人。

 

原文链接:

https://mydeveloperplanet.com/2023/01/18/how-to-check-docker-images-for-vulnerabilities/

2023-04-14 14:223747

评论

发布
暂无评论
发现更多内容

终于有人把 "高可用" 说清楚了

架构精进之路

3月日更

【20万大奖】参加APICloud3.0案例与AVM组件大赛,赢现金大奖

YonBuilder低代码开发平台

开发者 大前端 APP开发 APICloud

价值感知:如何评价企业IT项目的价值?

boshi

价值传递 七日更 项目经验

项目截图

赝品

还不懂云数据库Redis是什么?快上车,一张图带你了解!

浪潮云

云数据库

已经整整10年了,经济学人分析日本福岛核泄漏事故带来的沉重影响

wbliu85

一名优秀的女程序员是如何炼成的?我们跟爱奇艺的五位工程师姐姐聊了聊

爱奇艺技术产品团队

Python 变量类型

依旧廖凯

28天写作 3月日更

Wireshark数据包分析学习笔记Day7

穿过生命散发芬芳

Wireshark 数据包分析 3月日更

震荡的比特币:区块链的“照妖镜”

CECBC

数字货币

Nacos配置安全最佳实践

Robert Lu

nacos 配置中心

如何带团队?

石云升

程序员 28天写作 职场经验 管理经验 3月日更

Python 基础语法

依旧廖凯

28天写作 3月日更

【动态规划/路径问题】强化 DP 分析方法练习题 ...

宫水三叶的刷题日记

面试 LeetCode 数据结构与算法

数字货币持币生息钱包系统开发搭建

薇電13242772558

区块链 数字货币

HashData携手中国移动 共筑通信技术数字化之路

酷克数据HashData

数据库 解决方案

JAVA中的I/O模型-多路复用

Java 架构 计算机

翻译:《实用的Python编程》04_04_Defining_exceptions

codists

Python

【笔记】第七周 第1课

Geek_娴子

2021最新快手面经主动分享:Java面试神技/技术知识集合(10个专题详细介绍)

比伯

Java 编程 架构 面试 程序人生

ARTS - Week 6

Khirye

Java LeetCode arts

如何破解区块链人才的结构性问题?

CECBC

区块链

为什么选择python

张鹤羽

28天写作 3月日更

LeetCode题解:125. 验证回文串,双指针,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

华为不养猪,小米没造车,“巨头错觉”是怎么来的?

脑极体

引爆40亿播放的抖音春节道具,背后是怎样的技术?

字节跳动技术团队

关于写东西的一点思考

道伟

28天写作

Hello World!!!

小太阳

FutureTask源码解析

程序员星星toC

多线程 Future future设计模式

Yarn日志聚合优化—摆脱HDFS依赖

笨小康

大数据 YARN

深读golang中map后思考和借鉴

ninetyhe

源码 Go 语言

如何检查 Docker 镜像是否存在漏洞_云原生_Gunter Rotsaert_InfoQ精选文章