<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cloud Computing 雲端服務 &#8211; Ling&#039;s Note</title>
	<atom:link href="https://www.chunho-ling.com/category/computing/cloud-computing-%e9%9b%b2%e7%ab%af%e6%9c%8d%e5%8b%99/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.chunho-ling.com</link>
	<description>Everything related IT, and me.</description>
	<lastBuildDate>Tue, 15 Nov 2022 12:29:38 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>
<site xmlns="com-wordpress:feed-additions:1">104401516</site>	<item>
		<title>Cloud Design Pattern &#8211; Ambassador</title>
		<link>https://www.chunho-ling.com/cloud-design-pattern-ambassador/</link>
					<comments>https://www.chunho-ling.com/cloud-design-pattern-ambassador/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Tue, 15 Nov 2022 12:29:38 +0000</pubDate>
				<category><![CDATA[Cloud Computing 雲端服務]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[System Design 系統設計]]></category>
		<guid isPermaLink="false">https://www.chunho-ling.com/?p=1614</guid>

					<description><![CDATA[Ambassador is one of the Separation of Concern (SoC) implementation. In cloud platform, functional features (e.g. Business logic) and non-functional features (e.g. retry / queue / etc) are implement in multi-containers: main application and proxy. <a class="mh-excerpt-more" href="https://www.chunho-ling.com/cloud-design-pattern-ambassador/" title="Cloud Design Pattern &#8211; Ambassador">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>Ambassador is one of the Separation of Concern (SoC) implementation. In cloud platform, functional features (e.g. Business logic) and non-functional features (e.g. retry / queue / etc) are implement in multi-containers: main application and proxy.</p>
<p><span id="more-1614"></span></p>
<h1>Problem</h1>
<p>Most microservices might require non-functional feature such as queueing and retry, but it will become complicate when number of microservices increase and changes.</p>
<p>Also, some of the application might cannot be change (e.g. legacy / source code missing / external application) so it cannot be add these non-functional feature in application itself.</p>
<h1>Solution</h1>
<p>Setup the Ambassador proxy to handle non-functional feature, main applications are require to get request / send response via Ambassador.</p>
<h1><img data-recalc-dims="1" decoding="async" class="alignnone size-medium wp-image-1616" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2022/11/ambassador.png?resize=300%2C134&#038;ssl=1" alt="" width="300" height="134" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2022/11/ambassador.png?resize=300%2C134&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2022/11/ambassador.png?w=541&amp;ssl=1 541w" sizes="(max-width: 300px) 100vw, 300px" /></h1>
<h1>Use Case</h1>
<ol>
<li>Legacy application which cannot implement such non-functional feature;</li>
<li>Share non-functional feature in different application;</li>
</ol>
<h1>Implementation</h1>
<p>There are some tools which can role as ambassador, some representives as below:</p>
<ol>
<li>Envoy</li>
<li>Nginx</li>
</ol>
<h1>Consideration</h1>
<h2>Compare with Sidecar</h2>
<p>Sidecar is for each microservices and Ambassador can for group of microservices. As result, it is complex on manage each sidecar. For example, using Istio to centralize mange Envoy for each sidecar.</p>
<h2>Compare with Adaptor</h2>
<p>Adaptor is transform request / response between microservices and caller. Majorly it is for legacy application but it do not provide additional non-functional feature.</p>
<h1>Reference:</h1>
<ol>
<li>The Distributed System ToolKit: Patterns for Composite Containers, Kubernetes Blog<br />
<a href="https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/" target="_blank" rel="noopener">https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns/</a></li>
<li>Ambassador pattern, Microsoft Learn<br />
<a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador" target="_blank" rel="noopener">https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador</a></li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/cloud-design-pattern-ambassador/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1614</post-id>	</item>
		<item>
		<title>[AWS] Create file checksum file when S3 Object uploaded</title>
		<link>https://www.chunho-ling.com/aws-create-file-checksum-file-when-s3-object-uploaded/</link>
					<comments>https://www.chunho-ling.com/aws-create-file-checksum-file-when-s3-object-uploaded/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Mon, 16 Aug 2021 07:15:34 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud Computing 雲端服務]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Gradle]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Lambda Function]]></category>
		<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">https://www.chunho-ling.com/?p=1400</guid>

					<description><![CDATA[Checksum ensure the integrity of file. In AWS S3, it also using eTag to do similar things. It create MD5 value and store in eTag. However, it is not a real checksum for s3 object <a class="mh-excerpt-more" href="https://www.chunho-ling.com/aws-create-file-checksum-file-when-s3-object-uploaded/" title="[AWS] Create file checksum file when S3 Object uploaded">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>Checksum ensure the integrity of file. In AWS S3, it also using eTag to do similar things. It create MD5 value and store in eTag. However, it is not a real checksum for s3 object itself. It incudes s3 object metadata. As result, it might not the same if download file and generate checksum by own.</p>
<p>To create a real file checksum, it can be done by Lambda trigger. With lambda function, it can create trigger to execute task when file uploaded. This demo, it it will use Java to create lambda trigger to create MD5 and SHA-256 checksum.<span id="more-1400"></span></p>
<h1>Pre-requests</h1>
<ol>
<li>AWS account should has sufficient privilege to create lambda function and list s3 buckets;</li>
<li>User account for execute Lambda function should be configurated;</li>
</ol>
<h1>Steps</h1>
<ol>
<li>Create Lambda function.<br />
In AWS Management Console, click <strong>Create Function</strong>, input Function name and select Runtime to <strong>Java 11 (Corretto)</strong>, then click <strong>Create Function</strong>.<br />
<img data-recalc-dims="1" decoding="async" class="alignnone size-medium wp-image-1401" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?resize=300%2C138&#038;ssl=1" alt="" width="300" height="138" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?resize=300%2C138&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?resize=1024%2C471&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?resize=768%2C353&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?resize=1536%2C706&amp;ssl=1 1536w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?w=1807&amp;ssl=1 1807w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_21_34-Window.png?w=1356&amp;ssl=1 1356w" sizes="(max-width: 300px) 100vw, 300px" /></li>
<li>Add Trigger<br />
Open created trigger, click <strong>Add trigger</strong>.<br />
<img data-recalc-dims="1" decoding="async" class="alignnone size-medium wp-image-1403" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_27_37-s3-object-sha-256-Lambda-Brave.png?resize=300%2C114&#038;ssl=1" alt="" width="300" height="114" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_27_37-s3-object-sha-256-Lambda-Brave.png?resize=300%2C114&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_27_37-s3-object-sha-256-Lambda-Brave.png?w=758&amp;ssl=1 758w" sizes="(max-width: 300px) 100vw, 300px" /></li>
<li>Configure new trigger<br />
In Add trigger menu, select <strong>S3</strong> as trigger, then select target bucket in <strong>Bucket</strong> dropdown. Optionally, it can add s3 object key prefix and suffix in Prefix and suffix textbox.<br />
After tick <strong>Recursive invocation</strong> consent, click <strong>Add</strong>.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1402" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_26_20-Lambda-Brave.png?resize=287%2C300&#038;ssl=1" alt="" width="287" height="300" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_26_20-Lambda-Brave.png?resize=287%2C300&amp;ssl=1 287w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_26_20-Lambda-Brave.png?resize=768%2C802&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_26_20-Lambda-Brave.png?w=834&amp;ssl=1 834w" sizes="auto, (max-width: 287px) 100vw, 287px" /></li>
<li>Create gradle library project<br />
In command prompt / terminal create project with gradle command as below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell">gradle init</pre>
</li>
<li>Add dependency.<br />
In build.gradle, add line below to setup dependency and build task.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="groovy">dependencies {
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.1'
    implementation 'com.amazonaws:aws-lambda-java-events:3.9.0'
    runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.2.0'

    implementation 'software.amazon.awssdk:s3:2.17.9'

    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
}

task("buildZip", type: Zip) {
    from compileJava
    from processResources
    into("lib") {
        from configurations.runtimeClasspath
    }
}

test {
    useJUnitPlatform()
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

build.dependsOn buildZip
</pre>
</li>
<li>Add handler.<br />
Create new class file named GenerateChecksumEventHandler and add code below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="java">import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.ResponseBytes;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class ChecksumEventHandler implements RequestHandler&lt;S3EventNotification, Void&gt; {
    private static final String ENVIRONMENT_VARIABLE_ACCESS_KEY_ID="ACCESS_KEY_ID";
    private static final String ENVIRONMENT_VARIABLE_SECRET_ACCESS_KEY=SECRET_ACCESS_KEY";

    @Override
    public Void handleRequest(S3EventNotification input, Context context) {
        // Initial settings.
        LambdaLogger logger = context.getLogger();
        String s3AccessKeyId = System.getenv(ENVIRONMENT_VARIABLE_L2_REMOTE_ACCESS_KEY_ID);
        String s3SecretAccessKey = System.getenv(ENVIRONMENT_VARIABLE_L2_REMOTE_SECRET_ACCESS_KEY);

        // Connect to s3 with specific access key and secret access key which store in environment variable.
        AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(
                s3AccessKeyId,
                s3SecretAccessKey);
        S3Client s3Client = S3Client.builder().credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).build();

        // Loop with uploaded files.
        input.getRecords().forEach(o-&gt; {
            // Get related s3 object metadata and content.
            String bucketName = o.getS3().getBucket().getName();
            String objectKey = o.getS3().getObject().getKey();
            GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName).key(objectKey).build();
            ResponseBytes&lt;GetObjectResponse&gt; response = s3Client.getObjectAsBytes(getObjectRequest);
            InputStream objectByte = new ByteArrayInputStream(response.asByteArray());

            // Generate checksum file and store in same bucket.
            generateChecksumFile(logger, bucketName, objectKey, objectByte, "MD5", "md5", s3Client);
            generateChecksumFile(logger, bucketName, objectKey, objectByte, "SHA-256", "sha256", s3Client);
        });
        return null;
    }

    /**
     * Generate checksum with specific algorithm.
     * @param logger injected logger.
     * @param bucketName s3 bucket name.
     * @param objectKey s3 object key name.
     * @param inputStream s3 object input stream.
     * @param algorithm checksum algorithm required.
     * @param fileExtension checksum file extension.
     * @param s3Client injected s3 client.
     */
    private void generateChecksumFile(LambdaLogger logger, String bucketName, String objectKey, InputStream inputStream, String algorithm, String fileExtension, S3Client s3Client) {
        try {
            inputStream.reset();
            String checksum = generateChecksum(inputStream, algorithm);
            logger.log(algorithm+ " checksum = "+ checksum);
            String checksumObjectName = objectKey+ "." +fileExtension;
            RequestBody s3ObjectBody = RequestBody.fromString(checksum);
            PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(bucketName).key(checksumObjectName).build();
            PutObjectResponse putObjectResponse = s3Client.putObject(putObjectRequest, s3ObjectBody);
            logger.log("Checksum stored and upload to bucket "+bucketName+"; path = "+ checksumObjectName+ ", e-tag = "+putObjectResponse.eTag()+".");
        } catch (NoSuchAlgorithmException | IOException e) {
            logger.log(e.getMessage());
            logger.log(Arrays.toString(e.getStackTrace()));
        }
    }

    /**
     * Generate checksum with specific algorithm.
     * @param inputStream object stream to be hash.
     * @param algorithm checksum algorithm.
     * @return Checksum in string format.
     * @throws NoSuchAlgorithmException Invalid input algorithm.
     * @throws IOException Exception when read / write byte.
     */
    private String generateChecksum(InputStream inputStream, String algorithm) throws NoSuchAlgorithmException, IOException {
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);

        DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest);
        byte[] buffer = new byte[4096];
        int count = 0;
        while (digestInputStream.read(buffer) &gt; -1) {
            count++;
        }
        MessageDigest digest = digestInputStream.getMessageDigest();
        digestInputStream.close();

        byte[] checksum = digest.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : checksum) {
            sb.append(String.format("%02X", b));
        }
        return sb.toString().toUpperCase();
    }
}
</pre>
<p>As it will generate file and upload to s3 bucket, so it is required to use AWS SDK and put object permission.</li>
<li>Build distributed file.<br />
In command prompt / terminal, execute command below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell">gradle clean buildZip</pre>
</li>
<li>Upload file.<br />
In Lambda function, select <strong>Code</strong> tab, click <strong>Upload From</strong> &gt;<strong> zip of jar file</strong>, select built file and upload it.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1405" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_50_36-s3-object-sha-256-Lambda-Brave.png?resize=300%2C127&#038;ssl=1" alt="" width="300" height="127" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_50_36-s3-object-sha-256-Lambda-Brave.png?resize=300%2C127&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_50_36-s3-object-sha-256-Lambda-Brave.png?resize=768%2C326&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_50_36-s3-object-sha-256-Lambda-Brave.png?w=912&amp;ssl=1 912w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Add credential.<br />
In lambda function, select <strong>Configuration</strong> &gt; <strong>Environment variables</strong>, click <strong>Edit</strong>, then add parameter below and set access key and secret key.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1404" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_47_47-Edit-environment-variables-s3-object-sha-256-Lambda-Brave.png?resize=300%2C189&#038;ssl=1" alt="" width="300" height="189" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_47_47-Edit-environment-variables-s3-object-sha-256-Lambda-Brave.png?resize=300%2C189&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_47_47-Edit-environment-variables-s3-object-sha-256-Lambda-Brave.png?resize=768%2C483&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_47_47-Edit-environment-variables-s3-object-sha-256-Lambda-Brave.png?w=845&amp;ssl=1 845w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Create Test<br />
In lambda function, select <strong>Test</strong> tab, click <strong>new event</strong> and input event name, then input json below. Beware bucket name, arn and object key should align with triggered s3 bucket and its object.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1406" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?resize=300%2C142&#038;ssl=1" alt="" width="300" height="142" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?resize=300%2C142&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?resize=1024%2C486&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?resize=768%2C365&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?resize=1536%2C729&amp;ssl=1 1536w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?w=1599&amp;ssl=1 1599w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-14_53_40-s3-object-sha-256-Lambda-Brave.png?w=1356&amp;ssl=1 1356w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "ap-southeast-1",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "requestParameters": {
        "sourceIPAddress": "127.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
      },
      "s3": {
        "bucket": {
          "name": "test-bucket",
          "arn": "arn:aws:s3:::test-bucket"
        },
        "object": {
          "key": "test.zip"
        }
      }
    }
  ]
}</pre>
</li>
<li>Execute test.<br />
Click <strong>Test</strong> to execute test, expected it will result success.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1407" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?resize=300%2C133&#038;ssl=1" alt="" width="300" height="133" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?resize=300%2C133&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?resize=1024%2C455&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?resize=768%2C341&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?resize=1536%2C682&amp;ssl=1 1536w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?w=1587&amp;ssl=1 1587w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2021/08/2021-08-16-15_00_10-s3-object-sha-256-Lambda-Brave.png?w=1356&amp;ssl=1 1356w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/aws-create-file-checksum-file-when-s3-object-uploaded/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1400</post-id>	</item>
		<item>
		<title>[SpringBoot] Add custom metric in spring boot application and show in AWS CloudWatch</title>
		<link>https://www.chunho-ling.com/springboot-add-custom-metric-in-spring-boot-application-and-show-in-aws-cloudwatch/</link>
					<comments>https://www.chunho-ling.com/springboot-add-custom-metric-in-spring-boot-application-and-show-in-aws-cloudwatch/#comments</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Thu, 26 Nov 2020 06:39:51 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud Computing 雲端服務]]></category>
		<category><![CDATA[CloudWatch]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Spring MVC]]></category>
		<guid isPermaLink="false">https://www.chunho-ling.com/?p=1275</guid>

					<description><![CDATA[Application Performance Monitoring is one of the method to ensure application&#8217;s availability and status. However, most of them only can check the platform status (e.g. CPU usage / Thread / Memory / etc), some organization <a class="mh-excerpt-more" href="https://www.chunho-ling.com/springboot-add-custom-metric-in-spring-boot-application-and-show-in-aws-cloudwatch/" title="[SpringBoot] Add custom metric in spring boot application and show in AWS CloudWatch">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>Application Performance Monitoring is one of the method to ensure application&#8217;s availability and status. However, most of them only can check the platform status (e.g. CPU usage / Thread / Memory / etc), some organization will define application healthiness with some custom business logic (e.g. no. of order failure, etc) to indicate its perform normal or not.</p>
<p>In this demo, it will use springboot actuator to capture metric and AWS cloudwatch to render it out.<span id="more-1275"></span>Steps as below:</p>
<ol>
<li>Add related library.<br />
In build.gradle, add dependency as below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.cloud:spring-cloud-starter-aws:2.2.5.RELEASE')
    compile('org.springframework.boot:spring-boot-starter-aop')
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile('org.springframework.cloud:spring-cloud-aws-actuator:2.2.5.RELEASE')
}</pre>
</li>
<li>Add annotation in Main application.<br />
In application.java, alter code as below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-title="application.java">@EnableAspectJAutoProxy
@SpringBootApplication
@EnableAutoConfiguration(exclude = {ContextInstanceDataAutoConfiguration.class})
@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
</pre>
<p>&nbsp;</li>
<li>Create metrics and register in Meter Registry.<br />
Create controller DiagnoisisController and alter code as below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="java" data-enlighter-title="DiagnosisController.java">@RestController("DiagnosisController")
@RequestMapping(value ="/v1/diagnosis")
public class DiagnosisController {
    @Autowired
    DiagnosisService diagnosisService;

    public static final long METRIC_RELOAD_INTERVAL=10000;
    public static final String METRIC CLIENT_COUNT="connection.count";
    public static final String METRIC_THALES_CLIENT_COMPLETED_TASK_COUNT="client.completed.tasks";

    private final AtomicInteger currentHsmClientCount;
    private final Counter currentThalesClientCompletedTaskCount;

    public DiagnosisController(MeterRegistry meterRegistry) throws Exception {
        currentHsmClientCount=meterRegistry.gauge(METRIC_HSM_CLIENT_COUNT, new AtomicInteger());
        currentThalesClientCompletedTaskCount= Counter.builder(METRIC_THALES_CLIENT_COMPLETED_TASK_COUNT).description("Thales client completed tasks.").register(meterRegistry);
    }

    @Scheduled(fixedRate = METRIC_RELOAD_INTERVAL)
    public void updateMetric() throws Throwable {
        ServiceStatus serviceStatus=diagnosisService.status(false);
        currentHsmClientCount.set(serviceStatus.getCurrentClientCount());
        currentThalesClientCompletedTaskCount.increment(serviceStatus.getCurrentClientCompletedTaskCount());
    }
}</pre>
<p>Method updateMetric() is used to update metric value with schedule job. Normally it can return object count / size, but my case is return service response so it&#8217;s not valid in there.</li>
<li>Add AWS metric properties.<br />
In application.properties, add settings as below.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">## Springboot Actuator settings.
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=*
management.health.db.enabled=true

## AWS Cloudwatch settings.
cloud.aws.region.static=[[AWS available zone code]]
cloud.aws.stack.auto = false
management.metrics.export.cloudwatch.namespace=[Display name in CloudWatch]
management.metrics.export.cloudwatch.batchSize=20</pre>
</li>
<li>Check result locally.<br />
Run debug in IDE, open /actuator/metrics/ , see custom metric found or not. Expected it is exists.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1277" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-10_43_55-Mozilla-Firefox.png?resize=300%2C158&#038;ssl=1" alt="" width="300" height="158" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-10_43_55-Mozilla-Firefox.png?resize=300%2C158&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-10_43_55-Mozilla-Firefox.png?w=400&amp;ssl=1 400w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Check result in CloudWatch<br />
After deploy to AWS EC2 instance, CloudWatch will capture metric automatically.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1279" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-14_36_33-Window.png?resize=300%2C120&#038;ssl=1" alt="" width="300" height="120" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-14_36_33-Window.png?resize=300%2C120&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-14_36_33-Window.png?resize=1024%2C409&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-14_36_33-Window.png?resize=768%2C307&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-14_36_33-Window.png?w=1496&amp;ssl=1 1496w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/11/2020-11-26-14_36_33-Window.png?w=1356&amp;ssl=1 1356w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/springboot-add-custom-metric-in-spring-boot-application-and-show-in-aws-cloudwatch/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1275</post-id>	</item>
		<item>
		<title>[DevOps] Publish Java package to AWS CodeArtifact</title>
		<link>https://www.chunho-ling.com/devops-publish-java-package-to-aws-codeartifact/</link>
					<comments>https://www.chunho-ling.com/devops-publish-java-package-to-aws-codeartifact/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Wed, 16 Sep 2020 08:54:59 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud Computing 雲端服務]]></category>
		<category><![CDATA[Code Artifacts]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">https://www.chunho-ling.com/?p=1250</guid>

					<description><![CDATA[AWS CodeArtifact is one of the AWS devops feature for package management. Even compare with NexusOSS, it cannot upload package manually, but it still worth to use if using AWS as DevOps Platform.In this demo, <a class="mh-excerpt-more" href="https://www.chunho-ling.com/devops-publish-java-package-to-aws-codeartifact/" title="[DevOps] Publish Java package to AWS CodeArtifact">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>AWS CodeArtifact is one of the AWS devops feature for package management. Even compare with NexusOSS, it cannot upload package manually, but it still worth to use if using AWS as DevOps Platform.<span id="more-1250"></span>In this demo, it will show how to config Java project (Maven / Gradle) to publish to CodeArtifact.</p>
<ol>
<li>Create AWS CodeArtifact Domain.<br />
In AWS CodeArtifact, select <strong>Domains</strong> &gt; <strong>Create Domain</strong>. Input domain name and click button <strong>Create Domain</strong>.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1251" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?resize=300%2C226&#038;ssl=1" alt="" width="300" height="226" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?resize=300%2C226&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?resize=768%2C579&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?resize=678%2C509&amp;ssl=1 678w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?resize=326%2C245&amp;ssl=1 326w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?resize=80%2C60&amp;ssl=1 80w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_40_41-Window.png?w=830&amp;ssl=1 830w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Create Repository.<br />
In AWS CodeArtifact, select <strong>Repository</strong> &gt; <strong>Create Repository</strong>, input <strong>Repository name</strong> and click <strong>Next</strong>.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1252" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_46_29-Window.png?resize=300%2C174&#038;ssl=1" alt="" width="300" height="174" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_46_29-Window.png?resize=300%2C174&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_46_29-Window.png?resize=1024%2C593&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_46_29-Window.png?resize=768%2C445&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_46_29-Window.png?w=1090&amp;ssl=1 1090w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Select Repository&#8217;s domain.<br />
Select AWS account to <strong>This AWS account</strong> and select related Domain, then click <strong>Next</strong>.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1253" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_54_33-Window.png?resize=300%2C128&#038;ssl=1" alt="" width="300" height="128" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_54_33-Window.png?resize=300%2C128&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_54_33-Window.png?resize=1024%2C439&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_54_33-Window.png?resize=768%2C329&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_54_33-Window.png?resize=1030%2C438&amp;ssl=1 1030w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_54_33-Window.png?w=1067&amp;ssl=1 1067w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Confirm repository settings and create.<br />
After review settings, then click <strong>Create Repository</strong>.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1254" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_55_50-Window.png?resize=300%2C185&#038;ssl=1" alt="" width="300" height="185" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_55_50-Window.png?resize=300%2C185&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_55_50-Window.png?resize=1024%2C633&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_55_50-Window.png?resize=768%2C475&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-15_55_50-Window.png?w=1063&amp;ssl=1 1063w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Setup Maven repository settings for local computer<br />
Create file setting.xml in %USER%\.m2\</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">&lt;settings&gt;
  &lt;servers&gt;
    &lt;server&gt;
      &lt;id&gt;CodeArtifact&lt;/id&gt;
      &lt;username&gt;aws&lt;/username&gt;
      &lt;password&gt;${env.CODEARTIFACT_AUTH_TOKEN}&lt;/password&gt;
    &lt;/server&gt;
    &lt;/servers&gt;
&lt;mirrors&gt;
  &lt;mirror&gt;
    &lt;id&gt;CodeArtifact&lt;/id&gt;
    &lt;name&gt;CodeArtifact&lt;/name&gt;
    &lt;url&gt;https://{{domain-name}}-{{domain-id}}.d.codeartifact.ap-southeast-1.amazonaws.com/maven/{{repo-name}}/&lt;/url&gt;
    &lt;mirrorOf&gt;*&lt;/mirrorOf&gt;
  &lt;/mirror&gt;
&lt;/mirrors&gt;
&lt;/settings&gt;</pre>
</li>
<li>Generate AWS authentication token and store in variable.<br />
In command prompt / bash, execute command and store variable in CODEARTIFACT_AUTH_TOKEN.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">:: For Windows:
FOR /F "tokens=*" %a in ('aws codeartifact get-authorization-token --domain {{domain-name}} --domain-owner {{domain-id}} --query authorizationToken --output text') do SET CODEARTIFACT_AUTH_TOKEN=%a

:: For Linux: 
export CODEARTIFACT_AUTH_TOKEN=`aws codeartifact get-authorization-token --domain {{domain-name}} --domain-owner {{domain-id}} --query authorizationToken --output text`</pre>
</li>
<li>Update project settings.<br />
Edit pom.xml (for Maven project) / build.gradle (for Gradle project).<br />
pom.xml</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">&lt;project&gt;
...
  &lt;groupId&gt;com.test&lt;/groupId&gt;
  &lt;artifactId&gt;demo&lt;/artifactId&gt;
  &lt;version&gt;1.0.1&lt;/version&gt;
  &lt;packaging&gt;jar&lt;/packaging&gt;
  &lt;name&gt;demo&lt;/name&gt;
...
  &lt;distributionManagement&gt;
  	&lt;repository&gt;
        &lt;id&gt;d-sg-2--d-sg-ca-repo&lt;/id&gt;
        &lt;name&gt;aws-codeArtifact&lt;/name&gt;
        &lt;url&gt;https://{{domain-name}}-{{domain-id}}.d.codeartifact.ap-southeast-1.amazonaws.com/maven/{{repo-name}}/&lt;/url&gt;
  	&lt;/repository&gt;
  &lt;/distributionManagement&gt;
...
&lt;/project&gt;</pre>
<p>build.gradle</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">...
plugins {
    id 'maven-publish'
}
...
ext {
    // Package metadata.
    packageGroup = 'com.test'
    artifact='demo'
    packageName = 'demo'
    packageVersion = '1.0.1'
}
...
repositories {
    //mavenCentral()
    //mavenLocal()
    maven {
      url 'https://{{domain-name}}-{{domain-id}}.d.codeartifact.ap-southeast-1.amazonaws.com/maven/{{repo-name}}/'
      credentials {
          username "aws"
          password System.env.CODEARTIFACT_AUTH_TOKEN
      }
    }
}
...
publishing {
    publications {
        mavenJava(MavenPublication) {
        	groupId="${packageGroup}"
            artifactId="${packageName}"
            version="${packageVersion}"
            from components.java
        }
    }
    repositories {
      // AWS CodeArtifact
      maven {
          url 'https://{{domain-name}}-{{domain-id}}.d.codeartifact.ap-southeast-1.amazonaws.com/maven/{{repo-name}}/'
          credentials {
              username "aws"
              password System.env.CODEARTIFACT_AUTH_TOKEN
          }
      }
    }
}
...</pre>
</li>
<li>Publish to AWS CodeArtifact.<br />
In command prompt / bash, execute command.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">::Maven project.
mvn deploy

::Gradle project.
gradle publish</pre>
<p><img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1256" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_53_04-Window.png?resize=300%2C124&#038;ssl=1" alt="" width="300" height="124" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_53_04-Window.png?resize=300%2C124&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_53_04-Window.png?resize=768%2C316&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_53_04-Window.png?w=787&amp;ssl=1 787w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
<li>Verify delivery.<br />
In CodeArtifact, click Repositories &gt; select repository, see published package found or not.<br />
<img data-recalc-dims="1" loading="lazy" decoding="async" class="alignnone size-medium wp-image-1255" src="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_51_11-Window.png?resize=300%2C115&#038;ssl=1" alt="" width="300" height="115" srcset="https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_51_11-Window.png?resize=300%2C115&amp;ssl=1 300w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_51_11-Window.png?resize=1024%2C394&amp;ssl=1 1024w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_51_11-Window.png?resize=768%2C295&amp;ssl=1 768w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_51_11-Window.png?w=1504&amp;ssl=1 1504w, https://i0.wp.com/www.chunho-ling.com/wp-content/uploads/2020/09/2020-09-16-16_51_11-Window.png?w=1356&amp;ssl=1 1356w" sizes="auto, (max-width: 300px) 100vw, 300px" /></li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/devops-publish-java-package-to-aws-codeartifact/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1250</post-id>	</item>
		<item>
		<title>[Cloud Computing] NextCloud</title>
		<link>https://www.chunho-ling.com/cloud-computing-nextcloud/</link>
					<comments>https://www.chunho-ling.com/cloud-computing-nextcloud/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Tue, 06 Dec 2016 02:31:32 +0000</pubDate>
				<category><![CDATA[Cloud Computing 雲端服務]]></category>
		<category><![CDATA[End User Environment 用戶環境]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=318</guid>

					<description><![CDATA[現在Cloud Computing 技術日漸成熟, 其實說到底, 就是讓user在一個平台(Platform)上做到要做的事情, 例如Google 和Microsoft 這類人人都可以用的公有雲(Public Cloud), 除了email, calendar 還有 file storage / editing 這類軟件即服務 (Software-as-a-Service, SaaS). 然而, 在若果將業務放到公有雲上, 雖然一次性的建立成本會低, 但其營運成本便相對較高, 除了服務費用 (Service Charge), 替換成本(Switching Cost)及將公司敏感資料放到網上而洩密(Data leakage)等風險成本亦會出現. 因此, 部份公司亦會決定自己架構私有雲(Private Cloud). 若要做到類似Google 和Microsoft 相類似的話, <a class="mh-excerpt-more" href="https://www.chunho-ling.com/cloud-computing-nextcloud/" title="[Cloud Computing] NextCloud">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>現在Cloud Computing 技術日漸成熟, 其實說到底, 就是讓user在一個平台(Platform)上做到要做的事情, 例如Google 和Microsoft 這類人人都可以用的公有雲(Public Cloud), 除了email, calendar 還有 file storage / editing 這類軟件即服務 (Software-as-a-Service, SaaS).</p>
<p>然而, 在若果將業務放到公有雲上, 雖然一次性的建立成本會低, 但其營運成本便相對較高, 除了服務費用 (Service Charge), 替換成本(Switching Cost)及將公司敏感資料放到網上而洩密(Data leakage)等風險成本亦會出現. 因此, 部份公司亦會決定自己架構私有雲(Private Cloud). 若要做到類似Google 和Microsoft 相類似的話, 首推NextCloud.<span id="more-318"></span></p>
<p>NextCloud 是一套Opensource platform 可以存取檔案, 聯絡人, 行事曆, 還可以加建add-on, 加入email client / GPX tracker 等, 方便地打造適合自己使用的平台.</p>
<p>Reference</p>
<ul>
<li><a href="https://nextcloud.com/" target="_blank">NextCloud</a></li>
<li><a href="https://apps.nextcloud.com/" target="_blank">AppStore</a>, NextCloud</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/cloud-computing-nextcloud/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">318</post-id>	</item>
	</channel>
</rss>
