doc-exports/docs/fg/umn/functiongraph_04_0103.html
Chen, Junjie dac566cf2f FG UMN 20230725 version
Reviewed-by: Eotvos, Oliver <oliver.eotvos@t-systems.com>
Co-authored-by: Chen, Junjie <chenjunjie@huawei.com>
Co-committed-by: Chen, Junjie <chenjunjie@huawei.com>
2024-04-03 10:30:56 +00:00

126 lines
19 KiB
HTML

<a name="functiongraph_04_0103"></a><a name="functiongraph_04_0103"></a>
<h1 class="topictitle1">Developing an HTTP Function</h1>
<div id="body0000001250435134"><div class="section" id="functiongraph_04_0103__section6371173123910"><h4 class="sectiontitle">Introduction</h4><p id="functiongraph_04_0103__p2073745323917">When developing an HTTP function using a custom image, implement an HTTP server in the image and listen on <strong id="functiongraph_04_0103__b18712171162917">port 8000</strong> for requests. <strong id="functiongraph_04_0103__b4639203162910">(Do not change port 8000 in the examples provided in this section.)</strong> HTTP functions support only APIG triggers.</p>
</div>
<div class="section" id="functiongraph_04_0103__section0418520193311"><h4 class="sectiontitle">Step 1: Prepare the Environment</h4><p id="functiongraph_04_0103__functiongraph_04_0101_p722313491535">To perform the operations described in this section, ensure that you have the <strong id="functiongraph_04_0103__functiongraph_04_0101_b571115773214">FunctionGraph FullAccess</strong> permissions, that is, all permissions for FunctionGraph. For more information, see section "Permissions Management".</p>
</div>
<div class="section" id="functiongraph_04_0103__section992877392"><h4 class="sectiontitle">Step 2: Create an Image</h4><p id="functiongraph_04_0103__p068419143913">Take the Linux x86 64-bit OS as an example.</p>
</div>
<ol id="functiongraph_04_0103__ol4774141334018"><li id="functiongraph_04_0103__li977419139409">Create a folder.<pre class="screen" id="functiongraph_04_0103__screen3922727114118">mkdir custom_container_http_example &amp;&amp; cd custom_container_http_example</pre>
</li></ol><ol start="2" id="functiongraph_04_0103__ol1390513210407"><li id="functiongraph_04_0103__li11905021164011">Implement an HTTP server. Node.js is used as an example. For details about other languages, see section "Creating an HTTP Function".<p id="functiongraph_04_0103__p187921276440"><a name="functiongraph_04_0103__li11905021164011"></a><a name="li11905021164011"></a>Create the <strong id="functiongraph_04_0103__b917615137223">main.js</strong> file to introduce the Express framework, receive POST requests, print the request body as standard output, and return "Hello FunctionGraph, method POST" to the client.</p>
<pre class="screen" id="functiongraph_04_0103__screen133291853183612">const express = require('express');
const PORT = 8000;
const app = express();
app.use(express.json());
app.post('/*', (req, res) =&gt; {
console.log('receive', req.body);
res.send('Hello FunctionGraph, method POST');
});
app.listen(PORT, () =&gt; {
console.log(`Listening on http://localhost:${PORT}`);
});</pre>
</li></ol><ol start="3" id="functiongraph_04_0103__ol1035701334214"><li id="functiongraph_04_0103__li71011312114818">Create the <strong id="functiongraph_04_0103__b45845159255">package.json</strong> file for npm so that it can identify the project and process project dependencies.<pre class="screen" id="functiongraph_04_0103__screen1030904474017">{
"name": "custom-container-http-example",
"version": "1.0.0",
"description": "An example of a custom container http function",
"main": "main.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
}
}</pre>
<ul id="functiongraph_04_0103__ul9401719516"><li id="functiongraph_04_0103__li144021105119"><strong id="functiongraph_04_0103__b0528115182613">name</strong>: project name</li><li id="functiongraph_04_0103__li1354861819513"><strong id="functiongraph_04_0103__b58201618142618">version</strong>: project version</li><li id="functiongraph_04_0103__li71791629115113"><strong id="functiongraph_04_0103__b12899122716277">main</strong>: application entry file</li><li id="functiongraph_04_0103__li3728104885115"><strong id="functiongraph_04_0103__b529194813284">dependencies</strong>: all available dependencies of the project in npm</li></ul>
</li><li id="functiongraph_04_0103__li5357613144220">Create a Dockerfile.<pre class="screen" id="functiongraph_04_0103__screen16957194045310">FROM node:12.10.0
ENV HOME=/home/custom_container
ENV GROUP_ID=1003
ENV GROUP_NAME=custom_container
ENV USER_ID=1003
ENV USER_NAME=custom_container
RUN mkdir -m 550 ${HOME} &amp;&amp; groupadd -g ${GROUP_ID} ${GROUP_NAME} &amp;&amp; useradd -u ${USER_ID} -g ${GROUP_ID} ${USER_NAME}
COPY --chown=${USER_ID}:${GROUP_ID} main.js ${HOME}
COPY --chown=${USER_ID}:${GROUP_ID} package.json ${HOME}
RUN cd ${HOME} &amp;&amp; npm install
RUN chown -R ${USER_ID}:${GROUP_ID} ${HOME}
RUN find ${HOME} -type d | xargs chmod 500
RUN find ${HOME} -type f | xargs chmod 500
USER ${USER_NAME}
WORKDIR ${HOME}
EXPOSE 8000
ENTRYPOINT ["node", "main.js"]</pre>
<ul id="functiongraph_04_0103__ul10963114434217"><li id="functiongraph_04_0103__li29636447427"><strong id="functiongraph_04_0103__b448224192916">FROM</strong>: Specify base image <strong id="functiongraph_04_0103__b1612211144305">node:12.10.0</strong>. The base image is mandatory and its value can be changed.</li><li id="functiongraph_04_0103__li137654248557"><strong id="functiongraph_04_0103__b2037884919303">ENV</strong>: Set environment variables <strong id="functiongraph_04_0103__b13964925103119">HOME</strong> (<strong id="functiongraph_04_0103__b53161432183118">/home/custom_container</strong>), <strong id="functiongraph_04_0103__b2201173923114">GROUP_NAME</strong> and <strong id="functiongraph_04_0103__b867884223113">USER_NAME</strong> (<strong id="functiongraph_04_0103__b11632148143111">custom_container</strong>), <strong id="functiongraph_04_0103__b17649205417318">USER_ID</strong> and <strong id="functiongraph_04_0103__b87032572316">GROUP_ID</strong> (<strong id="functiongraph_04_0103__b148619112322">1003</strong>). These environment variables are mandatory and their values can be changed.</li><li id="functiongraph_04_0103__li198492020124718"><strong id="functiongraph_04_0103__b15681748203313">RUN</strong>: Use the format <strong id="functiongraph_04_0103__b165751855185917">RUN</strong> <em id="functiongraph_04_0103__i7791759145915">&lt;Command&gt;</em>. For example, <strong id="functiongraph_04_0103__b103103141105">RUN mkdir -m 550 ${HOME}</strong>, which means to create the <strong id="functiongraph_04_0103__b1197311301365">home</strong> directory for user <em id="functiongraph_04_0103__i5111756703">${USER_NAME}</em> during container building.</li><li id="functiongraph_04_0103__li15560499126"><strong id="functiongraph_04_0103__b663011916418">USER</strong>: Switch to user <em id="functiongraph_04_0103__i915717172417">${USER_NAME}</em>.</li><li id="functiongraph_04_0103__li1573427151310"><strong id="functiongraph_04_0103__b19838209415">WORKDIR</strong>: Switch the working directory to the <strong id="functiongraph_04_0103__b1257373613616">home</strong> directory of user <em id="functiongraph_04_0103__i9294143412418">${USER_NAME}</em>.</li><li id="functiongraph_04_0103__li11176163481315"><strong id="functiongraph_04_0103__b66071391958">COPY</strong>: Copy <strong id="functiongraph_04_0103__b850413507512">main.js</strong> and <strong id="functiongraph_04_0103__b752514521758">package.json</strong> to the <strong id="functiongraph_04_0103__b163271401665">home</strong> directory of user <em id="functiongraph_04_0103__i118382016620">${USER_NAME}</em> in the container.</li><li id="functiongraph_04_0103__li19963544104216"><strong id="functiongraph_04_0103__b79091013183016">EXPOSE: Expose port 8000 of the container. Do not change this parameter.</strong></li><li id="functiongraph_04_0103__li1799418920148"><strong id="functiongraph_04_0103__b486252713716">ENTRYPOINT</strong>: Run the <strong id="functiongraph_04_0103__b1891142474">node main.js</strong> command to start the container. Do not change this parameter.</li></ul>
<div class="note" id="functiongraph_04_0103__note17244712135519"><img src="public_sys-resources/note_3.0-en-us.png"><span class="notetitle"> </span><div class="notebody"><ol type="a" id="functiongraph_04_0103__ol16166128155510"><li id="functiongraph_04_0103__li18166162811556">You can use any base image.</li><li id="functiongraph_04_0103__li191661328155510">In the cloud environment, UID 1003 and GID 1003 are used to start the container by default. The two IDs can be modified by choosing <strong id="functiongraph_04_0103__b9425115012369">Configuration</strong> &gt; <strong id="functiongraph_04_0103__b116461947193611">Basic Settings</strong> &gt; <strong id="functiongraph_04_0103__b96917572361">Container Image Override</strong> on the function details page. They cannot be <strong id="functiongraph_04_0103__b1945814510375">root</strong> or a reserved ID.</li><li id="functiongraph_04_0103__li1544116347117"><strong id="functiongraph_04_0103__b210144718304">Do not change port 8000 in the example HTTP function.</strong></li></ol>
</div></div>
</li></ol><ol start="5" id="functiongraph_04_0103__ol12590173254310"><li id="functiongraph_04_0103__li65901932114317">Build an image.<p id="functiongraph_04_0103__p8688195019499"><a name="functiongraph_04_0103__li65901932114317"></a><a name="li65901932114317"></a>In the following example, the image name is <strong id="functiongraph_04_0103__b366523713718">custom_container_http_example</strong>, the tag is <strong id="functiongraph_04_0103__b632010713175">latest</strong>, and the period (.) indicates the directory where the Dockerfile is located. Run the image build command to pack all files in the directory and send the package to a container engine to build an image.</p>
<pre class="screen" id="functiongraph_04_0103__screen1356617348547">docker build -t custom_container_http_example:latest .</pre>
</li></ol>
<div class="section" id="functiongraph_04_0103__section14706131145612"><h4 class="sectiontitle">Step 3: Perform Local Verification</h4><ol id="functiongraph_04_0103__ol15219131615717"><li id="functiongraph_04_0103__li19219171614578">Start the Docker container.<pre class="screen" id="functiongraph_04_0103__screen32034014570">docker run -u 1003:1003 -p 8000:8000 custom_container_http_example:latest</pre>
</li></ol><ol start="2" id="functiongraph_04_0103__ol3221850579"><li id="functiongraph_04_0103__li32212511577">Open a new Command Prompt, and send a message through port 8000. You can access all paths in the root directory in the template code. The following uses <strong id="functiongraph_04_0103__b1639253712524">helloworld</strong> as an example.<pre class="screen" id="functiongraph_04_0103__screen207121444175712">curl -XPOST -H 'Content-Type: application/json' -d '{"message":"HelloWorld"}' localhost:8000/helloworld</pre>
<div class="p" id="functiongraph_04_0103__p11235659183714">The following information is returned based on the module code:<pre class="screen" id="functiongraph_04_0103__screen1265281710582">Hello FunctionGraph, method POST</pre>
</div>
</li></ol><ol start="3" id="functiongraph_04_0103__ol038443342215"><li id="functiongraph_04_0103__li891393415237">Check whether the following information is displayed:<pre class="screen" id="functiongraph_04_0103__screen4971414596">receive {"message":"HelloWorld"}</pre>
<p id="functiongraph_04_0103__p10679134518242"><span><img id="functiongraph_04_0103__image66790459247" src="en-us_image_0000001472516001.png"></span></p>
<p id="functiongraph_04_0103__p27663417249">Alternatively, run the <strong id="functiongraph_04_0103__b167381058686">docker logs</strong> command to obtain container logs.</p>
<p id="functiongraph_04_0103__p205727219252"><span><img id="functiongraph_04_0103__image1057222112516" src="en-us_image_0000001422359078.png"></span></p>
</li></ol>
</div>
<div class="section" id="functiongraph_04_0103__section15137197135915"><h4 class="sectiontitle">Step 4: Upload the Image</h4><ol id="functiongraph_04_0103__ol10526155517598"><li id="functiongraph_04_0103__li1280144911552">Log in to the SoftWare Repository for Container (SWR) console. In the navigation pane, choose <strong id="functiongraph_04_0103__b284013377486">My Images</strong>.</li><li id="functiongraph_04_0103__li19526145511590">Click <strong id="functiongraph_04_0103__b290678819">Upload Through Client</strong> or <strong id="functiongraph_04_0103__b888071310817">Upload Through SWR</strong> in the upper right corner.</li><li id="functiongraph_04_0103__li1169192171917">Upload the image as prompted.<p id="functiongraph_04_0103__p87902033161813"><a name="functiongraph_04_0103__li1169192171917"></a><a name="li1169192171917"></a></p>
<p id="functiongraph_04_0103__p125952020123114"><span><img id="functiongraph_04_0103__image35951420123110" src="en-us_image_0000001631149450.png"></span></p>
</li><li id="functiongraph_04_0103__li823013951820">View the image on the <strong id="functiongraph_04_0103__b1037115116454">My Images</strong> page.</li></ol>
</div>
<div class="section" id="functiongraph_04_0103__section12330203912578"><h4 class="sectiontitle">Step 5: Create a Function</h4><ol id="functiongraph_04_0103__ol18740710529"><li id="functiongraph_04_0103__li7794535128">In the left navigation pane of the management console, choose <strong id="functiongraph_04_0103__b19633164513554">Compute</strong> &gt; <strong id="functiongraph_04_0103__b2402184765512">FunctionGraph</strong>. On the FunctionGraph console, choose <strong id="functiongraph_04_0103__b6460359185317">Functions</strong> &gt; <strong id="functiongraph_04_0103__b12460165995320">Function List</strong> from the navigation pane.</li><li id="functiongraph_04_0103__li27941371211">Click <strong id="functiongraph_04_0103__b10524844175719">Create Function</strong> in the upper right corner and choose <strong id="functiongraph_04_0103__b2524944115719">Container Image</strong>.</li><li id="functiongraph_04_0103__li1176013361624">Set the basic information.<ul id="functiongraph_04_0103__ul1714016229416"><li id="functiongraph_04_0103__li9143162215418"><strong id="functiongraph_04_0103__b204921265912">Function Type</strong>: Select <strong id="functiongraph_04_0103__b18800117205911">HTTP Function</strong>.</li><li id="functiongraph_04_0103__li5121204615412"><strong id="functiongraph_04_0103__b34011251546">Function Name</strong>: Enter <strong id="functiongraph_04_0103__b540818519411">custom_container_http</strong>.</li><li id="functiongraph_04_0103__li11250348182118"><strong id="functiongraph_04_0103__b7196123811453">Container Image</strong>: Select the image uploaded to SWR. </li><li id="functiongraph_04_0103__li39981317382"><strong id="functiongraph_04_0103__b589546181414">Agency</strong>: Select an agency with the <strong id="functiongraph_04_0103__b168984616149">SWR Admin</strong> permission. If no agency is available, create one by referring to section "Creating an Agency".</li></ul>
</li><li id="functiongraph_04_0103__li1416383714911">After the configuration is complete, click <strong id="functiongraph_04_0103__b126491561320">Create Function</strong>.</li></ol>
</div>
<div class="section" id="functiongraph_04_0103__section623165141019"><h4 class="sectiontitle">Step 6: Test the Function</h4><ol id="functiongraph_04_0103__ol138801929154513"><li id="functiongraph_04_0103__li118801429194518">On the function details page, click <strong id="functiongraph_04_0103__b2018012013321">Test</strong>. In the displayed dialog box, create a test event.</li><li id="functiongraph_04_0103__li1355343014466">Select <strong id="functiongraph_04_0103__b1671117466314">apig-event-template</strong>, set <strong id="functiongraph_04_0103__b1171744693110">Event Name</strong> to <strong id="functiongraph_04_0103__b271715468314">helloworld</strong>, modify the test event as follows, and click <strong id="functiongraph_04_0103__b1171784633117">Create</strong>.<pre class="screen" id="functiongraph_04_0103__screen627810633110">{
"body": "{\"message\": \"helloworld\"}",
"requestContext": {
"requestId": "11cdcdcf33949dc6d722640a13091c77",
"stage": "RELEASE"
},
"queryStringParameters": {
"responseType": "html"
},
"httpMethod": "POST",
"pathParameters": {},
"headers": {
"Content-Type": "application/json"
},
"path": "/helloworld",
"isBase64Encoded": false
}</pre>
</li></ol>
</div>
<div class="section" id="functiongraph_04_0103__section109701256191214"><h4 class="sectiontitle">Step 7: View the Execution Result</h4><p id="functiongraph_04_0103__p852616631310">Click <strong id="functiongraph_04_0103__b14423165631016">Test</strong> and view the execution result on the right.</p>
<div class="fignone" id="functiongraph_04_0103__fig19835131516462"><span class="figcap"><b>Figure 1 </b>Execution result</span><br><span><img id="functiongraph_04_0103__image18836191584614" src="en-us_image_0000001422359706.png"></span></div>
<ul id="functiongraph_04_0103__ul1714875285210"><li id="functiongraph_04_0103__li20148952105216"><strong id="functiongraph_04_0103__b145531627183114">Function Output</strong>: displays the return result of the function.</li><li id="functiongraph_04_0103__li1659264116539"><strong id="functiongraph_04_0103__b65576304314">Log Output</strong>: displays the execution logs of the function.</li><li id="functiongraph_04_0103__li1014811523528"><strong id="functiongraph_04_0103__b17680163273115">Summary</strong>: displays key information of the logs.<div class="note" id="functiongraph_04_0103__note153221935131416"><img src="public_sys-resources/note_3.0-en-us.png"><span class="notetitle"> </span><div class="notebody"><p id="functiongraph_04_0103__functiongraph_04_0101_p1235012235414">A maximum of 2 KB logs can be displayed. For more log information, see section "Querying Function Logs".</p>
</div></div>
</li></ul>
</div>
<div class="section" id="functiongraph_04_0103__section0486613514"><h4 class="sectiontitle">Step 8: View Monitoring Metrics</h4><p id="functiongraph_04_0103__p17904185720618">On the function details page, click the <strong id="functiongraph_04_0103__functiongraph_04_0101_b1337097146">Monitoring</strong> tab.</p>
<ul id="functiongraph_04_0103__ul514673445811"><li id="functiongraph_04_0103__functiongraph_04_0101_li1814673415587">On the <strong id="functiongraph_04_0103__functiongraph_04_0101_b152431737165312">Monitoring</strong> tab page, choose <strong id="functiongraph_04_0103__functiongraph_04_0101_b17548418101316">Metrics</strong>, and select a time range (such as 5 minutes, 15 minutes, or 1 hour) to query the function.</li><li id="functiongraph_04_0103__functiongraph_04_0101_li88981734907">The following metrics are displayed: invocations, errors, duration (including the maximum, average, and minimum durations), and throttles.</li></ul>
</div>
<div class="section" id="functiongraph_04_0103__section5661458145412"><h4 class="sectiontitle">Step 9: Delete the Function</h4><ol id="functiongraph_04_0103__ol07481824023"><li id="functiongraph_04_0103__functiongraph_04_0101_li197481224129">On the function details page, choose <strong id="functiongraph_04_0103__functiongraph_04_0101_b6137103021213">Operation</strong> &gt; <strong id="functiongraph_04_0103__functiongraph_04_0101_b12443175210478">Delete Function</strong> in the upper right corner.</li><li id="functiongraph_04_0103__functiongraph_04_0101_li0745531425">In the confirmation dialog box, enter <strong id="functiongraph_04_0103__functiongraph_04_0101_b3374104583013">DELETE</strong> and click <strong id="functiongraph_04_0103__functiongraph_04_0101_b179661748143013">OK</strong> to release resources in a timely manner.</li></ol>
</div>
</div>
<div>
<div class="familylinks">
<div class="parentlink"><strong>Parent topic:</strong> <a href="functiongraph_04_0105.html">Deploying a Function Using a Container Image</a></div>
</div>
</div>