首页 文章 精选 留言 我的

精选列表

搜索[搭建],共10000篇文章
优秀的个人博客,低调大师

手写一个类SpringBoot的HTTP框架:几十行代码基于Netty搭建一个 HTTP Server

本文已经收录进 : https://github.com/Snailclimb/netty-practical-tutorial (Netty 从入门到实战:手写 HTTP Server+RPC 框架)。 相关项目:https://github.com/Snailclimb/jsoncat (仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架) 目前正在写的一个叫做 jsoncat 的轻量级 HTTP 框架内置的 HTTP 服务器是我自己基于 Netty 写的,所有的核心代码加起来不过就几十行。这得益于 Netty 提供的各种开箱即用的组件,为我们节省了太多事情。 这篇文章我会手把手带着小伙伴们实现一个简易的 HTTP Server。 如果文章有任何需要改善和完善的地方,欢迎在评论区指出,共同进步! 开始之前为了避免有小伙伴不了解 Netty ,还是先来简单介绍它! 什么是 Netty? 简单用 3 点来概括一下 Netty 吧! Netty 是一个基于 NIO 的 client-server(客户端服务器)框架,使用它可以快速简单地开发网络应用程序。 Netty 极大地简化并优化了 TCP 和 UDP 套接字服务器等网络编程,并且性能以及安全性等很多方面都要更好。 Netty 支持多种协议 如 FTP,SMTP,HTTP 以及各种二进制和基于文本的传统协议。本文所要写的 HTTP Server 就得益于 Netty 对 HTTP 协议(超文本传输协议)的支持。 Netty 应用场景有哪些? 凭借自己的了解,简单说一下吧!理论上来说,NIO 可以做的事情 ,使用 Netty 都可以做并且更好。 不过,我们还是首先要明确的是 Netty 主要用来做网络通信 。 实现框架的网络通信模块 : Netty 几乎满足任何场景的网络通信需求,因此,框架的网络通信模块可以基于 Netty 来做。拿 RPC 框架来说! 我们在分布式系统中,不同服务节点之间经常需要相互调用,这个时候就需要 RPC 框架了。不同服务指点的通信是如何做的呢?那就可以使用 Netty 来做了!比如我调用另外一个节点的方法的话,至少是要让对方知道我调用的是哪个类中的哪个方法以及相关参数吧! 实现一个自己的 HTTP 服务器 :通过 Netty ,我们可以很方便地使用少量代码实现一个简单的 HTTP 服务器。Netty 自带了编解码器和消息聚合器,为我们开发节省了很多事! 实现一个即时通讯系统 : 使用 Netty 我们可以实现一个可以聊天类似微信的即时通讯系统,这方面的开源项目还蛮多的,可以自行去 Github 找一找。 实现消息推送系统 :市面上有很多消息推送系统都是基于 Netty 来做的。 ...... 那些开源项目用到了 Netty? 我们平常经常接触的 Dubbo、RocketMQ、Elasticsearch、gRPC 、Spring Cloud Gateway 等等都用到了 Netty。 可以说大量的开源项目都用到了 Netty,所以掌握 Netty 有助于你更好的使用这些开源项目并且让你有能力对其进行二次开发。 实际上还有很多很多优秀的项目用到了 Netty,Netty 官方也做了统计,统计结果在这里:https://netty.io/wiki/related-projects.html 。 实现 HTTP Server 必知的前置知识 既然,我们要实现 HTTP Server 那必然先要回顾一下 HTTP 协议相关的基础知识。 HTTP 协议 超文本传输协议(HTTP,HyperText Transfer Protocol)主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。 当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的,整个过程如下图所示。 <p style="text-align:right;font-size:12px">https://www.seobility.net/en/wiki/HTTP_headers</p> HTTP 协议是基于 TCP 协议的,因此,发送 HTTP 请求之前首先要建立 TCP 连接也就是要经历 3 次握手。目前使用的 HTTP 协议大部分都是 1.1。在 1.1 的协议里面,默认是开启了 Keep-Alive 的,这样的话建立的连接就可以在多次请求中被复用了。 了解了 HTTP 协议之后,我们再来看一下 HTTP 报文的内容,这部分内容很重要!(参考图片来自:https://iamgopikrishna.wordpress.com/2014/06/13/4/) HTTP 请求报文: HTTP 响应报文: 我们的 HTTP 服务器会在后台解析 HTTP 请求报文内容,然后根据报文内容进行处理之后返回 HTTP 响应报文给客户端。 Netty 编解码器 如果我们要通过 Netty 处理 HTTP 请求,需要先进行编解码。所谓编解码说白了就是在 Netty 传输数据所用的 ByteBuf 和 Netty 中针对 HTTP 请求和响应所提供的对象比如 HttpRequest 和 HttpContent之间互相转换。 Netty 自带了 4 个常用的编解码器: HttpRequestEncoder (HTTP 请求编码器):将 HttpRequest 和 HttpContent 编码为 ByteBuf 。 HttpRequestDecoder (HTTP 请求解码器):将 ByteBuf 解码为 HttpRequest 和 HttpContent HttpResponsetEncoder (HTTP 响应编码器):将 HttpResponse 和 HttpContent 编码为 ByteBuf 。 HttpResponseDecoder(HTTP 响应解码器):将 ByteBuf 解码为 HttpResponst 和 HttpContent 网络通信最终都是通过字节流进行传输的。 ByteBuf 是 Netty 提供的一个字节容器,其内部是一个字节数组。 当我们通过 Netty 传输数据的时候,就是通过 ByteBuf 进行的。 HTTP Server 端用于接收 HTTP Request,然后发送 HTTP Response。因此我们只需要 HttpRequestDecoder 和 HttpResponseEncoder 即可。 我手绘了一张图,这样看着应该更容易理解了。 Netty 对 HTTP 消息的抽象 为了能够表示 HTTP 中的各种消息,Netty 设计了抽象了一套完整的 HTTP 消息结构图,核心继承关系如下图所示。 HttpObject : 整个 HTTP 消息体系结构的最上层接口。HttpObject 接口下又有 HttpMessage 和HttpContent两大核心接口。 HttpMessage: 定义 HTTP 消息,为HttpRequest和HttpResponse提供通用属性 HttpRequest : HttpRequest对应 HTTP request。通过 HttpRequest 我们可以访问查询参数(Query Parameters)和 Cookie。和 Servlet API 不同的是,查询参数是通过QueryStringEncoder和QueryStringDecoder来构造和解析查询查询参数。 HttpResponse : HttpResponse 对应 HTTP response。和HttpMessage相比,HttpResponse 增加了 status(相应状态码) 属性及其对应的方法。 HttpContent : 分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种数据传输机制(HTTP/1.1 才有),允许 HTTP 由应用服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多“块”(数据量比较大的情况)。我们可以把 HttpContent 看作是这一块一块的数据。 LastHttpContent : 标识 HTTP 请求结束,同时包含 HttpHeaders 对象。 FullHttpRequest 和 FullHttpResponse : HttpMessage 和 HttpContent 聚合后得到的对象。 HTTP 消息聚合器 HttpObjectAggregator 是 Netty 提供的 HTTP 消息聚合器,通过它可以把 HttpMessage 和 HttpContent 聚合成一个 FullHttpRequest 或者 FullHttpResponse(取决于是处理请求还是响应),方便我们使用。 另外,消息体比较大的话,可能还会分成好几个消息体来处理,HttpObjectAggregator 可以将这些消息聚合成一个完整的,方便我们处理。 使用方法:将 HttpObjectAggregator 添加到 ChannelPipeline 中,如果是用于处理 HTTP Request 就将其放在 HttpResponseEncoder 之后,反之,如果用于处理 HTTP Response 就将其放在 HttpResponseDecoder 之后。 因为,HTTP Server 端用于接收 HTTP Request,对应的使用方式如下。 ChannelPipeline p = ...; p.addLast("decoder", new HttpRequestDecoder()) .addLast("encoder", new HttpResponseEncoder()) .addLast("aggregator", new HttpObjectAggregator(512 * 1024)) .addLast("handler", new HttpServerHandler()); 基于 Netty 实现一个 HTTP Server 通过 Netty,我们可以很方便地使用少量代码构建一个可以正确处理 GET 请求和 POST 请求的轻量级 HTTP Server。 源代码地址:https://github.com/Snailclimb/netty-practical-tutorial/tree/master/example/http-server 。 添加所需依赖到 pom.xml 第一步,我们需要将实现 HTTP Server 所必需的第三方依赖的坐标添加到 pom.xml中。 <!--netty--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.42.Final</version> </dependency> <!-- log --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> <scope>provided</scope> </dependency> <!--commons-codec--> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version> </dependency> 创建服务端 @Slf4j public class HttpServer { private static final int PORT = 8080; public void start() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // TCP默认开启了 Nagle 算法,该算法的作用是尽可能的发送大数据快,减少网络传输。TCP_NODELAY 参数的作用就是控制是否启用 Nagle 算法。 .childOption(ChannelOption.TCP_NODELAY, true) // 是否开启 TCP 底层心跳机制 .childOption(ChannelOption.SO_KEEPALIVE, true) //表示系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁,服务器处理创建新连接较慢,可以适当调大这个参数 .option(ChannelOption.SO_BACKLOG, 128) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast("decoder", new HttpRequestDecoder()) .addLast("encoder", new HttpResponseEncoder()) .addLast("aggregator", new HttpObjectAggregator(512 * 1024)) .addLast("handler", new HttpServerHandler()); } }); Channel ch = b.bind(PORT).sync().channel(); log.info("Netty Http Server started on port {}.", PORT); ch.closeFuture().sync(); } catch (InterruptedException e) { log.error("occur exception when start server:", e); } finally { log.error("shutdown bossGroup and workerGroup"); bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } 简单解析一下服务端的创建过程具体是怎样的! 1.创建了两个 NioEventLoopGroup 对象实例:bossGroup 和 workerGroup。 bossGroup : 用于处理客户端的 TCP 连接请求。 workerGroup : 负责每一条连接的具体读写数据的处理逻辑,真正负责 I/O 读写操作,交由对应的 Handler 处理。 举个例子:我们把公司的老板当做 bossGroup,员工当做 workerGroup,bossGroup 在外面接完活之后,扔给 workerGroup 去处理。一般情况下我们会指定 bossGroup 的 线程数为 1(并发连接量不大的时候) ,workGroup 的线程数量为 CPU 核心数 *2 。另外,根据源码来看,使用 NioEventLoopGroup 类的无参构造函数设置线程数量的默认值就是 CPU 核心数 *2 。 2.创建一个服务端启动引导/辅助类: ServerBootstrap,这个类将引导我们进行服务端的启动工作。 3.通过 .group() 方法给引导类 ServerBootstrap 配置两大线程组,确定了线程模型。 4.通过channel()方法给引导类 ServerBootstrap指定了 IO 模型为NIO NioServerSocketChannel :指定服务端的 IO 模型为 NIO,与 BIO 编程模型中的ServerSocket对应 NioSocketChannel : 指定客户端的 IO 模型为 NIO, 与 BIO 编程模型中的Socket对应 5.通过 .childHandler()给引导类创建一个ChannelInitializer ,然后指定了服务端消息的业务处理逻辑也就是自定义的ChannelHandler 对象 6.调用 ServerBootstrap 类的 bind()方法绑定端口 。 //bind()是异步的,但是,你可以通过 sync()方法将其变为同步。 ChannelFuture f = b.bind(port).sync(); 自定义服务端 ChannelHandler 处理 HTTP 请求 我们继承SimpleChannelInboundHandler ,并重写下面 3 个方法: channelRead() :服务端接收并处理客户端发送的 HTTP 请求调用的方法。 exceptionCaught() :处理客户端发送的 HTTP 请求发生异常的时候被调用。 channelReadComplete() : 服务端消费完客户端发送的 HTTP 请求之后调用的方法。 另外,客户端 HTTP 请求参数类型为 FullHttpRequest。我们可以把 FullHttpRequest对象看作是 HTTP 请求报文的 Java 对象的表现形式。 @Slf4j public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> { private static final String FAVICON_ICO = "/favicon.ico"; private static final AsciiString CONNECTION = AsciiString.cached("Connection"); private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive"); private static final AsciiString CONTENT_TYPE = AsciiString.cached("Content-Type"); private static final AsciiString CONTENT_LENGTH = AsciiString.cached("Content-Length"); @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) { log.info("Handle http request:{}", fullHttpRequest); String uri = fullHttpRequest.uri(); if (uri.equals(FAVICON_ICO)) { return; } RequestHandler requestHandler = RequestHandlerFactory.create(fullHttpRequest.method()); Object result; FullHttpResponse response; try { result = requestHandler.handle(fullHttpRequest); String responseHtml = "<html><body>" + result + "</body></html>"; byte[] responseBytes = responseHtml.getBytes(StandardCharsets.UTF_8); response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(responseBytes)); response.headers().set(CONTENT_TYPE, "text/html; charset=utf-8"); response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes()); } catch (IllegalArgumentException e) { e.printStackTrace(); String responseHtml = "<html><body>" + e.toString() + "</body></html>"; byte[] responseBytes = responseHtml.getBytes(StandardCharsets.UTF_8); response = new DefaultFullHttpResponse(HTTP_1_1, INTERNAL_SERVER_ERROR, Unpooled.wrappedBuffer(responseBytes)); response.headers().set(CONTENT_TYPE, "text/html; charset=utf-8"); } boolean keepAlive = HttpUtil.isKeepAlive(fullHttpRequest); if (!keepAlive) { ctx.write(response).addListener(ChannelFutureListener.CLOSE); } else { response.headers().set(CONNECTION, KEEP_ALIVE); ctx.write(response); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } } 我们返回给客户端的消息体是 FullHttpResponse 对象。通过 FullHttpResponse 对象,我们可以设置 HTTP 响应报文的 HTTP 协议版本、响应的具体内容 等内容。 我们可以把 FullHttpResponse 对象看作是 HTTP 响应报文的 Java 对象的表现形式。 FullHttpResponse response; String responseHtml = "<html><body>" + result + "</body></html>"; byte[] responseBytes = responseHtml.getBytes(StandardCharsets.UTF_8); // 初始化 FullHttpResponse ,并设置 HTTP 协议 、响应状态码、响应的具体内容 response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(responseBytes)); 我们通过 FullHttpResponse的headers()方法获取到 HttpHeaders,这里的 HttpHeaders 对应于 HTTP 响应报文的头部。通过 HttpHeaders对象,我们就可以对 HTTP 响应报文的头部的内容比如 Content-Typ 进行设置。 response.headers().set(CONTENT_TYPE, "text/html; charset=utf-8"); response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes()); 本案例中,为了掩饰我们设置的 Content-Type 为 text/html ,也就是返回 html 格式的数据给客户端。 常见的 Content-Type Content-Type 解释 text/html html 格式 text/plain 纯文本格式 text/css css 格式 text/javascript js 格式 application/json json 格式(前后端分离项目常用) image/gif gif 图片格式 image/jpeg jpg 图片格式 image/png png 图片格式 请求的具体处理逻辑实现 因为有这里有 POST 请求和 GET 请求。因此我们需要首先定义一个处理 HTTP Request 的接口。 public interface RequestHandler { Object handle(FullHttpRequest fullHttpRequest); } HTTP Method 不只是有 GET 和 POST,其他常见的还有 PUT、DELETE、PATCH。只是本案例中实现的 HTTP Server 只考虑了 GET 和 POST。 GET :请求从服务器获取特定资源。举个例子:GET /classes(获取所有班级) POST :在服务器上创建一个新的资源。举个例子:POST /classes(创建班级) PUT :更新服务器上的资源(客户端提供更新后的整个资源)。举个例子:PUT /classes/12(更新编号为 12 的班级) DELETE :从服务器删除特定的资源。举个例子:DELETE /classes/12(删除编号为 12 的班级) PATCH :更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新),使用的比较少,这里就不举例子了。 GET 请求的处理 @Slf4j public class GetRequestHandler implements RequestHandler { @Override public Object handle(FullHttpRequest fullHttpRequest) { String requestUri = fullHttpRequest.uri(); Map<String, String> queryParameterMappings = this.getQueryParams(requestUri); return queryParameterMappings.toString(); } private Map<String, String> getQueryParams(String uri) { QueryStringDecoder queryDecoder = new QueryStringDecoder(uri, Charsets.toCharset(CharEncoding.UTF_8)); Map<String, List<String>> parameters = queryDecoder.parameters(); Map<String, String> queryParams = new HashMap<>(); for (Map.Entry<String, List<String>> attr : parameters.entrySet()) { for (String attrVal : attr.getValue()) { queryParams.put(attr.getKey(), attrVal); } } return queryParams; } } 我这里只是简单得把 URI 的查询参数的对应关系直接返回给客户端了。 实际上,获得了 URI 的查询参数的对应关系,再结合反射和注解相关的知识,我们很容易实现类似于 Spring Boot 的 @RequestParam 注解了。 建议想要学习的小伙伴,可以自己独立实现一下。不知道如何实现的话,你可以参考我开源的轻量级 HTTP 框架jsoncat (仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架)。 POST 请求的处理 @Slf4j public class PostRequestHandler implements RequestHandler { @Override public Object handle(FullHttpRequest fullHttpRequest) { String requestUri = fullHttpRequest.uri(); log.info("request uri :[{}]", requestUri); String contentType = this.getContentType(fullHttpRequest.headers()); if (contentType.equals("application/json")) { return fullHttpRequest.content().toString(Charsets.toCharset(CharEncoding.UTF_8)); } else { throw new IllegalArgumentException("only receive application/json type data"); } } private String getContentType(HttpHeaders headers) { String typeStr = headers.get("Content-Type"); String[] list = typeStr.split(";"); return list[0]; } } 对于 POST 请求的处理,我们这里只接受处理 Content-Type 为 application/json 的数据,如果 POST 请求传过来的不是 application/json 类型的数据,我们就直接抛出异常。 实际上,我们获得了客户端传来的 json 格式的数据之后,再结合反射和注解相关的知识,我们很容易实现类似于 Spring Boot 的 @RequestBody 注解了。 建议想要学习的小伙伴,可以自己独立实现一下。不知道如何实现的话,你可以参考我开源的轻量级 HTTP 框架jsoncat (仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架)。 请求处理工厂类 public class RequestHandlerFactory { public static final Map<HttpMethod, RequestHandler> REQUEST_HANDLERS = new HashMap<>(); static { REQUEST_HANDLERS.put(HttpMethod.GET, new GetRequestHandler()); REQUEST_HANDLERS.put(HttpMethod.POST, new PostRequestHandler()); } public static RequestHandler create(HttpMethod httpMethod) { return REQUEST_HANDLERS.get(httpMethod); } } 我这里用到了工厂模式,当我们额外处理新的 HTTP Method 方法的时候,直接实现 RequestHandler 接口,然后将实现类添加到 RequestHandlerFactory 即可。 启动类 public class HttpServerApplication { public static void main(String[] args) { HttpServer httpServer = new HttpServer(); httpServer.start(); } } 效果 运行 HttpServerApplication 的main()方法,控制台打印出: [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9bb1012a] REGISTERED [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9bb1012a] BIND: 0.0.0.0/0.0.0.0:8080 [nioEventLoopGroup-2-1] INFO io.netty.handler.logging.LoggingHandler - [id: 0x9bb1012a, L:/0:0:0:0:0:0:0:0:8080] ACTIVE [main] INFO server.HttpServer - Netty Http Server started on port 8080. GET 请求 POST 请求 参考 Netty 学习笔记-http objects 我的开源项目推荐 JavaGuide :「Java学习+面试指南」一份涵盖大部分Java程序员所需要掌握的核心知识。准备 Java 面试,首选 JavaGuide! guide-rpc-framework :A custom RPC framework implemented by Netty+Kyro+Zookeeper.(一款基于 Netty+Kyro+Zookeeper 实现的自定义 RPC 框架-附详细实现过程和相关教程) jsoncat :仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架 programmer-advancement :程序员应该有的一些好习惯+面试必知事项! springboot-guide :Not only Spring Boot but also important knowledge of Spring(不只是SpringBoot还有Spring重要知识点) awesome-java :Collection of awesome Java project on Github(Github 上非常棒的 Java 开源项目集合). 我是 Guide 哥,一 Java 后端开发,会一点前端,自由的少年。我们下期再见!微信搜“JavaGuide”回复“面试突击”领取我整理的 4 本原创PDF

优秀的个人博客,低调大师

教大家用云服务器搭建自己的云盘 可离线下载 可在线看片

随着迅雷远程离线下载的关闭,某度网盘不开会员又没速度,下载一些冷门资源的时候,看着几kb甚至几B的情况是不是很绝望? 别担心,小编教大家如何自建网盘,摆脱限速和无法远程离线下载的限制。 介绍 教程里使用的是容器化的 Aria2 - 一款轻量级的多用户下载工具,可以下载HTTP、FTP、磁力、BT等。不过Aria2是命令行软件,我们还需要通过 AriaNG 来实现网页版的图形化控制就像一个网页版迅雷了。再通过 FileRun 实现文件的下载、预览和共享,让我们的离线下载更加多用途化。 我们需要用到 Putty,推荐新手由 Larry Li维护并开源的中文版,下载地址:https://github.com/larryli/PuTTY/releases 还需要一台服务器,我推荐用阿里云服务器ECS,安全、稳定:https://promotion.aliyun.com/ntms/act/enterprise-discount.html 安装 Docker 我们购买ECS首先选择 Ubuntu 16.04 64位的系统,然后安装阿里云的 Docker 加速脚本,会自动安装阿里云提供的 Docker 安装脚本以及加速功能。 1 curl -sSL http: //acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh - 安装 MySQL 1 docker run --name=db -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=filerun -e MYSQL_USER=filerun -e MYSQL_PASSWORD=filerun -dP mysql 安装离线下载服务: 会自动安装 Aria2、AriaNG和Filerun非常的省心: 1 docker run --name=pan --link=db -ti -p 8081:80 -p 6800:6800 jaegerdocker/pan 体验一波FileRun 打开 http://IP:8081,出现登录窗口就OK了,用户名和密码都是:superuser 然后再修改一下默认密码,之后就可以看到一个类似云盘的界面了,我们可以自行上传我们的文件,在线预览 视频、PDF、图片、Office 文档也是小意思。这样我们就可以将我们的下载或者上传的资源很方便的分享给我们的朋友了,当然还可以开一个新的账号给小伙伴们使用。榨干你云服务器的所有价值,~ 体验一波离线下载 重头戏来了,我们的离线下载,进入 http://ip:8081/dweb 完全一个网页版迅雷嘛,支持下载BT、HTTP、FTP、磁力、电驴等等,对于冷门资源睡觉前添加下载,一觉醒来就可以慢速下载回来了~~如果是一些中国网络下载慢的资源,可能一瞬间就可以下载完毕,我们就可以全速下载回来了! 最重要的是可以看小姐姐了(前提是你的云服务器带宽要足够大,才能流畅在线观看)

优秀的个人博客,低调大师

Linux日记本_04:阿里云ECS服务器(CentOS7)端口设置以及 MySQL数据库搭建

阿里云 阿里云控制台设置端口开放 控制台 购买的阿里云服务器默认开放的 22 和 3389 以及-1,我们需要配置一些常用的端口开放。比如说MySQL 数据库 3306 ,NoSQL数据库Redis 6379 Oracle数据库1521 Nginx 的默认80 以及https的443.....等依次类推,需要先设置好了这一步然后再去启用Linux(CentOS7)中的防火墙。 在Linux的发行版本:CentOS7中,iptables 时无法使用的,去/etc/sysconfig/...下面去找的话也是找不到那个熟悉的防火墙配置文件了。 我们需要使用firewalld,如果你想更加仔细的了解firewalld,请查阅我之前写过的一篇文章 传送门:https://www.jianshu.com/p/cbddef3cab47 查看当前Linux操作系统发行版本:cat /etc/redhat-release 发行版本信息 开启3306端口:firewall-cmd --zone=public --remove-port=3306/tcp --permanent 准备工作做完了我们就可以开始啦! 开始安装MySQL 1.保证服务器时最新状态以及删除之前可能安装过的mysql yum -y update reboot --- 重启 ---检查是否已经安装,如果已经安装先删除以前版本,以免安装不成功 php -v 或者 rpm -qa | gerp mysql 或者 yum list installed | grep mysql 表示没有安过mysql command not found 2.在线下载MySQL压缩包并安装 下载:rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm 或者 rpm -ivh http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm 安装:yum install -y mysql-server 或者 yum install mysql-community-server 安装过程 安装过程 安装成功 安装成功 3.设置开机启动MySQLsystemctl enable mysqld.service 4.检查是否已经安装了开机自动启动systemctl list-unit-files | grep mysqld 5.设置开启服务systemctl start mysqld.service 6.查看MySql默认密码grep 'temporary password' /var/log/mysqld.log 7.粘贴临时密码,登陆MySql,输入用户名和密码mysql -uroot -p 8.修改账号密码,需要复杂一些,不然会报错提示你安全性不够mysql>SET PASSWORD = PASSWORD('********'); 9.开启远程登录,授权root远程登录mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '********' WITH GRANT OPTION; 10.命令立即执行生效mysql>flush privileges; 测试连接 Connection successful

优秀的个人博客,低调大师

「镁客·请讲」云脑科技张本宇:搭建一座桥梁,弥补行业与人工智能之间的断层

在张本宇看来,AI是一种很好的技术,而各行各业的发展也提供了很多的需求,但是这两者之间并不是简单利用AI工具就能解决的。 如同此前的互联网+,随着语音识别、计算机视觉等人工智能技术的出现,当技术渐趋成熟,如何实现商业化落地就成为了一个难题。而对于企业来讲,随着智能化时代的到来,如何运用这些技术改变自己、避免被时代的潮流所淹没也是一个问题。 “打造行业与人工智能之间的桥梁”,在云脑科技的首页,镁客君第一眼看见的就是这句话。细细想来,我们不禁想问,桥梁出现之前的断层是什么?这座桥梁又该如何打造?带着这样的问题,镁客君采访了云脑科技的创始人兼CEO张本宇。 创业念头早已存在,只是还缺一个时机 对于创业这回事,其实张本宇早就有了这方面的想法,无奈的是,他缺少一个时机。在已经深耕人工智能领域十多年的他眼中,彼时的AI技术相对来说并没有特别的成熟。 就在2015年,张本宇等到了那个时机,并毅然决然的从谷歌离职,继而创立了现在的云脑科技。 那这个时机是什么?张本宇说出了三点: 首先,深度学习已经具备向互联网之外渗透的能力; 其次,国内大数据基础设施的建立已经有了几年,许多行业已经是属于有数据的阶段,同时大数据也有了一定的计算基础平台; 最后,AI算法本身已经发展到了一定的阶段。 目前,云脑科技分别在硅谷和国内都设有站点,并均建立了研发中心。不同的是,在偏重上,硅谷站点更偏向于算法的研发,而国内更倾向于对技术、产品商业化的推进。 人工智能与行业之间有断层,他们想做的就是搭座桥梁 前面我们也提到,云脑科技的官网上就醒目地写着一句“打造行业与人工智能之间的桥梁”,让我们一眼就能看到其正在做的事情与自身的定位。 “AI是一种很好的技术,而各行各业的发展也提供了很多的需求,但是这两者之间并不是简单利用AI工具就能解决的。”张本宇表示,在其看来,要想将AI用好,我们需要多方面的专业技术。 相应的,有着迫切需求的传统公司会尝试用AI去解决,但往往在这个过程中会遇到一些问题。比如数据,数据够不够、需要什么样的数据、多来源数据又该怎么结合……这些都是在运用AI之前所需要考虑进去的问题。 另外,面对日新月异的算法,什么样的算法,或者说哪些算法结合才能解决这些问题?AI系统所输出的结果或数据又该如何才能与应用场景真正结合?这些问题也同样需要斟酌一下。 当前,基于对行业信息化程度、AI需求、合作伙伴的考量,云脑科技目前主要在四个领域提供服务,分别是金融、能源、人力资源和通信。 在服务上,云脑科技更多的是和不同行业的合作伙伴一起,共同打造——行业中间件AI(X)。张本宇介绍道:“AI中间件就是我们的核心AI技术平台。基于不同行业特定的知识和需求,继而形成一个解决该行业特定问题、让该行业人群能够迅速使用的服务产品。” 简单来讲,就是“我提供算法、你提供数据和需求”的模式,通过针对性的培训,让算法提供针对性的服务。 与此同时,除了为行业提供AI服务,针对当前AI产业人才紧缺的痛点,云脑科技还设立了一个“中美AI青年计划”项目。这一项目主要分为两部分,一部分是云脑科技硅谷研究院的线下参与活动,参与项目的学生在此期间会接受美国顶尖算法工程师的指导,另一部分叫做“云脑机器学习实战训练营”,即线上视频教学授课,而中美导师会带着学员做项目,为其答疑解惑。 只做技术是死路一条?那可不一定 在接下来的规划中,依据“一横一纵”的战略制定,云脑科技将打造一个足够强大的AI平台,继续在不同的行业中进行深挖。总体来看,云脑科技是一个以技术为主导的AI创企,那么,问题来了。 此前,有人说“只做技术的公司只有死路一条,因为这些技术在未来终将被BAT免费开放”。再联想此前百度与科大讯飞之间因语音识别免费开源而闹得沸沸扬扬一事,似乎从侧面印证了这个观点。对此,张本宇说出了自己的不同见解。 “只做技术的确会慢慢的贬值,但并不意味着完全的死路一条。”张本宇表示。在其看来,在技术已经开源的前提下,如果只是做技术,但是有没有去解决真正的行业问题,那样才的的确确是“死路一条”。 另外,他也称,将算法进行开源并不代表该算法能够在所有的行业或场景中达到领先。“很难有一个技术能够在所有行业里面都取得很好的效果,因为不同行业有不同特征,也有着不同需求,继而会诞生出一些新的算法。”张本宇表示。 我们可以看到,鉴于国内市场需求的庞大,以及在新技术采用与迭代方面的强悍,国内AI 技术实现商业化落地的前景还是非常之好的。不过,在这种情况下,还是有不少人在思考——如果要在AI领域创业,还有哪里可以进入?与此同时,在计算机视觉等领域,越来越多的玩家开始扎堆进行创业。 就以计算机视觉为例,“目前基本上还是在安防领域,而安防是一个以政府为主导的行业,在这之外还有很多的行业需求,像医疗、教育等等。其实,很多行业还是在用10年、20年前的技术,急需新技术的出现与变革。”张本宇表示。同时,他也警示,创业方向的选择也要考虑到团队整体的长处,在技术与产品落地之间如何抉择?需要依据不同的情况制定更为适合的战略决策。 云脑科技中国团队部分成员 结语 今年7月份,云脑科技已经完成了A轮融资,而在明年年初,他们就将开启新一轮融资计划。对于投资方的选择,张本宇表示,他会着重看两个方面,一个是双方是否能够在对AI的深度和广度上拥有一个较为一致的认知,另一方面则是希望双方能够在战略层面上能够达到一种很好地配合。 从某一层面来看,云脑科技是没有绝对竞争对手的,而相对来讲,在AI+人力资源、AI+金融等细分领域,它则有着竞争对手的。张本宇称,云脑科技的核心还是一个AI算法平台,但是它的表现形式就是适用于不同行业的中间件,让不同行业来刺激它,从而让它逐步的建立起来。 不过,虽然直接对标的竞争对手还没出现,但是张本宇还是表示了对于竞争对手出现的期待。毕竟很多时候,只有竞争的出现才能真正的把这件事情更快地推进,才能和客户共同推进这个行业。 原文发布时间: 2017-12-20 18:06 本文作者: 韩璐 本文来自云栖社区合作伙伴镁客网,了解相关信息可以关注镁客网。

优秀的个人博客,低调大师

基于 ACK Fluid 的混合云优化数据访问(二):搭建弹性计算实例与第三方存储的桥梁

前文回顾: 本系列将介绍如何基于 ACK Fluid 支持和优化混合云的数据访问场景,相关文章请参考:《基于 ACK Fluid 的混合云优化数据访问(一):场景与架构》 在前文《基于 ACK Fluid 的混合云优化数据访问(一):场景与架构》中,重点介绍 ACK Fluid 支持混合云数据访问适用的不同应用场景和架构实现。在本文中会重点介绍如何通过 ACK Fluid 实现公共云的弹性计算实例访问云下存储系统的能力。 概述 ACK(阿里云容器服务 Kubernetes)即开即用的弹性能力可以很好做自建IDC的弹性能力补充。特别是随着 AIGC 的流行,算力推动创新的理念深入人心,许多原本抵制计算上云的客户也开始在评估公共云。他们通常会选择使用 ECI(弹性计算实例)作为技术验证的第一步。但是,如何将自建存储与云上弹性资源对接,特别是 ECI 资源对接,就成了混合云客户使用阿里云的门槛。比如,用户想快速比较通过云上 ASK 和云下自建机房运行训练任务的成本,传统的做法需要把数据搬到云上,这就会涉及数据隐私问题,还有迁移的时间和金钱成本,无法做快速验证。甚至有些客户短期内无法通过内部安全评审,导致整个创新节奏受到严重的影响。 可以看到许多企业的数据都是存在线下,并且使用的存储类型多样,包括各种开源存储(Ceph,lustrure,JuiceFS,CubeFS)和自建存储。在使用公共云计算资源的时候,也存在挑战: 数据迁云安全性和成本评估时间长:对于数据迁移到云存储上,需要安全和存储团队的长时间评估,这会延缓整个上云过程。 数据访问适配性差:比如公共云对于弹性计算实例(ECI)支持的分布式存储类型有限(比如 NAS,OSS,CPFS),但是对于第三方存储缺乏支持。 接入云平台周期长和难度高:需要开发和维护云原生兼容的 CSI 插件,一方面需要相关的专家和开发适配工程量,同时要维护版本的升级,同时支持的场景有限。比如自建 CSI 无法适配弹性计算实例(ECI)。 缺乏可信透明的数据接入方式:如何在 Serverless 容器的黑盒系统访问数据过程中规避泄露,如何确保数据在传输、访问过程中安全,透明,可靠。 避免业务修改的需求:如何确保业务用户不感知基础设施层面的差异,避免对现有应用本身进行任何修改。 ACK Fluid 通过提供 ThinRuntime 扩展机制支持将基于 FUSE 实现第三方存储客户端以容器化的方式接入 Kubernetes 中,可以支持阿里云上标准 Kubernetes,边缘 Kubernetes,Serverless Kubernetes 多种形态。 简单的开发接入模式,易扩展:基于 ThinRuntime 方案,只需要了解 Dockerfile 构建就可以完成,一般开发工作 2-3 小时左右,从而显著降低了接入第三方存储的工作成本。同时基于开源 Fluid 标准对于 ThinRuntime 提供了完整的支持,只要满足开源要求就可以适配。 安全可控的数据访问:以容器化的方式支持自定义方式实现数据访问。整个数据访问过程云平台无侵入,无需提供实现细节。 无降低改造适配的成本:只需要在 PVC 中添加特定 label 即可,满足了业务用户无需感知基础设施层面的差异的需求,能将存储适配时间缩短为原计划的十分之一。 存储客户端的自适应部署:Fluid 同时支持 CSI 和 FUSE Sidecar 两种客户端部署模式,根据所在运行平台选择合适的部署模式,将 PVC 协议转换成 Sidecar 模式,无需最终用户感知。 增强可观测性和可控制性:第三方存储客户端只需要实现自身的容器化,就可以转化为 Fluid 管理的 Pod,无缝接入 Kubernetes 体系,并获得可观测性和计算资源可控制性。 总结:ACK Fluid 为云上计算访问云下数据提供了扩展性好,安全可控,低适配成本和与云平台实现无关的好处,应用案例参见小米[1]。 演示 以开源 MinIO 为例,展示如何通过 Fluid 将第三方存储接入阿里云弹性计算资源(ECI)。 1. 前提条件 已创建 ACK Pro 版集群,且集群版本为 1.18 及以上。具体操作,请参见创建 ACK Pro 版集群[2]。 已安装云原生 AI 套件并部署 ack-fluid 组件。重要:若您已安装开源 Fluid,请卸载后再部署 ack-fluid 组件。 未安装云原生 AI 套件:安装时开启Fluid 数据加速。具体操作,请参见安装云原生 AI 套件[3]。 已安装云原生 AI 套件:在容器服务管理控制台的云原生 AI 套件页面部署ack-fluid。 已部署 ACK 虚拟节点(Virtual Node)。具体操作,请参见通过部署 ACK 虚拟节点组件创建 ECI Pod[4]。 已通过 kubectl 连接 ACK 集群。具体操作,请参见通过 kubectl 工具连接集群[5]。 2. 准备MinIO环境 部署 Minio 存储到 ACK 集群中。 如下 YAML 文件 minio.yaml: apiVersion: v1 kind: Service metadata: name: minio spec: type: ClusterIP ports: - port: 9000 targetPort: 9000 protocol: TCP selector: app: minio --- apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 kind: Deployment metadata: # This name uniquely identifies the Deployment name: minio spec: selector: matchLabels: app: minio strategy: type: Recreate template: metadata: labels: # Label is used as selector in the service. app: minio spec: containers: - name: minio # Pulls the default Minio image from Docker Hub image: bitnami/minio env: # Minio access key and secret key - name: MINIO_ROOT_USER value: "minioadmin" - name: MINIO_ROOT_PASSWORD value: "minioadmin" - name: MINIO_DEFAULT_BUCKETS value: "my-first-bucket:public" ports: - containerPort: 9000 hostPort: 9000 部署上述资源到 ACK 集群: $ kubectl create -f minio.yaml 部署成功后,ACK 集群内的其他 Pod 即可通过http://minio:9000的Minio API 端点访问 Minio 存储系统中的数据。上述 YAML 配置中,我们设置 Minio 的用户名与密码均为 minioadmin,并在启动 Minio 存储时默认创建一个名为 my-first-bucket 的存储桶,在接下来的示例中,我们将会访问 my-first-bucket 这个存储桶中的数据。在执行以下步骤前,首先执行以下命令,在 my-first-bucket 中存储示例文件: $ kubectl exec -it minio-69c555f4cf-np59j -- bash -c "echo fluid-minio-test > testfile" $ kubectl exec -it minio-69c555f4cf-np59j -- bash -c "mc cp ./testfile local/my-first-bucket/" $ kubectl exec -it minio-69c555f4cf-np59j -- bash -c "mc cat local/my-first-bucket/testfile" fluid-minio-test 3. 集群管理员将 MinIO 接入 Fluid 的开发和部署过程 作为一个 MinIO 存储管理员,接入 Fluid 的工作主要是三个步骤,以下调试过程可以在开源 Kubernetes 中完成: 开发和构建 MinIO 容器镜像 开发和部署 MinIO 的 RuntimeProfile 创建访问 MinIO 的 Fluid 数据集,并且生成对应的数据卷 3.1. 容器镜像的开发和构建 Fluid 将会把 ThinRuntime 中 FUSE 所需的运行参数、Dataset 中描述数据路径的挂载点等参数传入到 ThinRuntime FUSE Pod 容器中。在容器内部,需要执行参数解析脚本,并将解析完的运行时参数传递给 FUSE 客户端程序,由客户端程序完成 Fuse 文件系统在容器内的挂载。 因此,使用 ThinRuntime CRD 描述存储系统时,需要使用特制的容器镜像,镜像中需要包括以下两个程序: FUSE 客户端程序 FUSE 客户端程序所需的运行时参数解析脚本 对于 FUSE 客户端程序,在本示例中选择 S3 协议兼容的 goofys 客户端连接并挂载 minio 存储系统。 对于运行时所需的参数解析脚本,定义如下 python 脚本 fluid-config-parse.py: import json with open("/etc/fluid/config.json", "r") as f: lines = f.readlines() rawStr = lines[0] print(rawStr) script = """ #!/bin/sh set -ex export AWS_ACCESS_KEY_ID=`cat $akId` export AWS_SECRET_ACCESS_KEY=`cat $akSecret` mkdir -p $targetPath exec goofys -f --endpoint "$url" "$bucket" $targetPath """ obj = json.loads(rawStr) with open("mount-minio.sh", "w") as f: f.write("targetPath=\"%s\"\n" % obj['targetPath']) f.write("url=\"%s\"\n" % obj['mounts'][0]['options']['minio-url']) if obj['mounts'][0]['mountPoint'].startswith("minio://"): f.write("bucket=\"%s\"\n" % obj['mounts'][0]['mountPoint'][len("minio://"):]) else: f.write("bucket=\"%s\"\n" % obj['mounts'][0]['mountPoint']) f.write("akId=\"%s\"\n" % obj['mounts'][0]['options']['minio-access-key']) f.write("akSecret=\"%s\"\n" % obj['mounts'][0]['options']['minio-access-secret']) f.write(script) 上述 python 脚本按以下步骤执行: 读取 /etc/fluid/config.json 文件中的 json 字符串,Fluid 会将 Fuse 客户端挂载所需的参数存储并挂载到 Fuse 容器的 /etc/fluid/config.json 文件。 解析 json 字符串,从中提取 Fuse 客户端挂载所需的参数。例如,上述示例中的 url、bucket、minio-access-key、minio-access-secret 等参数。 提取出所需参数后,输出挂载脚本到文件 mount-minio.sh。 ⚠️注意:在 Fluid 中,/etc/fluid/config.json 文件中仅会提供各个加密参数具体值的存储路径,因此需要参数解析脚本额外执行文件读取操作(例如:上述示例中的 "export AWS_ACCESS_KEY_ID=`cat $akId`")。 接着,使用如下 Dockerfile 制作镜像,这里我们直接选择包含 goofys 客户端程序的镜像(i.e. cloudposse/goofys)作为 Dockerfile 的基镜像: FROM cloudposse/goofys RUN apk add python3 bash COPY ./fluid-config-parse.py /fluid-config-parse.py 使用以下命令构建并推送镜像到镜像仓库: $ IMG_REPO=<your image repo> $ docker build -t $IMG_REPO/fluid-minio-goofys:demo . $ docker push $IMG_REPO/fluid-minio-goofys:demo 3.2. 开发和部署 MinIO 的 ThinRuntimeProfile 在创建 Fluid Dataset 和 ThinRuntime 挂载 Minio 存储系统前,首先需要开发 ThinRuntimeProfile CR 资源。ThinRuntimeProfile 是一种 Kubernetes 集群级别的 Fluid CRD 资源,它描述了一类需要与 Fluid 对接的存储系统的基础配置(例如:容器、计算资源描述信息等)。集群管理员需提前在集群中定义若干 ThinRuntimeProfile CR 资源,在这之后,集群用户需要显示声明引用一个 ThinRuntimeProfile CR 来创建 ThinRuntime,从而完成对应存储系统的挂载。 以下为 MinIO 存储系统的 ThinRuntimeProfile CR 示例(profile.yaml): apiVersion: data.fluid.io/v1alpha1 kind: ThinRuntimeProfile metadata: name: minio spec: fileSystemType: fuse fuse: image: $IMG_REPO/fluid-minio-goofys imageTag: demo imagePullPolicy: IfNotPresent command: - sh - -c - "python3 /fluid-config-parse.py && chmod u+x ./mount-minio.sh && ./mount-minio.sh" 在上述 CR 示例中: fileSystemType 描述了 ThinRuntime FUSE 所挂载的文件系统类型 (fsType)。需要根据使用的存储系统 Fuse 客户端程序填写,例如,goofys 挂载的挂载点 fsType为fuse,s3fs 挂载的挂载点 fsType 为 fuse.s3fs) fuse 描述了 ThinRuntime FUSE 的容器信息,包括镜像信息 (image、imageTag、imagePullPolicy) 以及容器启动命令 (command) 等。 创建 ThinRuntimeProfile CR minio 并且部署到 ACK 集群。 3.3. 创建 Dataset 和 ThinRuntime CR 来挂载访问 Minio 存储系统中的数据。 创建访问 minio 所需的凭证 Secret: $ kubectl create secret generic minio-secret \ --from-literal=minio-access-key=minioadmin \ --from-literal=minio-access-secret=minioadmin 创建 Dataset 和 ThinRuntime CR 的示例(dataset.yaml),目的是生成用户可用的存储数据卷: apiVersion: data.fluid.io/v1alpha1 kind: Dataset metadata: name: minio-demo spec: mounts: - mountPoint: minio://my-first-bucket # minio://<bucket name> name: minio options: minio-url: http://minio:9000 # minio service <url>:<port> encryptOptions: - name: minio-access-key valueFrom: secretKeyRef: name: minio-secret key: minio-access-key - name: minio-access-secret valueFrom: secretKeyRef: name: minio-secret key: minio-access-secret --- apiVersion: data.fluid.io/v1alpha1 kind: ThinRuntime metadata: name: minio-demo spec: profileName: minio Dataset.spec.mounts[*].mountPoint 指定所需访问的数据桶 (e.g. my-frist-bucket) Dataset.spec.mounts[*].options.minio-url 指定 minio 在集群可访问的 URL(e.g.http://minio:9000) ThinRuntime.spec.profileName 指定已创建的 ThinRuntimeProfile(e.g. minio-profile) 创建 Dataset 和 ThinRuntime CR: $ kubectl create -f dataset.yaml 检查 Dataset 状态,一段时间后,可发现 Dataset 和 Phase 状态变为 Bound,Dataset 可正常挂载使用: $ kubectl get dataset minio-demo NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE minio-demo N/A N/A N/A Bound 2m18s 4. 最终用户使用 ECI(弹性容器实例)直接通过 PVC(数据卷申请)直接访问 MinIO 对于最终用户来说,访问 MinIO 的过程是非常简单的。以下为示例 Pod Spec 的 YAML 文件(pod.yaml),用户只需要使用和 Dataset 同名的 PVC: apiVersion: v1 kind: Pod metadata: name: test-minio labels: alibabacloud.com/fluid-sidecar-target: eci alibabacloud.com/eci: "true" spec: restartPolicy: Never containers: - name: app image: nginx:latest command: ["bash"] args: - -c - ls -lh /data && cat /data/testfile && sleep 180 volumeMounts: - mountPath: /data name: data-vol volumes: - name: data-vol persistentVolumeClaim: claimName: minio-demo http://alibabacloud.com/fluid-sidecar-target=eci标识了需要启用 ACK Fluid 对于 ECI 的特定支持 http://alibabacloud.com/eci表示在 ACK 中调度到 ECI 对应的虚拟节点 创建数据访问Pod: $ kubectl create -f pod.yaml 查看数据访问 Pod 结果: $ kubectl logs test-minio -c app total 512 -rw-r--r-- 1 root root 6 Aug 15 12:32 testfile fluid-minio-test 可以看到,Pod test-minio 可正常访问 Minio 存储系统中的数据。 5. 环境清理 $ kubectl delete -f pod.yaml $ kubectl delete -f dataset.yaml $ kubectl delete -f profile.yaml $ kubectl delete -f minio.yaml ⚠️注意 本示例用于展示整个数据接入流程,相关的 MinIO 环境配置仅作为演示目的。 相关链接: [1] 小米 https://www.infoq.cn/article/kco7hi5TcVE08ySwNIw7 [2] 创建 ACK Pro 版集群 https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/create-an-ack-managed-cluster-2#task-skz-qwk-qfb [3] 安装云原生 AI 套件 https://help.aliyun.com/zh/ack/cloud-native-ai-suite/user-guide/deploy-the-cloud-native-ai-suite#task-2038811 [4] 通过部署 ACK 虚拟节点组件创建 ECI Pod https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/deploy-the-virtual-node-controller-and-use-it-to-create-elastic-container-instance-based-pods#task-1443354 [5] 通过 kubectl 工具连接集群 https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/obtain-the-kubeconfig-file-of-a-cluster-and-use-kubectl-to-connect-to-the-cluster#task-ubf-lhg-vdb 作者:车漾 点击立即免费试用云产品 开启云上实践之旅! 原文链接 本文为阿里云原创内容,未经允许不得转载。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册