MINIO无公网访问地址下OSS的配置

在实际项目中,会存在MINIO外网不能访问,只能通过应用的域名(IP)进行转发才能访问的情况。该篇文章主要是为解决这种场景。

PS:如果MINIO外网可以直接访问,正常配置MINIO的OSS配置即可。

阅读之前

  • 了解MINIO对endpoint的限制, As per S3 specification, path in the endpoint is not supported. 即MINIO的请求地址不能带path.

详细参考:https://github.com/minio/minio-java/issues/1476
MINIO无公网访问地址下OSS的配置

解决办法

  • 项目中的MINIO地址配置一个可以访问的外网地址; 在网络层(NGINX)中配置该外网地址到MINIO的内网地址;
  • 因MINIO对endpoint的限制只能是 ip+port,即不能包含path, 也即不能通过配置path的方式进行转发;需要给一个IP(域名)+ 端口的 外部地址。

详细配置步骤

项目中OSS的配置

uploadUrl 和 downloadUrl配置为外网可访问的地址,非实际的MINIO地址。即访问MINIO通过一个可外部访问的地址进行转换

cdn:
  oss:
    name: MINIO
    type: MINIO
    bucket: pamirs
    # uploadUrl 和 downloadUrl配置为外网可访问的地址,非实际的MINIO地址
    uploadUrl: http://127.0.0.1:8083
    downloadUrl: http://127.0.0.1:8083
    accessKeyId: svs7nKWRSrfFPH1X5FOy
    accessKeySecret: yoIq1T1w4ythggvL51rNyyiKST0KLPagUwB3C23A
    mainDir: assert/demo
    validTime: 3600000A
    timeout: 600000
    active: true
    referer:
    localFolderUrl:

NGINX配置(MINIO配置)

    upstream minio {
       #真实的MINIO的地址
        server 39.103.145.77:9000 weight=100 max_fails=2 fail_timeout=30s;
    }

    server {
        listen 8083;
        server_name 127.0.0.1;

        location / {
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-For $remote_addr;
            client_body_buffer_size 10M;
            client_max_body_size 50M;
            proxy_buffers 1024 4k;
            proxy_read_timeout 3000;
            proxy_next_upstream error timeout http_404;

            proxy_pass http://minio;
        }
    }

解决办法2

自定义实现MinioOssClient,跳过minio官方限制

package pro.shushi.pamirs.hr.core.file;

import io.minio.DateFormat;
import io.minio.MinioClient;
import io.minio.PostPolicy;
import io.minio.Result;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.framework.connectors.cdn.client.AbstractFileClient;
import pro.shushi.pamirs.framework.connectors.cdn.configure.CdnConfig;
import pro.shushi.pamirs.framework.connectors.cdn.enmu.CDNExpEnum;
import pro.shushi.pamirs.framework.connectors.cdn.factory.CdnConfigRouter;
import pro.shushi.pamirs.framework.connectors.cdn.pojo.*;
import pro.shushi.pamirs.framework.connectors.cdn.utils.MinioMultipart;
import pro.shushi.pamirs.framework.connectors.cdn.utils.URLHelper;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.api.prefix.KeyPrefixManager;
import pro.shushi.pamirs.meta.common.exception.PamirsException;
import pro.shushi.pamirs.meta.common.spi.SPI;

import javax.annotation.PostConstruct;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static pro.shushi.pamirs.framework.connectors.cdn.utils.MinioMultipart.generateRequestHeader;
import static pro.shushi.pamirs.meta.common.constants.CharacterConstants.SEPARATOR_SLASH;

@Slf4j
@Component
@SPI.Service(WzMiniOssClient.TYPE)
public class WzMiniOssClient extends AbstractFileClient {

    @Value("${cdn.oss.minioRealUrl}")
    private String minioRealUrl;

    public static final String TYPE = "WZ_MINIO";
    private static final String CONTENT_ENCODING = "Content-Encoding";
    private static final String CHUNKED = "aws-chunked";
    private static final String CONTENT_LENGTH = "x-amz-decoded-content-length";
    private static MinioClient DEFAULT_MINIO_CLIENT;

    private static final Map<String, MinioClient> MINIO_CLIENTS = new ConcurrentHashMap<>(2);

    private static final long MAX_OBJECT_SIZE = 5L * 1024 * 1024 * 1024 * 1024;
    // maxPartSize - maximum part size 5GiB for a single multipart upload operation
    private static final int MAX_MULTIPART_COUNT = 10000;
    // minimum allowed multipart size is 5MiB
    private static final int MIN_MULTIPART_SIZE = 5 * 1024 * 1024;

    // maximum allowed bucket policy size is 12KiB
    @Override
    protected String generatorFrontUploadFileKey(String filename) {
        CdnConfig cdnConfig = getCdnConfig();
        return getMinoFileKey(cdnConfig.getMainDir(), filename);
    }

    @Override
    protected String generatorFrontUploadUrl() {
        String uploadUrl = super.generatorFrontUploadUrl();
        if (!uploadUrl.endsWith(SEPARATOR_SLASH)) {
            uploadUrl = uploadUrl + SEPARATOR_SLASH;
        }
        return uploadUrl;
    }

    @Override
    protected Map<String, String> generatorFormData(String fileKey, CdnUploadFileRequest request) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();
        String bucket = cdnConfig.getBucket();
        Long validTime = cdnConfig.getValidTime();
        try {
            PostPolicy postPolicy = new PostPolicy(bucket, fileKey, DateTime.now().plus(validTime));
            Map<String, String> formData = minioClient.presignedPostPolicy(postPolicy);
            formData.remove("bucket");
            formData.put("key", fileKey);
            return formData;
        } catch (Exception e) {
            throw PamirsException.construct(CDNExpEnum.MINIO_GET_FORM_DATA_ERROR, e).errThrow();
        }
    }

    @Override
    protected String getDefaultBaseDownloadUrl(CdnConfig cdnConfig) {
        return cdnConfig.getDownloadUrl() + SEPARATOR_SLASH + cdnConfig.getBucket();
    }

    @Override
    protected String getDefaultBaseUploadUrl(CdnConfig cdnConfig) {
        return minioRealUrl + SEPARATOR_SLASH + cdnConfig.getBucket();
    }

    @Override
    protected CdnMultipartUploadData generatorMultipartFileFormData(String fileKey, CdnUploadFileRequest request) {
        List<CdnChunkFile> chunkFiles = getChunkFiles(request);
        if (chunkFiles == null) {
            return null;
        }
        fileKey = URLHelper.encodeFileName(fileKey);
        CdnConfig cdnConfig = getCdnConfig();
        String accessKeyId = cdnConfig.getAccessKeyId();
        String accessKeySecret = cdnConfig.getAccessKeySecret();

        String date = new DateTime().toString(DateFormat.AMZ_DATE_FORMAT);
        String baseUploadUrl = getBaseUploadUrl();
        String uploadUrl = baseUploadUrl + SEPARATOR_SLASH + fileKey;

        //获取uploadId
        String uploadId = MinioMultipart.initMultipartUpload(baseUploadUrl, fileKey, accessKeyId, accessKeySecret, date);
        if (uploadId == null) {
            return null;
        }

        //构建分片上传参数
        CdnMultipartUploadData multipartUploadData = new CdnMultipartUploadData();
        List<CdnSingleUploadData> uploadDataList = new ArrayList<>();
        for (CdnChunkFile chunkFile : chunkFiles) {
            String partNumber = chunkFile.getPartNumber().toString();
            String fileSize = chunkFile.getFileSize().toString();
            CdnSingleUploadData singleUploadData = new CdnSingleUploadData();
            singleUploadData.setHttpMethod(Method.PUT.name());
            String url = String.format("%s?uploadId=%s&partNumber=%s", uploadUrl, uploadId, partNumber);
            singleUploadData.setUploadUrl(url);

            Map<String, String> uploadHeaders = new HashMap<>();
            uploadHeaders.put(CONTENT_ENCODING, CHUNKED);
            uploadHeaders.put(CONTENT_LENGTH, fileSize);
            try {
                generateRequestHeader(uploadHeaders, url, Method.PUT.toString(), accessKeyId, accessKeySecret, date);
            } catch (MalformedURLException | NoSuchAlgorithmException | InvalidKeyException e) {
                log.error("Minio 获取分片 生成请求头失败", e);
                return null;
            }
            singleUploadData.setUploadHeaders(uploadHeaders);
            uploadDataList.add(singleUploadData);
        }
        multipartUploadData.setUploadDataList(uploadDataList);

        //合并所有分片上传参数
        CdnCompleteUploadData completeUploadData = new CdnCompleteUploadData();
        String uploadCompleteUrl = baseUploadUrl + SEPARATOR_SLASH + fileKey + "?uploadId=" + uploadId;
        completeUploadData.setUploadUrl(uploadCompleteUrl);

        Map<String, String> uploadCompleteHeaders = new HashMap<>();
        try {
            generateRequestHeader(uploadCompleteHeaders, uploadCompleteUrl, Method.POST.toString(), accessKeyId, accessKeySecret, date);
        } catch (MalformedURLException | NoSuchAlgorithmException | InvalidKeyException e) {
            log.error("Minio 合并分片 生成请求头失败", e);
            return null;
        }
        completeUploadData.setUploadHeaders(uploadCompleteHeaders);
        completeUploadData.setUploadData("`<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\n<CompleteMultipartUpload>\n" + "${parts}" + "</CompleteMultipartUpload>`");
        completeUploadData.setUploadPartData("`<Part>\n" + "<PartNumber>${partNumber}</PartNumber>\n" + "<ETag>${response.partKey}</ETag>\n" + "</Part>\n`");

        Map<String, String> uploadCompletePartContext = new HashMap<>();
        uploadCompletePartContext.put("partNumber", "partNumber");
        uploadCompletePartContext.put("response.partKey", "headers.etag");
        completeUploadData.setUploadPartContext(uploadCompletePartContext);
        multipartUploadData.setCompleteUploadData(completeUploadData);
        return multipartUploadData;
    }

    @Override
    public CdnFile upload(String fileName, byte[] data) {
        return upload(fileName, new ByteArrayInputStream(data));
    }

    @Override
    public CdnFile upload(String fileName, InputStream inputStream) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();
        CdnFile cdnFile = new CdnFile();
        String fileKey = getMinoFileKey(cdnConfig.getMainDir(), fileName);
        String bucket = cdnConfig.getBucket();
        try {
            Map<String, String> headerMap = new HashMap<>();
            String contentType = MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM).toString();
            headerMap.put("Content-Type", contentType);
            minioClient.putObject(bucket, fileKey, inputStream, Long.valueOf(inputStream.available()), headerMap, null, contentType);
            String url = getBaseDownloadUrl() + SEPARATOR_SLASH + fileKey;
            cdnFile.setType(FILE_TYPE);
            cdnFile.setName(fileName);
            cdnFile.setUrl(url);
        } catch (Exception e) {
            log.error("MINIO文件上传服务出错!", e);
            try {
                inputStream.close();
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
        return cdnFile;
    }

    @Override
    public String uploadByFileName(String fileName, byte[] data) {
        return uploadByFileName(fileName, new ByteArrayInputStream(data));
    }

    @Override
    public String uploadByFileName(String fileName, InputStream inputStream) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();

        String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
        String fileKey = cdnConfig.getMainDir() + keyPrefix + fileName;
        String bucket = cdnConfig.getBucket();
        Map<String, String> headerMap = new HashMap<>();
        String contentType = MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM).toString();
        headerMap.put("Content-Type", contentType);
        try {
            minioClient.putObject(bucket, fileKey, inputStream, contentType);
            return getBaseDownloadUrl() + SEPARATOR_SLASH + fileKey;
        } catch (Exception e) {
            log.error("MINIO文件上传服务出错!", e);
        }
        return null;
    }

    @Override
    public String getDownloadUrl(String fileName) {
        CdnConfig cdnConfig = getCdnConfig();
        String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
        String fileKey = cdnConfig.getMainDir() + keyPrefix + fileName;
        return generatorDownloadUrl(fileKey);
    }

    @Override
    public void deleteByFolder(String folder) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();
        String folderKey = getMinoFolder(cdnConfig.getMainDir(), folder);
        String bucket = cdnConfig.getBucket();

        try {
            // 获取指定前缀下的所有对象
            Iterable<Result<Item>> objects = minioClient.listObjects(bucket, folderKey, true);

            // 遍历对象列表,获取对象名
            List<String> objectNames = new ArrayList<>();
            for (Result<Item> result : objects) {
                Item item = result.get();
                objectNames.add(item.objectName());
            }
            minioClient.removeObjects(bucket, objectNames);
            log.info("deleteByFolder folder:[{}] 成功", folder);
        } catch (Exception e) {
            log.error("deleteByFolder folder:[{" + folder + "}] 失败", e);
        }
    }

    @Override
    public InputStream getDownloadStream(String fileKey) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();
        String bucket = cdnConfig.getBucket();
        String bucketPrefix = bucket + SEPARATOR_SLASH;
        if (fileKey.startsWith(bucketPrefix)) {
            fileKey = fileKey.substring(bucketPrefix.length());
        }
        try {
            return minioClient.getObject(bucket, fileKey);
        } catch (Throwable e) {
            log.error("MINIO读取文件IO异常", e);
        }
        return null;
    }

    @Override
    public String fetchContent(String fileName) {
        try {
            CdnConfig cdnConfig = getCdnConfig();
            MinioClient minioClient = getMinioClient();
            String bucket = cdnConfig.getBucket();
            String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
            String fileKey = cdnConfig.getMainDir() + keyPrefix + fileName;
            InputStream inputStream = minioClient.getObject(bucket, fileKey);
            String content = IOUtils.toString(inputStream);
            inputStream.close();
            return content;
        } catch (Throwable e) {
            log.error("MINIO读取文件IO异常", e);
        }
        return null;
    }

    @Override
    public void deleteByFilename(String filename) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();
        String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
        String fileKey = cdnConfig.getMainDir() + keyPrefix + filename;
        String bucket = cdnConfig.getBucket();
        try {
            minioClient.removeObject(bucket, fileKey);
        } catch (Exception e) {
            log.error("MINIO文件上传服务出错!", e);
        }
    }

    @Override
    public boolean isExistByFilename(String filename) {
        CdnConfig cdnConfig = getCdnConfig();
        MinioClient minioClient = getMinioClient();
        String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
        String fileKey = cdnConfig.getMainDir() + keyPrefix + filename;
        String bucket = cdnConfig.getBucket();
        try {
            minioClient.statObject(bucket, fileKey);
            return true;
        } catch (Exception e) {
            log.error("MINIO文件上传服务出错!", e);
        }
        return false;
    }

    /**
     * 静态文件只有路径/用于初始化文件放置的路径
     * <p>
     * 配置项 DownloadUrl 必须带 协议头:HTTP/HTTPS
     *
     * @return
     */
    @Override
    public String getStaticUrl() {
        CdnConfig cdnConfig = getCdnConfig();
        if (cdnConfig.getAppLogoUseCdn() != null && cdnConfig.getAppLogoUseCdn()) {
            return minioRealUrl + SEPARATOR_SLASH + cdnConfig.getBucket();
        } else {
            return CdnConfig.defaultCdnUrl;
        }
    }

    // 客户特定场景需要(目前有客户需要),不要改变开放级别。
    // 正确的获取文件系统Client的方式:FileClientFactory.getClient()
    public MinioClient getMinioClient() {
        String routerKey = CdnConfigRouter.get();
        if (StringUtils.isBlank(routerKey)) {
            return DEFAULT_MINIO_CLIENT;
        }
        return MINIO_CLIENTS.computeIfAbsent(routerKey, (key) -> generatorMinioClient(getCdnConfig()));
    }

    protected MinioClient generatorMinioClient(CdnConfig cdnConfig) {
        MinioClient minioClient = null;
        String accessKeyId = cdnConfig.getAccessKeyId();
        String accessKeySecret = cdnConfig.getAccessKeySecret();
        // String endpoint = cdnConfig.getUploadUrl();
        Long timeout = cdnConfig.getTimeout();
        try {
            minioClient = new MinioClient(minioRealUrl, accessKeyId, accessKeySecret);
            minioClient.setTimeout(timeout, timeout, timeout);
            String bucketName = cdnConfig.getBucket();
            boolean isExist = minioClient.bucketExists(bucketName);
            if (!isExist) {
                minioClient.makeBucket(bucketName);
            }
        } catch (Exception e) {
            log.error("Minio 连接异常,bucketName: " + cdnConfig.getBucket() + "", e);
        }
        return minioClient;
    }

    @PostConstruct
    public void init() {
        CdnConfig cdnConfig = getCdnConfig();
        if (WzMiniOssClient.TYPE.equals(cdnConfig.getType())) {
            DEFAULT_MINIO_CLIENT = generatorMinioClient(cdnConfig);
        }
    }

    //FileKey不能以 / 开头,否则老版本的MINIO会有问题
    protected String getMinoFileKey(String mainDir, String filename) {
        String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
        if (StringUtils.isNotBlank(keyPrefix)) {
            if (!keyPrefix.endsWith(SEPARATOR_SLASH)) {
                keyPrefix = keyPrefix + SEPARATOR_SLASH;
            }
        }
        return getFileDir(mainDir) + SEPARATOR_SLASH + keyPrefix + filename;
    }

    protected String getMinoFolder(String mainDir, String folder) {
        String keyPrefix = KeyPrefixManager.generate(SEPARATOR_SLASH, SEPARATOR_SLASH);
        if (StringUtils.isNotBlank(keyPrefix)) {
            if (!keyPrefix.endsWith(SEPARATOR_SLASH)) {
                keyPrefix = keyPrefix + SEPARATOR_SLASH;
            }
        }
        return getFileDir(mainDir) + SEPARATOR_SLASH + keyPrefix + folder;
    }
}

nginx 配置,拦截前端访问地址,转到实际minio地址

location /minio/ {
    rewrite ^/minio(/.*)$ $1 break; # 去除/minio前缀
    proxy_pass http://39.103.145.77:9000;
}

oss配置
MINIO无公网访问地址下OSS的配置

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/yun-wei-shi-jian/7112.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
望闲的头像望闲数式管理员
上一篇 2024年5月8日 am2:46
下一篇 2024年5月11日 am10:52

相关推荐

  • Maven包拉取:拉取Oinone包的配置

    1、方式一,配置数式仓库代理 创建一个proxy类型的仓库 点击"Repository"–>“Repositories”–>“Create repository”,选择maven2(proxy)。 Name:要代理的数式的maven,自定义maven-proxy-shushi-release Online:勾选,设置成在线 ProxyRemote storage:设置远程数式仓库的地址。这里设置成数式的maven仓库地址:http://nexus.shushi.pro/repository/pamirs-releases/ 认证方式:Authentication,填写数式提供的用户名和密码; 其他的保持默认即可 用同样的方式,把数式snapshots(http://nexus.shushi.pro/repository/pamirs-snapshots/) 2、方式二,Settings融合 在Maven的配置文件中(settings.xml),增加数式的仓库配置: <!– oinone –> <server> <id>oinone-develop-release</id> <username>数式提供的账号</username> <password>数式提供的密码</password> </server> <server> <id>oinone-develop-snapshot</id> <username>数式提供的账号</username> <password>数式提供的密码</password> </server> <!– oinone –> <repository> <id>oinone-develop-release</id> <name>Repository for pamirs releases</name> <url>http://nexus.shushi.pro/repository/pamirs-releases/</url> <releases> <enabled>true</enabled> <!– <updatePolicy>always</updatePolicy> –> </releases> <snapshots> <enabled>false</enabled> </snapshots> <layout>default</layout> </repository> <repository> <id>oinone-develop-snapshot</id> <name>Repository for pamirs snapshots</name> <url>http://nexus.shushi.pro/repository/pamirs-snapshots/</url> <snapshots> <enabled>true</enabled> </snapshots> <layout>default</layout> </repository>

    2024年2月20日
    73700
  • Oinone平台部署及依赖说明(v4.7)

    概述 名词解释 业务工程包:指平台提供的内置基础包和内置功能包。 设计器工程包:指模型设计器、界面设计器、流程设计器等相关依赖包。 父POM:仅声明依赖包版本的pom文件 启动工程POM:仅声明具体依赖包的pom文件,一般不用于指定版本。 业务工程部署 Oinone平台向合作伙伴提供前后端业务工程所需的全部依赖,依赖项的具体说明下面会分别介绍。 设计器部署 Oinone平台向合作伙伴提供了两种设计器部署方式: Docker镜像:支持amd64和arm64两种架构的操作系统。(推荐) JAR包:与Docker镜像中的内容完全一致。 使用JAR包直接启动需要使用Oinone专属启动器,Docker镜像已内置Oinone专属启动器。 PS:如遇到以上部署方式或提供的镜像无法满足部署需求时,请联系Oinone平台售后获取技术支持。 Docker镜像 体验镜像 包括所有设计器。 内置所有所需中间件,包括Mysql、Redis、Zookeeper、RocketMQ。 适用场景:用于快速体验Oinone平台全部功能 docker pull harbor.oinone.top/oinone/oinone-designer-full-v4.8:TAG 前后端一体部署镜像 包括所有设计器。 无内置中间件。 适用场景:用于便捷部署Oinone平台的前后端服务 docker pull harbor.oinone.top/oinone/oinone-designer-mini-v4.8:TAG 前后端一体部署镜像 – 流程设计器 仅包括流程设计器。 无内置中间件。 适用场景:用于便捷部署仅需流程设计器的Oinone平台的前后端服务。 docker pull harbor.oinone.top/oinone/workflow-designer-v4.8:TAG 镜像拉取 以体验镜像为例,Oinone平台提供多种拉取镜像的方式。 # 获取混合架构镜像,支持amd64和arm64架构的操作系统 docker pull harbor.oinone.top/oinone/oinone-designer-full-v4.8:4.8.19 # 仅获取amd64架构镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v4.8:4.8.19-amd64 # 仅获取arm64架构镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v4.8:4.8.19-arm64 # 获取最新版镜像(每次拉取自动更新) docker pull harbor.oinone.top/oinone/oinone-designer-full-v4.8 PS:如镜像拉取过慢,可在确定操作系统架构的情况下获取amd64或arm64架构镜像。 JAR包获取 $VERSION:对应镜像版本号 包含所有设计器的后端JAR包下载路径示例 https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/oinone-designer/pamirs-designer-boot-v4.8-$VERSION.jar 仅包含流程设计器的后端JAR包下载路径示例 https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/workflow-designer/pamirs-workflow-designer-boot-v4.8-$VERSION.jar 后端依赖 Oinone平台后端使用Maven管理工具对所有依赖包进行版本管理。 版本说明 下面是在每个版本升级说明中提供的所有依赖版本,最新版本请查看对应的最新升级说明文档。 版本更新日志 <!– 平台基础 –> <pamirs.middleware.version>4.7.8.5</pamirs.middleware.version> <pamirs.k2.version>4.7.8.7</pamirs.k2.version> <pamirs.framework.version>4.7.8.19</pamirs.framework.version> <pamirs.boot.version>4.7.8.12</pamirs.boot.version> <pamirs.distribution.version>4.7.8.5</pamirs.distribution.version> <!– 平台功能 –> <pamirs.metadata.manager>4.7.8</pamirs.metadata.manager> <pamirs.core.version>4.7.8.19</pamirs.core.version> <pamirs.workflow.version>4.7.8.16</pamirs.workflow.version> <pamirs.workbench.version>4.7.8</pamirs.workbench.version> <pamirs.data.visualization.version>4.7.8.1</pamirs.data.visualization.version> <!– 设计器 –> <pamirs.designer.common.version>4.7.8</pamirs.designer.common.version> <pamirs.flow.designer.base.version>4.7.8.1</pamirs.flow.designer.base.version> <pamirs.workflow.designer.version>4.7.8</pamirs.workflow.designer.version> <pamirs.model.designer.version>4.7.8</pamirs.model.designer.version> <pamirs.ui.designer.version>4.7.8.9</pamirs.ui.designer.version> <pamirs.data.designer.version>4.7.8</pamirs.data.designer.version> <pamirs.dataflow.designer.version>4.7.8.1</pamirs.dataflow.designer.version> <pamirs.eip.designer.version>4.7.8.1</pamirs.eip.designer.version> 完整依赖管理示例 以下列举了除了设计器相关依赖外的全部依赖管理项,其通常使用在父POM中。 <dependency> <groupId>pro.shushi.pamirs</groupId> <artifactId>pamirs-k2</artifactId> <version>${pamirs.k2.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs</groupId> <artifactId>pamirs-framework</artifactId> <version>${pamirs.framework.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs.boot</groupId> <artifactId>pamirs-boot-dependencies</artifactId> <version>${pamirs.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-core-dependencies</artifactId> <version>${pamirs.core.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs</groupId> <artifactId>pamirs-distribution</artifactId> <version>${pamirs.distribution.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>pro.shushi.pamirs.middleware</groupId> <artifactId>pamirs-middleware-dependencies</artifactId> <version>${pamirs.middleware.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!–metadata manager–> <dependency> <groupId>pro.shushi.pamirs.metadata.manager</groupId> <artifactId>pamirs-metadata-manager</artifactId> <version>${pamirs.metadata.manager}</version> </dependency> <!–workflow–> <dependency> <groupId>pro.shushi.pamirs.workflow</groupId> <artifactId>pamirs-workflow</artifactId> <version>${pamirs.workflow.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!–workbench–> <dependency> <groupId>pro.shushi.pamirs.work.bench</groupId> <artifactId>pamirs-work-bench</artifactId> <version>${pamirs.workbench.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!–data-vi–> <dependency> <groupId>pro.shushi.pamirs.data.visualization</groupId> <artifactId>pamirs-data-visualization</artifactId> <version>${pamirs.data.visualization.version}</version> <type>pom</type> <scope>import</scope> </dependency> 完整功能依赖示例 以下列举了除了设计器相关依赖外的全部依赖管理项,其通常使用在启动工程POM中。 <dependency> <groupId>pro.shushi.pamirs</groupId> <artifactId>a</artifactId> </dependency>…

    2024年9月3日
    55800
  • Oinone平台部署及依赖说明(v5.1)

    概述 名词解释 业务工程包:指平台提供的内置基础包和内置功能包。 设计器工程包:指模型设计器、界面设计器、流程设计器等相关依赖包。 父POM:仅声明依赖包版本的pom文件 启动工程POM:仅声明具体依赖包的pom文件,一般不用于指定版本。 业务工程部署 Oinone平台向合作伙伴提供前后端业务工程所需的全部依赖,依赖项的具体说明下面会分别介绍。 设计器部署 Oinone平台向合作伙伴提供了两种设计器部署方式: Docker镜像:支持amd64和arm64两种架构的操作系统。(推荐) JAR包:与Docker镜像中的内容完全一致。 使用JAR包直接启动需要使用Oinone专属启动器,Docker镜像已内置Oinone专属启动器。 PS:如遇到以上部署方式或提供的镜像无法满足部署需求时,请联系Oinone平台售后获取技术支持。 Docker镜像 体验镜像 包括所有设计器。 内置所有所需中间件,包括Mysql、Redis、Zookeeper、RocketMQ。 适用场景:用于快速体验Oinone平台全部功能 docker pull harbor.oinone.top/oinone/oinone-designer-full-v5.1:TAG 前后端一体部署镜像 包括所有设计器。 无内置中间件。 适用场景:用于便捷部署Oinone平台的前后端服务 docker pull harbor.oinone.top/oinone/oinone-designer-mini-v5.1:TAG 前后端一体部署镜像 – 流程设计器 仅包括流程设计器。 无内置中间件。 适用场景:用于便捷部署仅需流程设计器的Oinone平台的前后端服务。 docker pull harbor.oinone.top/oinone/workflow-designer-v5.1:TAG 后端部署镜像 用于前后端分别部署,包括所有设计器。 仅包含后端服务 无内置中间件 适用场景:Kubenetes部署;支持健康检查,前后端分离部署; docker pull harbor.oinone.top/oinone/designer-backend-v5.1:TAG 前端部署镜像 用于前后端分别部署,包括所有设计器。 仅包含前端服务 无内置中间件 适用场景:Kubenetes部署;支持健康检查,前后端分离部署; docker pull harbor.oinone.top/oinone/designer-frontend-v5.1:TAG 镜像拉取 以体验镜像为例,Oinone平台提供多种拉取镜像的方式。 # 获取混合架构镜像,支持amd64和arm64架构的操作系统 docker pull harbor.oinone.top/oinone/oinone-designer-full-v5.1:5.1.13 # 仅获取amd64架构镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v5.1:5.1.13-amd64 # 仅获取arm64架构镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v5.1:5.1.13-arm64 # 获取最新版镜像(每次拉取自动更新) docker pull harbor.oinone.top/oinone/oinone-designer-full-v5.1 PS:如镜像拉取过慢,可在确定操作系统架构的情况下获取amd64或arm64架构镜像。 JAR包获取 $VERSION:对应镜像版本号 包含所有设计器的后端JAR包下载路径示例 https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/oinone-designer/pamirs-designer-boot-v5.1-$VERSION.jar 仅包含流程设计器的后端JAR包下载路径示例 https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/workflow-designer/pamirs-workflow-designer-boot-v5.1-$VERSION.jar Kubernetes后端部署健康检查 准备健康检查脚本 将以下脚本放置在镜像中。/opt/pamirs/bin/healthCheck.sh为以下示例中所用脚本路径。(平台提供的设计器镜像有内置该脚本,并与示例路径一致) #!/usr/bin/env bash function sendDingTalkMessage() { url=$DING_TALK_ROBOT_URL if [ -z $url ]; then return -1 fi message=$DING_TALK_ROBOT_MESSAGE if [ -z $message ]; then return -1 fi message="$message\\nby kubernetes" isAtAll=$DING_TALK_ROBOT_IS_AT_ALL if [ $isAtAll ]; then isAtAll="true" message="$message\\n" else isAtAll="false" fi message="{\"msgtype\": \"text\",\"text\": {\"content\":\"$message\"}, \"isAtAll\": \"${isAtAll}\"}" curl "${url}" -H 'Content-Type: application/json' -d "${message}" } port=$1 callback=$2 OK=$(curl -s http://127.0.0.1:${port}/ruok) if [ "$OK" == "imok" ]; then if [ -n $callback ]; then $callback fi exit 0 else exit 1 fi 配置Kubernetes健康检查 kind: Deployment apiVersion: apps/v1 spec: template: spec: containers: – name: designer-backend env: – name: DING_TALK_ROBOT_URL #…

    2024年9月18日
    89400
  • Oinone平台部署及依赖说明(v6.2)

    概述 名词解释 业务工程包:指平台提供的内置基础包和内置功能包。 设计器工程包:指模型设计器、界面设计器、流程设计器等相关依赖包。 父POM:仅声明依赖包版本的pom文件 启动工程POM:仅声明具体依赖包的pom文件,一般不用于指定版本。 业务工程部署 Oinone平台向合作伙伴提供前后端业务工程所需的全部依赖,依赖项的具体说明下面会分别介绍。 设计器部署 Oinone平台向合作伙伴提供了两种设计器部署方式: Docker镜像:支持amd64和arm64两种架构的操作系统。(推荐) JAR包:与Docker镜像中的内容完全一致。 使用JAR包直接启动需要使用Oinone专属启动器,Docker镜像已内置Oinone专属启动器。 PS:如遇到以上部署方式或提供的镜像无法满足部署需求时,请联系Oinone平台售后获取技术支持。 Docker镜像 体验镜像 包括所有设计器。 内置所有所需中间件,包括Mysql、Redis、Zookeeper、RocketMQ。 适用场景:用于快速体验Oinone平台全部功能 docker pull harbor.oinone.top/oinone/oinone-designer-full-v6.2:TAG 前后端一体部署镜像 包括所有设计器。 无内置中间件。 适用场景:用于便捷部署Oinone平台的前后端服务 docker pull harbor.oinone.top/oinone/oinone-designer-mini-v6.2:TAG 前后端一体部署镜像 – 流程设计器 仅包括流程设计器。 无内置中间件。 适用场景:用于便捷部署仅需流程设计器的Oinone平台的前后端服务。 docker pull harbor.oinone.top/oinone/workflow-designer-v6.2:TAG 后端部署镜像 用于前后端分别部署,包括所有设计器。 仅包含后端服务 无内置中间件 适用场景:Kubenetes部署;支持健康检查,前后端分离部署; docker pull harbor.oinone.top/oinone/designer-backend-v6.2:TAG 前端部署镜像 用于前后端分别部署,包括所有设计器。 仅包含前端服务 无内置中间件 适用场景:Kubenetes部署;支持健康检查,前后端分离部署; docker pull harbor.oinone.top/oinone/designer-frontend-v6.2:TAG 镜像拉取 以体验镜像为例,Oinone平台提供多种拉取镜像的方式。 # 获取混合架构镜像,支持amd64和arm64架构的操作系统 docker pull harbor.oinone.top/oinone/oinone-designer-full-v6.2:6.2.3.1 # 仅获取amd64架构镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v6.2:6.2.3.1-amd64 # 仅获取arm64架构镜像 docker pull harbor.oinone.top/oinone/oinone-designer-full-v6.2:6.2.3.1-arm64 # 获取最新版镜像(每次拉取自动更新) docker pull harbor.oinone.top/oinone/oinone-designer-full-v6.2 PS:如镜像拉取过慢,可在确定操作系统架构的情况下获取amd64或arm64架构镜像。 JAR包获取 $VERSION:对应镜像版本号 包含所有设计器的后端JAR包下载路径示例 https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/oinone-designer/pamirs-designer-boot-v6.2-$VERSION.jar 仅包含流程设计器的后端JAR包下载路径示例 https://oinone-jar.oss-cn-zhangjiakou.aliyuncs.com/install/workflow-designer/pamirs-workflow-designer-boot-v6.2-$VERSION.jar 后端依赖 Oinone平台后端使用Maven管理工具对所有依赖包进行版本管理。 版本说明 下面是在每个版本升级说明中提供的所有依赖版本,最新版本请查看对应的最新升级说明文档。 版本更新日志 <!– 平台基础 –> <oinone-bom.version>6.2.3.1</oinone-bom.version> <!– 设计器 –> <pamirs.workflow.designer.version>6.2.1</pamirs.workflow.designer.version> <pamirs.model.designer.version>6.2.3</pamirs.model.designer.version> <pamirs.ui.designer.version>6.2.3</pamirs.ui.designer.version> <pamirs.print.designer.version>6.2.1</pamirs.print.designer.version> <pamirs.data.designer.version>6.2.2</pamirs.data.designer.version> <pamirs.dataflow.designer.version>6.2.1</pamirs.dataflow.designer.version> <pamirs.eip.designer.version>6.2.1</pamirs.eip.designer.version> <pamirs.microflow.designer.version>6.2.1</pamirs.microflow.designer.version> <pamirs.ai.designer.version>6.2.1</pamirs.ai.designer.version> <dependencyManagement> <dependencies> <dependency> <groupId>pro.shushi</groupId> <artifactId>oinone-bom</artifactId> <version>${oinone.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 完整功能依赖示例 以下列举了除了设计器相关依赖外的全部依赖管理项,其通常使用在启动工程POM中。 <dependency> <groupId>pro.shushi.pamirs</groupId> <artifactId>a</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.boot</groupId> <artifactId>pamirs-boot-standard</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.framework</groupId> <artifactId>pamirs-framework-turbo-ee</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.framework</groupId> <artifactId>pamirs-framework-meta-virtual</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.metadata.manager</groupId> <artifactId>pamirs-metadata-manager</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.framework</groupId> <artifactId>pamirs-connectors-event-rocketmq</artifactId> </dependency> <!–<dependency>–> <!– <groupId>pro.shushi.pamirs.framework</groupId>–> <!– <artifactId>pamirs-connectors-event-kafka</artifactId>–> <!–</dependency>–> <!–<dependency>–> <!– <groupId>pro.shushi.pamirs.framework</groupId>–> <!– <artifactId>pamirs-connectors-event-rabbitmq</artifactId>–> <!–</dependency>–> <dependency> <groupId>pro.shushi.pamirs.boot</groupId> <artifactId>pamirs-distribution-id</artifactId> </dependency> <!–<dependency>–> <!– <groupId>pro.shushi.pamirs.distribution</groupId>–> <!– <artifactId>pamirs-distribution-faas</artifactId>–> <!–</dependency>–> <!–<dependency>–> <!– <groupId>pro.shushi.pamirs.distribution</groupId>–> <!– <artifactId>pamirs-distribution-gateway</artifactId>–> <!–</dependency>–> <!–<dependency>–> <!– <groupId>pro.shushi.pamirs.distribution</groupId>–> <!– <artifactId>pamirs-distribution-session</artifactId>–> <!–</dependency>–> <!–<dependency>–> <!– <groupId>pro.shushi.pamirs.distribution</groupId>–> <!– <artifactId>pamirs-distribution-session-cd</artifactId>–>…

    2025年6月20日
    3000
  • 开源日志平台:Graylog部署及接入

    一、部署Graylog Graylog总共需要3个服务:graylog服务端、mongodb(存储graylog的配置)、elasticSeach(存储日志)本文档部署方案介绍: graylog服务端、mongodb(存储graylog的配置)使用docker-compose部署 elasticSeach 引用外部地址 1. 安装docker、安装docker-compose 这部分直接参考互联网上的教程:链接 2. 通过docker-compose部署graylog 服务器上新建一个 graylog的目录,并在该目录下新建 docker-compose.yml version: '3' services: mongo: image: mongo:5.0 container_name: mongo volumes: – /data/docker/graylog/mongo_data:/data/db networks: – graylog ports: – 27017:27017 environment: – TZ=Asia/Shanghai healthcheck: test: ["CMD", "mongo", "–eval", "db.adminCommand('ping')"] interval: 30s timeout: 10s retries: 5 graylog: image: graylog/graylog:5.2 container_name: graylog depends_on: mongo: condition: service_healthy environment: – GRAYLOG_ROOT_PASSWORD_SHA2=xxxxx #sha2生成的密码,可以服务器通过命令获取:echo -n yournewpassword | sha256sum – GRAYLOG_PASSWORD_SECRET=xxxxx #随机生成的secret,长度超过32位,可以自己生成 – GRAYLOG_HTTP_ENABLE_TLS=false – GRAYLOG_TIMEZONE=Asia/Shanghai – GRAYLOG_MONGO_URI=mongodb://mongo:27017/graylog – GRAYLOG_ELASTICSEARCH_VERSION=7 – GRAYLOG_ELASTICSEARCH_HOSTS=http://es账户:es密码@es地址:9200 – GRAYLOG_ELASTICSEARCH_USER=es账户 – GRAYLOG_ELASTICSEARCH_PASSWORD=es密码 – GRAYLOG_HTTP_EXTERNAL_URI=http://访问地址/ – GRAYLOG_HTTP_PUBLISH_URI=http://访问地址/ – GRAYLOG_PLUGIN_SYSTEM_LANGUAGESELECTOR_DEFAULT_LOCALE=zh_CN – TZ=Asia/Shanghai networks: – graylog ports: – "9000:9000" – "514:514" – "514:514/udp" – "12201:12201" – "12201:12201/udp" volumes: mongo_data: driver: local graylog_data: driver: local networks: graylog: driver: bridge 上面的配置根据自己的环境,重新配置。注意点:elasticSearch如果存在账密的化,参考下GRAYLOG_ELASTICSEARCH_XXX这几个配置,进行调整。 3. 启动graylog # 1. 启动执行 docker-compose up -d # 2. 如果希望调整docker-compose.yml的配置,需要先关闭,再重启 ## 2.1 先关闭graylog的应用 docker-compose down ## 2.2 修改完文件后,再执行启动命令 docker-compose up -d # 3.查看启动日志,确认是否完成启动 docker logs mongo; docker logs graylog; 4. 配置graylog 日志传输,建议采用UDP协议,其次包括graylog的踩坑记录,参考如下文档:参考1参考2 二、java应用接入Graylog 1. pom新增依赖 <!–logback gelf日志收集–> <dependency> <groupId>biz.paluch.logging</groupId> <artifactId>logstash-gelf</artifactId> <version>1.15.0</version> </dependency> 2. 配置logback.xml文件,同时增加traceId、spanId方便链路日志的追踪 a. 配置 Logback 以支持 MDC,在 logback.xml 中配置 GelfLogbackAppender,并确保包括 traceId 和 spanId 字段: <configuration> <appender name="GELF" class="biz.paluch.logging.gelf.logback.GelfLogbackAppender"> <host>udp:graylog的地址</host> <!– graylog 服务器ip –> <port>graylog开放的端口</port>…

    2024年5月30日
    1.9K00

Leave a Reply

登录后才能评论