Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php on line 6131

Deprecated: Creation of dynamic property ACF::$fields is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields.php on line 138

Deprecated: Creation of dynamic property acf_loop::$loops is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/loop.php on line 28

Deprecated: Creation of dynamic property ACF::$loop is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/loop.php on line 269

Deprecated: Creation of dynamic property ACF::$revisions is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/revisions.php on line 397

Deprecated: Creation of dynamic property acf_validation::$errors is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/validation.php on line 28

Deprecated: Creation of dynamic property ACF::$validation is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/validation.php on line 214

Deprecated: Creation of dynamic property acf_form_customizer::$preview_values is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-customizer.php on line 28

Deprecated: Creation of dynamic property acf_form_customizer::$preview_fields is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-customizer.php on line 29

Deprecated: Creation of dynamic property acf_form_customizer::$preview_errors is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-customizer.php on line 30

Deprecated: Creation of dynamic property ACF::$form_front is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-front.php on line 598

Deprecated: Creation of dynamic property acf_form_widget::$preview_values is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-widget.php on line 34

Deprecated: Creation of dynamic property acf_form_widget::$preview_reference is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-widget.php on line 35

Deprecated: Creation of dynamic property acf_form_widget::$preview_errors is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/forms/form-widget.php on line 36

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the all-in-one-wp-migration domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php on line 6131

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp_plugin/wp_plugin.php on line 23

Deprecated: str_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp-super-cache/wp-cache-phase2.php on line 54

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp-super-cache/wp-cache-phase2.php on line 1539

Deprecated: strtolower(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/wp-super-cache/wp-cache-phase2.php on line 828

Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the rocket domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php on line 6131

Deprecated: Creation of dynamic property acf_field_oembed::$width is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-oembed.php on line 31

Deprecated: Creation of dynamic property acf_field_oembed::$height is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-oembed.php on line 32

Deprecated: Creation of dynamic property acf_field_google_map::$default_values is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-google-map.php on line 33

Deprecated: Creation of dynamic property acf_field__group::$have_rows is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/includes/fields/class-acf-field-group.php on line 31

Deprecated: Creation of dynamic property acf_field_clone::$cloning is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/pro/fields/class-acf-field-clone.php on line 34

Deprecated: Creation of dynamic property acf_field_clone::$have_rows is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-pro/pro/fields/class-acf-field-clone.php on line 35

Deprecated: Creation of dynamic property jh_acf_field_table::$settings is deprecated in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-content/plugins/advanced-custom-fields-table-field/class-jh-acf-field-table.php on line 23

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902

Warning: Cannot modify header information - headers already sent by (output started at /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/functions.php:6131) in /var/www/vhosts/studiogo.tech/httpdocs/upcloudold/wp-includes/rest-api/class-wp-rest-server.php on line 1902
{"id":24881,"date":"2020-05-18T21:07:31","date_gmt":"2020-05-18T18:07:31","guid":{"rendered":"https:\/\/upcloud.com\/community\/tutorials\/deploy-dockerized-apps-kubernetes-centos-8"},"modified":"2020-05-18T21:07:31","modified_gmt":"2020-05-18T18:07:31","slug":"deploy-dockerized-apps-kubernetes-centos-8","status":"publish","type":"tutorial","link":"https:\/\/studiogo.tech\/upcloudold\/tutorial\/deploy-dockerized-apps-kubernetes-centos-8\/","title":{"rendered":"How to deploy dockerized apps to Kubernetes on CentOS 8"},"content":{"rendered":"\n

Kubernetes is a popular container orchestration system that lets you automate application deployment, scaling and management tasks via simple command line calls. This guide describes how to build and deploy a simple dockerized web app to a Kubernetes cluster on CentOS 8.<\/p>\n\n\n\n\n\n

This guide is divided into three main parts:<\/p>\n\n\n\n

1. Testing out containers
2. Building a simple dockerized app using Dockerfile
3. Deploying the app to Kubernetes<\/p>\n\n\n\n

If you do not yet have a running Kubernetes cluster, have a look at our earlier tutorial on how to install Kubernetes on CentOS 8<\/a>.<\/p>\n\n\n\n

\n
Test hosting on UpCloud!<\/a><\/div>\n<\/div>\n\n\n\n

Testing out containers<\/h2>\n\n\n\n

Let\u2019s start by running a simple docker app to test the container platform.<\/p>\n\n\n\n

1. Run hello-world app with the following command:<\/p>\n\n\n\n

docker run hello-world<\/pre>\n\n\n\n

You should see the app print \u201cHello from Docker!\u201d to your terminal towards the end of the output.<\/p>\n\n\n\n

Running a known container pulls the required image from a public registry and saves it on your docker server.<\/p>\n\n\n\n

2. Check the list of docker images<\/p>\n\n\n\n

docker images<\/pre>\n\n\n\n

After running the hello-world app once, it should show up on the images list.<\/p>\n\n\n\n

REPOSITORY    TAG      IMAGE ID       CREATED         SIZE\nhello-world   latest   fce289e99eb9   15 months ago   1.84kB<\/pre>\n\n\n\n

Now let\u2019s try a more advanced docker app<\/p>\n\n\n\n

1. Run the Ubuntu docker app in interactive mode.<\/p>\n\n\n\n

docker run -it ubuntu bash<\/pre>\n\n\n\n

On success, you\u2019ll be brought directly to Ubuntu prompt.<\/p>\n\n\n\n

2. Test the internet connection from inside docker app by running a command that requires network access.<\/p>\n\n\n\n

On Ubuntu\u2019s terminal prompt, run the following to check it has an internet connection.<\/p>\n\n\n\n

apt update<\/pre>\n\n\n\n

On success, you should see something like the below.<\/p>\n\n\n\n

Get:1 http:\/\/security.ubuntu.com\/ubuntu bionic-security InRelease [88.7 kB]\nGet:2 http:\/\/archive.ubuntu.com\/ubuntu bionic InRelease [242 kB]\n...\nGet:17 http:\/\/archive.ubuntu.com\/ubuntu bionic-backports\/main amd64 Packages [2496 B]\nGet:18 http:\/\/archive.ubuntu.com\/ubuntu bionic-backports\/universe amd64 Packages [4247 B] Fetched 17.7 MB in 5s (3439 kB\/s)<\/pre>\n\n\n\n

Then stop the Ubuntu container with the following command.<\/p>\n\n\n\n

exit<\/pre>\n\n\n\n

In case you cannot access the internet, you might see something similar to the error underneath.<\/p>\n\n\n\n

Err:1 http:\/\/security.ubuntu.com\/ubuntu bionic-security InRelease Temporary failure resolving 'security.ubuntu.com' Err:2 http:\/\/archive.ubuntu.com\/ubuntu<\/a> bionic InRelease Temporary failure resolving 'archive.ubuntu.com' ...<\/pre>\n\n\n\n

To fix this, make sure IP masquerade is enabled at the firewall and then try again.<\/p>\n\n\n\n

firewall-cmd --add-masquerade --permanent\nfirewall-cmd --reload<\/pre>\n\n\n\n

OK, we\u2019ve completed the first part, now let us move on to the next step.<\/p>\n\n\n\n

Building a simple dockerized app using Dockerfile<\/h2>\n\n\n\n

Dockerizing apps is a great way of creating consistent and reliable environments for many tasks regardless of the underlying operating system.<\/p>\n\n\n\n

For this example, we are going to make a simple Golang web server that takes input via the server URL and prints out a hello message.<\/p>\n\n\n\n

1. Start by creating a new directory named \u201cgoserver\u201d<\/p>\n\n\n\n

mkdir goserver<\/pre>\n\n\n\n

2. Create a file named \u201cmain.go\u201d in the goserver directory<\/p>\n\n\n\n

vi goserver\/main.go<\/pre>\n\n\n\n

Enter the following code, then save the file.<\/p>\n\n\n\n

package main\nimport ( \n   \"fmt\"\n   \"net\/http\"\n)\nfunc main() {\n   http.HandleFunc(\"\/\", HelloServer)\n   http.ListenAndServe(\":8080\", nil)\n}\nfunc HelloServer(w http.ResponseWriter, r *http.Request) {\n   fmt.Fprintf(w, \"Hello, %s!n\", r.URL.Path[1:])\n}<\/pre>\n\n\n\n

3. Create another new file named \u201cDockerfile\u201d with the following command.<\/p>\n\n\n\n

vi Dockerfile<\/pre>\n\n\n\n

Then add the following content to that file, save and exit the text editor.<\/p>\n\n\n\n

FROM golang:alpine as builder\nWORKDIR \/build\nCOPY \/goserver .\nRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags \"-static\"' -o main .\nFROM scratch\nCOPY --from=builder \/build\/main \/app\/\nWORKDIR \/app\nENV PORT=8080\nCMD [\".\/main\"]<\/pre>\n\n\n\n

4. Next, build a docker image based on our goserver.<\/p>\n\n\n\n

docker build -f Dockerfile -t goserver .<\/pre>\n\n\n\n

5. Additionally, you may wish to clean unused images from the build process.<\/p>\n\n\n\n

docker system prune -f<\/pre>\n\n\n\n

6. Then check that your web app was added to the images list.<\/p>\n\n\n\n

docker images<\/pre>\n\n\n\n

You should see a line such as in the example below.<\/p>\n\n\n\n

REPOSITORY   TAG      IMAGE ID       CREATED          SIZE\ngoserver    latest   6c0fb70f56fe   55 seconds ago   7.41MB<\/pre>\n\n\n\n

7. Afterwards, test run the web app.<\/p>\n\n\n\n

docker run -d -p 8090:8080 --name goserver goserver<\/pre>\n\n\n\n

8. You can verify that the deployment was successful by checking the running images.<\/p>\n\n\n\n

docker ps -f name=goserver<\/pre>\n\n\n\n

You should see the \u201cgoserver\u201d container running with the status \u201cUp\u201d.<\/p>\n\n\n\n

CONTAINER ID   IMAGE       COMMAND    CREATED          STATUS          PORTS                    NAMES\na16ebdf117b9   goserver   \".\/main\"   54 seconds ago   Up 53 seconds   0.0.0.0:8090->8080\/tcp   goserver<\/pre>\n\n\n\n

Your web app is now reachable both locally and over the internet.<\/p>\n\n\n\n

9. Call it on the command line, for example by using curl with the command below.<\/p>\n\n\n\n

curl http:\/\/localhost:8090\/Joe<\/pre>\n\n\n\n

You should have curl available but if not, install curl using sudo dnf install curl<\/tt><\/p>\n\n\n\n

You can also open the page in your web browser. Replace the public-ip-address<\/span> with the IP of your Master node.<\/p>\n\n\n\n

http:\/\/public-ip-address:8090\/Joe<\/tt><\/a><\/p>\n\n\n\n

You should see the following response.<\/p>\n\n\n\n

Hello, Joe!<\/p>\n\n\n\n

12. Once done, stop the web server and remove the image.<\/p>\n\n\n\n

docker stop goserver && docker rm goserver<\/pre>\n\n\n\n

Congratulations, you should now have an idea of what\u2019s included in making simple dockerized apps.<\/p>\n\n\n\n

Deploying a dockerized app to Kubernetes<\/h2>\n\n\n\n

We\u2019ve now tested out the container platform and built our own dockerized web app, so the last thing to do is to deploy it on our Kubernetes cluster.<\/p>\n\n\n\n

This part is referring to the Kubernetes configuration installed in our previous tutorial<\/a>.<\/p>\n\n\n\n

1. Create the following configuration file on the master node<\/strong>. Replace the <master_private_IP><\/span> with the private IP address of your master node.<\/p>\n\n\n\n

cat > \/etc\/docker\/daemon.json <<EOF\n{\n   \"log-driver\": \"json-file\",\n   \"log-opts\": {\n      \"max-size\": \"100m\"\n   },\n   \"storage-driver\": \"overlay2\",\n   \"storage-opts\": [\n      \"overlay2.override_kernel_check=true\"\n   ],\n   \"insecure-registries\": [ \"<master_private_IP><\/span>:5000\" ]\n}\nEOF<\/pre>\n\n\n\n

2. Add the exception for the registry also on all worker nodes<\/strong>. Again, replace the <master_private_IP><\/span> with the private IP address of your master node.<\/p>\n\n\n\n

cat > \/etc\/docker\/daemon.json <<EOF\n{\n   \"insecure-registries\": [ \"<master_private_IP><\/span>:5000\" ]\n}\nEOF<\/pre>\n\n\n\n

Then restart Docker on all nodes<\/strong>.<\/p>\n\n\n\n

systemctl restart docker<\/pre>\n\n\n\n

Continue with the rest of the steps on the master node only<\/strong>.<\/p>\n\n\n\n

We are going to be using a private registry container for storing and distributing our dockerized app in our cluster.<\/p>\n\n\n\n

3. Get the latest version of the docker registry.<\/p>\n\n\n\n

docker pull registry:2<\/pre>\n\n\n\n

4. Run the docker registry on port 5000 using the master node\u2019s private IP address. Replace the <master_private_IP><\/span> with the correct address.<\/p>\n\n\n\n

docker run -dit --restart=always -p <master_private_IP><\/span>:5000:5000 --name registry -e REGISTRY_STORAGE_DELETE_ENABLED=true registry:2<\/pre>\n\n\n\n

5. Next, create a deployment artefact for our \u201cgoserver\u201d app.<\/p>\n\n\n\n

Please be aware that indentation matters. This artefact is using two spaces for indentation.<\/p>\n\n\n\n

vi deployment.yaml<\/pre>\n\n\n\n

Enter the following content and again replace the <master_private_IP><\/span> with the correct address.<\/p>\n\n\n\n

apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  name: goserver\nspec:\n  selector:\n    matchLabels:\n      app: goserver\n  replicas: 2\n  revisionHistoryLimit: 0\n  progressDeadlineSeconds: 30\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxSurge: 2\n      maxUnavailable: 2\n  template:\n    metadata:\n      labels:\n        app: goserver\n    spec:\n      containers:\n      - name: goserver\n        image: <master_private_IP><\/span>:5000\/goserver:v1\n        ports:\n        - hostPort: 8090\n          containerPort: 8080\n\n---\napiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app: goserver\n  name: goserver\nspec:\n  selector:\n    app: goserver\n  ports:\n  - protocol: TCP\n    port: 8090\n    targetPort: 8080\n  type: ClusterIP<\/pre>\n\n\n\n

6. Tag the docker app to add the private registry address and port. As before, replace the <master_private_IP><\/span> with the private IP address of your master node.<\/p>\n\n\n\n

docker tag goserver:latest <master_private_IP><\/span>:5000\/goserver:v1<\/pre>\n\n\n\n

7. Then check to make sure the tagged app was created.<\/p>\n\n\n\n

docker images<\/pre>\n\n\n\n

It should show up on the list.<\/p>\n\n\n\n

8. Push the tagged app to the private registry so it can be pulled by Kubernetes deployment. Again, replace the <master_private_IP><\/span> with the private IP address of your master node.<\/p>\n\n\n\n

docker push <master_private_IP><\/span>:5000\/goserver:v1<\/pre>\n\n\n\n

9. Check that the tagged app was successfully pushed to the registry by querying the registry. Replace the <master_private_IP><\/span> with the private IP address of your master node.<\/p>\n\n\n\n

curl -s -X GET http:\/\/<master_private_IP><\/span>:5000\/v2\/goserver\/tags\/list<\/pre>\n\n\n\n
{\"name\":\"goserver\",\"tags\":[\"v1\"]}<\/pre>\n\n\n\n

Now that we have set up our private repository and pushed the docker image to it, it can be used to deploy the app onto our Kubernetes cluster.<\/p>\n\n\n\n

10. Deploy our goserver using the command below.<\/p>\n\n\n\n

kubectl apply -f deployment.yaml<\/pre>\n\n\n\n

11. Check that the deployment rollout succeeded.<\/p>\n\n\n\n

kubectl rollout status deployment\/goserver<\/pre>\n\n\n\n

12. You can also check that the pods are up and running.<\/p>\n\n\n\n

kubectl get pods<\/pre>\n\n\n\n

13. You should now be able to access the web server on both master and worker nodes.<\/p>\n\n\n\n

curl http:\/\/localhost:8090\/Joe<\/pre>\n\n\n\n

Or open browser to :8090\/Joe” target=”_blank” rel=”noopener”>http:\/\/<public-IP-address>:8090\/Joe<\/a><\/p>\n\n\n\n

Replace the <public-IP-address> with either the public IP address of your master or worker node.<\/p>\n\n\n\n

You should see the familiar greeting.<\/p>\n\n\n\n

Hello, Joe!<\/p>\n\n\n\n

14. When you wish to delete the test app, revert the deployment with the following command.<\/p>\n\n\n\n

kubectl delete -f deployment.yaml<\/pre>\n\n\n\n

Done!<\/p>\n\n\n\n

All done!<\/h2>\n\n\n\n

When you need to update \u201cgoserver\u201d codes, you need to dockerized again. Then you also need to push it to the registry with different tags (e.g. v2).<\/p>\n\n\n\n

That\u2019s all folks, happy dockerizing!<\/p>\n","protected":false},"featured_media":14966,"comment_status":"open","ping_status":"closed","template":"","community-category":[113,114],"class_list":["post-24881","tutorial","type-tutorial","status-publish","has-post-thumbnail","hentry","community-category-integrations","community-category-kubernetes"],"acf":[],"_links":{"self":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/tutorial\/24881","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/tutorial"}],"about":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/types\/tutorial"}],"replies":[{"embeddable":true,"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/comments?post=24881"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/media\/14966"}],"wp:attachment":[{"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/media?parent=24881"}],"wp:term":[{"taxonomy":"community-category","embeddable":true,"href":"https:\/\/studiogo.tech\/upcloudold\/wp-json\/wp\/v2\/community-category?post=24881"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}