mirror of https://github.com/istio/istio.io.git
181 lines
41 KiB
HTML
181 lines
41 KiB
HTML
<!doctype html><html lang=en itemscope itemtype=https://schema.org/WebPage><head><meta charset=utf-8><meta http-equiv=x-ua-compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=theme-color content="#466BB0"><meta name=title content="Consuming External TCP Services"><meta name=description content="Describes a simple scenario based on Istio's Bookinfo example."><meta name=author content="Vadim Eisenberg"><meta name=keywords content="microservices,services,mesh,traffic-management,egress,tcp"><meta property="og:title" content="Consuming External TCP Services"><meta property="og:type" content="website"><meta property="og:description" content="Describes a simple scenario based on Istio's Bookinfo example."><meta property="og:url" content="/v1.12/blog/2018/egress-tcp/"><meta property="og:image" content="https://raw.githubusercontent.com/istio/istio.io/master/static/img/istio-whitelogo-bluebackground-framed.svg"><meta property="og:image:alt" content="Istio Logo"><meta property="og:image:width" content="1024"><meta property="og:image:height" content="1024"><meta property="og:site_name" content="Istio"><meta name=twitter:card content="summary"><meta name=twitter:site content="@IstioMesh"><title>Istioldie 1.12 / Consuming External TCP Services</title><script async src="https://www.googletagmanager.com/gtag/js?id=UA-98480406-2"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}
|
|
gtag('js',new Date());gtag('config','UA-98480406-2');</script><link rel=alternate type=application/rss+xml title="Istio Blog" href=/v1.12/blog/feed.xml><link rel=alternate type=application/rss+xml title="Istio News" href=/v1.12/news/feed.xml><link rel=alternate type=application/rss+xml title="Istio Blog and News" href=/v1.12/feed.xml><link rel="shortcut icon" href=/v1.12/favicons/favicon.ico><link rel=apple-touch-icon href=/v1.12/favicons/apple-touch-icon-180x180.png sizes=180x180><link rel=icon type=image/png href=/v1.12/favicons/favicon-16x16.png sizes=16x16><link rel=icon type=image/png href=/v1.12/favicons/favicon-32x32.png sizes=32x32><link rel=icon type=image/png href=/v1.12/favicons/android-36x36.png sizes=36x36><link rel=icon type=image/png href=/v1.12/favicons/android-48x48.png sizes=48x48><link rel=icon type=image/png href=/v1.12/favicons/android-72x72.png sizes=72x72><link rel=icon type=image/png href=/v1.12/favicons/android-96x96.png sizes=96xW96><link rel=icon type=image/png href=/v1.12/favicons/android-144x144.png sizes=144x144><link rel=icon type=image/png href=/v1.12/favicons/android-192x192.png sizes=192x192><link rel=mask-icon href=/v1.12/favicons/safari-pinned-tab.svg color=#466bb0><link rel=manifest href=/v1.12/manifest.json><meta name=apple-mobile-web-app-title content="Istio"><meta name=application-name content="Istio"><meta name=msapplication-config content="/browserconfig.xml"><meta name=msapplication-TileColor content="#466BB0"><meta name=theme-color content="#466BB0"><link rel=stylesheet href=/v1.12/css/all.css><link rel=preconnect href=https://fonts.gstatic.com><link rel=stylesheet href="https://fonts.googleapis.com/css2?family=Barlow:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&display=swap"><script src=/v1.12/js/themes_init.min.js></script></head><body class="language-unknown archive-site"><script>const branchName="release-1.12";const docTitle="Consuming External TCP Services";const iconFile="\/v1.12/img/icons.svg";const buttonCopy='Copy to clipboard';const buttonPrint='Print';const buttonDownload='Download';</script><script src="https://www.google.com/cse/brand?form=search-form" defer></script><script src=/v1.12/js/all.min.js data-manual defer></script><header class=main-navigation><nav class="main-navigation-wrapper container-l"><div class=main-navigation-header><a id=brand href=/v1.12/><span class=logo><svg xmlns="http://www.w3.org/2000/svg" width="128" height="60" viewBox="0 0 128 60"><path d="M58.434 48.823A.441.441.0 0158.3 48.497V22.583a.444.444.0 01.134-.326.446.446.0 01.327-.134h3.527a.447.447.0 01.325.134.447.447.0 01.134.326v25.914a.443.443.0 01-.134.326.444.444.0 01-.325.134h-3.527a.444.444.0 01-.327-.134z"/><path d="m70.969 48.477a6.556 6.556.0 01-2.818-1.955 4.338 4.338.0 01-1-2.78v-.345a.443.443.0 01.134-.326.444.444.0 01.326-.135h3.374a.444.444.0 01.326.135.445.445.0 01.134.326v.077a2.014 2.014.0 001.054 1.667 4.672 4.672.0 002.664.709 4.446 4.446.0 002.492-.633 1.862 1.862.0 00.958-1.591 1.426 1.426.0 00-.786-1.322 12.7 12.7.0 00-2.549-.939l-1.457-.46a21.526 21.526.0 01-3.3-1.227 6.57 6.57.0 01-2.262-1.783 4.435 4.435.0 01-.92-2.894 5.081 5.081.0 012.109-4.275 8.993 8.993.0 015.558-1.591 10.445 10.445.0 014.1.748 6.3 6.3.0 012.722 2.07 5 5 0 01.958 3.009.441.441.0 01-.134.326.441.441.0 01-.325.134h-3.258a.441.441.0 01-.326-.134.443.443.0 01-.134-.326 1.974 1.974.0 00-.978-1.667 4.647 4.647.0 00-2.665-.671 4.741 4.741.0 00-2.435.556 1.724 1.724.0 00-.938 1.553 1.512 1.512.0 00.9 1.4 15.875 15.875.0 003.01 1.055l.843.229a27.368 27.368.0 013.412 1.246 6.67 6.67.0 012.338 1.763 4.387 4.387.0 01.958 2.933 4.988 4.988.0 01-2.146 4.275 9.543 9.543.0 01-5.712 1.552 11.626 11.626.0 01-4.227-.709z"/><path d="m97.039 32.837a.443.443.0 01-.326.135h-3.911a.169.169.0 00-.191.192v9.239a2.951 2.951.0 00.632 2.108 2.7 2.7.0 002.013.652h1.15a.444.444.0 01.325.134.441.441.0 01.134.326v2.875a.471.471.0 01-.459.5l-1.994.039a8 8 0 01-4.524-1.035q-1.495-1.035-1.533-3.91V33.166A.17.17.0 0088.164 32.974H85.978A.441.441.0 0185.652 32.839.441.441.0 0185.518 32.513V29.83a.441.441.0 01.134-.326.444.444.0 01.326-.135h2.186a.169.169.0 00.191-.192v-4.485a.438.438.0 01.134-.326.44.44.0 01.325-.134h3.336a.443.443.0 01.325.134.442.442.0 01.135.326v4.485a.169.169.0 00.191.192h3.911a.446.446.0 01.326.135.446.446.0 01.134.326v2.683a.446.446.0 01-.133.324z"/><path d="m101.694 25.917a2.645 2.645.0 01-.767-1.955 2.65 2.65.0 01.767-1.955 2.65 2.65.0 011.955-.767 2.65 2.65.0 011.955.767 2.652 2.652.0 01.767 1.955 2.647 2.647.0 01-.767 1.955 2.646 2.646.0 01-1.955.767 2.645 2.645.0 01-1.955-.767zm-.211 22.906a.441.441.0 01-.134-.326V29.79a.444.444.0 01.134-.326.446.446.0 01.326-.134h3.527a.446.446.0 01.326.134.445.445.0 01.134.326v18.707a.443.443.0 01-.134.326.443.443.0 01-.326.134h-3.527a.443.443.0 01-.326-.134z"/><path d="m114.019 47.734a8.1 8.1.0 01-3.047-4.255 14.439 14.439.0 01-.652-4.37 14.3 14.3.0 01.614-4.371 7.869 7.869.0 013.066-4.178 9.072 9.072.0 015.252-1.5 8.543 8.543.0 015.041 1.5 7.985 7.985.0 013.009 4.14 12.439 12.439.0 01.69 4.37 13.793 13.793.0 01-.651 4.37 8.255 8.255.0 01-3.028 4.275 8.475 8.475.0 01-5.1 1.553 8.754 8.754.0 01-5.194-1.534zm7.629-3.1a4.536 4.536.0 001.476-2.262 11.335 11.335.0 00.383-3.221 10.618 10.618.0 00-.383-3.22 4.169 4.169.0 00-1.457-2.243 4.066 4.066.0 00-2.531-.785 3.942 3.942.0 00-2.453.785 4.376 4.376.0 00-1.5 2.243 11.839 11.839.0 00-.383 3.22 11.84 11.84.0 00.383 3.221 4.222 4.222.0 001.476 2.262 4.075 4.075.0 002.549.8 3.8 3.8.0 002.44-.809z"/><path d="m15.105 32.057v15.565a.059.059.0 01-.049.059L.069 50.25A.06.06.0 01.005 50.167l14.987-33.47a.06.06.0 01.114.025z"/><path d="m17.631 23.087v24.6a.06.06.0 00.053.059l22.449 2.507a.06.06.0 00.061-.084L17.745.032a.06.06.0 00-.114.024z"/><path d="m39.961 52.548-24.833 7.45a.062.062.0 01-.043.0L.079 52.548a.059.059.0 01.026-.113h39.839a.06.06.0 01.017.113z"/></svg></span></a><button id=hamburger class=main-navigation-toggle aria-label="Open navigation"><svg class="icon menu-hamburger"><use xlink:href="/v1.12/img/icons.svg#menu-hamburger"/></svg></button>
|
|
<button id=menu-close class=main-navigation-toggle aria-label="Close navigation"><svg class="icon menu-close"><use xlink:href="/v1.12/img/icons.svg#menu-close"/></svg></button></div><div id=header-links class=main-navigation-links-wrapper><ul class=main-navigation-links><li class=main-navigation-links-item><a class="main-navigation-links-link has-dropdown"><span>About</span><svg class="icon dropdown-arrow"><use xlink:href="/v1.12/img/icons.svg#dropdown-arrow"/></svg></a><ul class=main-navigation-links-dropdown><li class=main-navigation-links-dropdown-item><a href=/v1.12/about/service-mesh class=main-navigation-links-link>Service mesh</a></li><li class=main-navigation-links-dropdown-item><a href=/v1.12/about/solutions class=main-navigation-links-link>Solutions</a></li><li class=main-navigation-links-dropdown-item><a href=/v1.12/about/case-studies class=main-navigation-links-link>Case studies</a></li><li class=main-navigation-links-dropdown-item><a href=/v1.12/about/ecosystem class=main-navigation-links-link>Ecosystem</a></li><li class=main-navigation-links-dropdown-item><a href=/v1.12/about/deployment class=main-navigation-links-link>Deployment</a></li><li class=main-navigation-links-dropdown-item><a href=/v1.12/about/faq class=main-navigation-links-link>FAQ</a></li></ul></li><li class=main-navigation-links-item><a href=/v1.12/blog/ class=main-navigation-links-link><span>Blog</span></a></li><li class=main-navigation-links-item><a href=/v1.12/news/ class=main-navigation-links-link><span>News</span></a></li><li class=main-navigation-links-item><a href=/v1.12/get-involved/ class=main-navigation-links-link><span>Get involved</span></a></li><li class=main-navigation-links-item><a href=/v1.12/docs/ class=main-navigation-links-link><span>Documentation</span></a></li></ul><div class=main-navigation-footer><button id=search-show class=search-show title="Search this site" aria-label=Search><svg class="icon magnifier"><use xlink:href="/v1.12/img/icons.svg#magnifier"/></svg></button>
|
|
<a href=/v1.12/docs/setup/getting-started class="btn btn--primary" id=try-istio>Try Istio</a></div></div><form id=search-form class=search name=cse role=search><input type=hidden name=cx value=002184991200833970123:iwwf17ikgf4>
|
|
<input type=hidden name=ie value=utf-8>
|
|
<input type=hidden name=hl value=en>
|
|
<input type=hidden id=search-page-url value=/search>
|
|
<input id=search-textbox class="search-textbox form-control" name=q type=search aria-label="Search this site" placeholder=Search>
|
|
<button id=search-close title="Cancel search" type=reset aria-label="Cancel search"><svg class="icon menu-close"><use xlink:href="/v1.12/img/icons.svg#menu-close"/></svg></button></form></nav></header><div class=banner-container><a href=/v1.12/news/releases/1.12.x/announcing-1.12.3/ class=banner data-title="Latest Release-2022-02-11 00:00:00 +0000 UTC" data-period-start=1644537600000 data-period-end=1645142400000 data-max-impressions=3 data-timeout><div class=content><p>Istio 1.12.3 is now available! Click here to learn more</p></div><div class=frame></div></a></div><article class=post itemscope itemtype=http://schema.org/BlogPosting><div class=header-content><h1>Consuming External TCP Services</h1><p>Describes a simple scenario based on Istio's Bookinfo example.</p></div><p class=post-author>Feb 6, 2018 <span>|</span> By Vadim Eisenberg</p><div><div><aside class="callout tip"><div class=type><svg class="large-icon"><use xlink:href="/v1.12/img/icons.svg#callout-tip"/></svg></div><div class=content>This blog post was updated on July 23, 2018 to use the new
|
|
<a href=/v1.12/blog/2018/v1alpha3-routing/>v1alpha3 traffic management API</a>. If you need to use the old version, follow these <a href=https://archive.istio.io/v0.7/blog/2018/egress-tcp.html>docs</a>.</div></aside></div><p>In my previous blog post, <a href=/v1.12/blog/2018/egress-https/>Consuming External Web Services</a>, I described how external services
|
|
can be consumed by in-mesh Istio applications via HTTPS. In this post, I demonstrate consuming external services
|
|
over TCP. You will use the <a href=/v1.12/docs/examples/bookinfo/>Istio Bookinfo sample application</a>, the version in which the book
|
|
ratings data is persisted in a MySQL database. You deploy this database outside the cluster and configure the
|
|
<em>ratings</em> microservice to use it. You define a
|
|
<a href=/v1.12/docs/reference/config/networking/service-entry/>Service Entry</a> to allow the in-mesh applications to
|
|
access the external database.</p><h2 id=bookinfo-sample-application-with-external-ratings-database>Bookinfo sample application with external ratings database</h2><p>First, you set up a MySQL database instance to hold book ratings data outside of your Kubernetes cluster. Then you
|
|
modify the <a href=/v1.12/docs/examples/bookinfo/>Bookinfo sample application</a> to use your database.</p><h3 id=setting-up-the-database-for-ratings-data>Setting up the database for ratings data</h3><p>For this task you set up an instance of <a href=https://www.mysql.com>MySQL</a>. You can use any MySQL instance; I used
|
|
<a href=https://www.ibm.com/cloud/compose/mysql>Compose for MySQL</a>. I used <code>mysqlsh</code>
|
|
(<a href=https://dev.mysql.com/doc/mysql-shell/en/>MySQL Shell</a>) as a MySQL client to feed the ratings data.</p><ol><li><p>Set the <code>MYSQL_DB_HOST</code> and <code>MYSQL_DB_PORT</code> environment variables:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ export MYSQL_DB_HOST=<your MySQL database host>
|
|
$ export MYSQL_DB_PORT=<your MySQL database port>
|
|
</code></pre><p>In case of a local MySQL database with the default port, the values are <code>localhost</code> and <code>3306</code>, respectively.</p></li><li><p>To initialize the database, run the following command entering the password when prompted. The command is
|
|
performed with the credentials of the <code>admin</code> user, created by default by
|
|
<a href=https://www.ibm.com/cloud/compose/mysql>Compose for MySQL</a>.</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ curl -s https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/src/mysql/mysqldb-init.sql | mysqlsh --sql --ssl-mode=REQUIRED -u admin -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT
|
|
</code></pre><p><em><strong>OR</strong></em></p><p>When using the <code>mysql</code> client and a local MySQL database, run:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ curl -s https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/src/mysql/mysqldb-init.sql | mysql -u root -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT
|
|
</code></pre></li><li><p>Create a user with the name <code>bookinfo</code> and grant it <em>SELECT</em> privilege on the <code>test.ratings</code> table:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysqlsh --sql --ssl-mode=REQUIRED -u admin -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "CREATE USER 'bookinfo' IDENTIFIED BY '<password you choose>'; GRANT SELECT ON test.ratings to 'bookinfo';"
|
|
</code></pre><p><em><strong>OR</strong></em></p><p>For <code>mysql</code> and the local database, the command is:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysql -u root -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "CREATE USER 'bookinfo' IDENTIFIED BY '<password you choose>'; GRANT SELECT ON test.ratings to 'bookinfo';"
|
|
</code></pre><p>Here you apply the <a href=https://en.wikipedia.org/wiki/Principle_of_least_privilege>principle of least privilege</a>. This
|
|
means that you do not use your <code>admin</code> user in the Bookinfo application. Instead, you create a special user for the
|
|
Bookinfo application , <code>bookinfo</code>, with minimal privileges. In this case, the <em>bookinfo</em> user only has the <code>SELECT</code>
|
|
privilege on a single table.</p><p>After running the command to create the user, you may want to clean your bash history by checking the number of the last
|
|
command and running <code>history -d <the number of the command that created the user></code>. You don’t want the password of the
|
|
new user to be stored in the bash history. If you’re using <code>mysql</code>, remove the last command from
|
|
<code>~/.mysql_history</code> file as well. Read more about password protection of the newly created user in <a href=https://dev.mysql.com/doc/refman/5.5/en/create-user.html>MySQL documentation</a>.</p></li><li><p>Inspect the created ratings to see that everything worked as expected:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysqlsh --sql --ssl-mode=REQUIRED -u bookinfo -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "select * from test.ratings;"
|
|
Enter password:
|
|
+----------+--------+
|
|
| ReviewID | Rating |
|
|
+----------+--------+
|
|
| 1 | 5 |
|
|
| 2 | 4 |
|
|
+----------+--------+
|
|
</code></pre><p><em><strong>OR</strong></em></p><p>For <code>mysql</code> and the local database:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysql -u bookinfo -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "select * from test.ratings;"
|
|
Enter password:
|
|
+----------+--------+
|
|
| ReviewID | Rating |
|
|
+----------+--------+
|
|
| 1 | 5 |
|
|
| 2 | 4 |
|
|
+----------+--------+
|
|
</code></pre></li><li><p>Set the ratings temporarily to <code>1</code> to provide a visual clue when our database is used by the Bookinfo <em>ratings</em>
|
|
service:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysqlsh --sql --ssl-mode=REQUIRED -u admin -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "update test.ratings set rating=1; select * from test.ratings;"
|
|
Enter password:
|
|
|
|
Rows matched: 2 Changed: 2 Warnings: 0
|
|
+----------+--------+
|
|
| ReviewID | Rating |
|
|
+----------+--------+
|
|
| 1 | 1 |
|
|
| 2 | 1 |
|
|
+----------+--------+
|
|
</code></pre><p><em><strong>OR</strong></em></p><p>For <code>mysql</code> and the local database:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysql -u root -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "update test.ratings set rating=1; select * from test.ratings;"
|
|
Enter password:
|
|
+----------+--------+
|
|
| ReviewID | Rating |
|
|
+----------+--------+
|
|
| 1 | 1 |
|
|
| 2 | 1 |
|
|
+----------+--------+
|
|
</code></pre><p>You used the <code>admin</code> user (and <code>root</code> for the local database) in the last command since the <code>bookinfo</code> user does not
|
|
have the <code>UPDATE</code> privilege on the <code>test.ratings</code> table.</p></li></ol><p>Now you are ready to deploy a version of the Bookinfo application that will use your database.</p><h3 id=initial-setting-of-bookinfo-application>Initial setting of Bookinfo application</h3><p>To demonstrate the scenario of using an external database, you start with a Kubernetes cluster with <a href=/v1.12/docs/setup/getting-started/>Istio installed</a>. Then you deploy the
|
|
<a href=/v1.12/docs/examples/bookinfo/>Istio Bookinfo sample application</a>, <a href=/v1.12/docs/examples/bookinfo/#apply-default-destination-rules>apply the default destination rules</a>, and <a href=/v1.12/docs/tasks/traffic-management/egress/egress-control/#change-to-the-blocking-by-default-policy>change Istio to the blocking-egress-by-default policy</a>.</p><p>This application uses the <code>ratings</code> microservice to fetch
|
|
book ratings, a number between 1 and 5. The ratings are displayed as stars for each review. There are several versions
|
|
of the <code>ratings</code> microservice. Some use <a href=https://www.mongodb.com>MongoDB</a>, others use <a href=https://www.mysql.com>MySQL</a>
|
|
as their database.</p><p>The example commands in this blog post work with Istio 0.8+, with or without
|
|
<a href=/v1.12/docs/concepts/security/#mutual-tls-authentication>mutual TLS</a> enabled.</p><p>As a reminder, here is the end-to-end architecture of the application from the
|
|
<a href=/v1.12/docs/examples/bookinfo/>Bookinfo sample application</a>.</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:59.086918235567985%><a data-skipendnotes=true href=/v1.12/docs/examples/bookinfo/withistio.svg title="The original Bookinfo application"><img class=element-to-stretch src=/v1.12/docs/examples/bookinfo/withistio.svg alt="The original Bookinfo application"></a></div><figcaption>The original Bookinfo application</figcaption></figure><h3 id=use-the-database-for-ratings-data-in-bookinfo-application>Use the database for ratings data in Bookinfo application</h3><ol><li><p>Modify the deployment spec of a version of the <em>ratings</em> microservice that uses a MySQL database, to use your
|
|
database instance. The spec is in <a href=https://github.com/istio/istio/blob/release-1.12/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml><code>samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml</code></a>
|
|
of an Istio release archive. Edit the following lines:</p><pre><code class=language-yaml data-expandlinks=true data-repo=istio>- name: MYSQL_DB_HOST
|
|
value: mysqldb
|
|
- name: MYSQL_DB_PORT
|
|
value: "3306"
|
|
- name: MYSQL_DB_USER
|
|
value: root
|
|
- name: MYSQL_DB_PASSWORD
|
|
value: password
|
|
</code></pre><p>Replace the values in the snippet above, specifying the database host, port, user, and password. Note that the
|
|
correct way to work with passwords in container’s environment variables in Kubernetes is <a href=https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables>to use secrets</a>. For this
|
|
example task only, you may want to write the password directly in the deployment spec. <strong>Do not do it</strong> in a real
|
|
environment! I also assume everyone realizes that <code>"password"</code> should not be used as a password…</p></li><li><p>Apply the modified spec to deploy the version of the <em>ratings</em> microservice, <em>v2-mysql</em>, that will use your
|
|
database.</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl apply -f @samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml@
|
|
deployment "ratings-v2-mysql" created
|
|
</code></pre></div></li><li><p>Route all the traffic destined to the <em>reviews</em> service to its <em>v3</em> version. You do this to ensure that the
|
|
<em>reviews</em> service always calls the <em>ratings</em> service. In addition, route all the traffic destined to the <em>ratings</em>
|
|
service to <em>ratings v2-mysql</em> that uses your database.</p><p>Specify the routing for both services above by adding two
|
|
<a href=/v1.12/docs/reference/config/networking/virtual-service/>virtual services</a>. These virtual services are
|
|
specified in <code>samples/bookinfo/networking/virtual-service-ratings-mysql.yaml</code> of an Istio release archive.
|
|
<strong><em>Important:</em></strong> make sure you
|
|
<a href=/v1.12/docs/examples/bookinfo/#apply-default-destination-rules>applied the default destination rules</a> before running the
|
|
following command.</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl apply -f @samples/bookinfo/networking/virtual-service-ratings-mysql.yaml@
|
|
</code></pre></div></li></ol><p>The updated architecture appears below. Note that the blue arrows inside the mesh mark the traffic configured according
|
|
to the virtual services we added. According to the virtual services, the traffic is sent to <em>reviews v3</em> and
|
|
<em>ratings v2-mysql</em>.</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:59.314858206480224%><a data-skipendnotes=true href=/v1.12/blog/2018/egress-tcp/bookinfo-ratings-v2-mysql-external.svg title="The Bookinfo application with ratings v2-mysql and an external MySQL database"><img class=element-to-stretch src=/v1.12/blog/2018/egress-tcp/bookinfo-ratings-v2-mysql-external.svg alt="The Bookinfo application with ratings v2-mysql and an external MySQL database"></a></div><figcaption>The Bookinfo application with ratings v2-mysql and an external MySQL database</figcaption></figure><p>Note that the MySQL database is outside the Istio service mesh, or more precisely outside the Kubernetes cluster. The
|
|
boundary of the service mesh is marked by a dashed line.</p><h3 id=access-the-webpage>Access the webpage</h3><p>Access the webpage of the application, after
|
|
<a href=/v1.12/docs/examples/bookinfo/#determine-the-ingress-ip-and-port>determining the ingress IP and port</a>.</p><p>You have a problem… Instead of the rating stars, the message <em>“Ratings service is currently unavailable”</em> is currently
|
|
displayed below each review:</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:36.18705035971223%><a data-skipendnotes=true href=/v1.12/blog/2018/egress-tcp/errorFetchingBookRating.png title="The Ratings service error messages"><img class=element-to-stretch src=/v1.12/blog/2018/egress-tcp/errorFetchingBookRating.png alt="The Ratings service error messages"></a></div><figcaption>The Ratings service error messages</figcaption></figure><p>As in <a href=/v1.12/blog/2018/egress-https/>Consuming External Web Services</a>, you experience <strong>graceful service degradation</strong>,
|
|
which is good. The application did not crash due to the error in the <em>ratings</em> microservice. The webpage of the
|
|
application correctly displayed the book information, the details, and the reviews, just without the rating stars.</p><p>You have the same problem as in <a href=/v1.12/blog/2018/egress-https/>Consuming External Web Services</a>, namely all the traffic
|
|
outside the Kubernetes cluster, both TCP and HTTP, is blocked by default by the sidecar proxies. To enable such traffic
|
|
for TCP, a mesh-external service entry for TCP must be defined.</p><h3 id=mesh-external-service-entry-for-an-external-mysql-instance>Mesh-external service entry for an external MySQL instance</h3><p>TCP mesh-external service entries come to our rescue.</p><ol><li><p>Get the IP address of your MySQL database instance. As an option, you can use the
|
|
<a href=https://linux.die.net/man/1/host>host</a> command:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ export MYSQL_DB_IP=$(host $MYSQL_DB_HOST | grep " has address " | cut -d" " -f4)
|
|
</code></pre><p>For a local database, set <code>MYSQL_DB_IP</code> to contain the IP of your machine, accessible from your cluster.</p></li><li><p>Define a TCP mesh-external service entry:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl apply -f - <<EOF
|
|
apiVersion: networking.istio.io/v1alpha3
|
|
kind: ServiceEntry
|
|
metadata:
|
|
name: mysql-external
|
|
spec:
|
|
hosts:
|
|
- $MYSQL_DB_HOST
|
|
addresses:
|
|
- $MYSQL_DB_IP/32
|
|
ports:
|
|
- name: tcp
|
|
number: $MYSQL_DB_PORT
|
|
protocol: tcp
|
|
location: MESH_EXTERNAL
|
|
EOF
|
|
</code></pre></li><li><p>Review the service entry you just created and check that it contains the correct values:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl get serviceentry mysql-external -o yaml
|
|
apiVersion: networking.istio.io/v1alpha3
|
|
kind: ServiceEntry
|
|
metadata:
|
|
...
|
|
</code></pre></li></ol><p>Note that for a TCP service entry, you specify <code>tcp</code> as the protocol of a port of the entry. Also note that you have to
|
|
specify the IP of the external service in the list of addresses, as a <a href=https://tools.ietf.org/html/rfc2317>CIDR</a> block
|
|
with suffix <code>32</code>.</p><p>I will talk more about TCP service entries
|
|
<a href=#service-entries-for-tcp-traffic>below</a>. For now, verify that the service entry we added fixed the problem. Access the
|
|
webpage and see if the stars are back.</p><p>It worked! Accessing the web page of the application displays the ratings without error:</p><figure style=width:80%><div class=wrapper-with-intrinsic-ratio style=padding-bottom:36.69064748201439%><a data-skipendnotes=true href=/v1.12/blog/2018/egress-tcp/externalMySQLRatings.png title="Book Ratings Displayed Correctly"><img class=element-to-stretch src=/v1.12/blog/2018/egress-tcp/externalMySQLRatings.png alt="Book Ratings Displayed Correctly"></a></div><figcaption>Book Ratings Displayed Correctly</figcaption></figure><p>Note that you see a one-star rating for both displayed reviews, as expected. You changed the ratings to be one star to
|
|
provide us with a visual clue that our external database is indeed being used.</p><p>As with service entries for HTTP/HTTPS, you can delete and create service entries for TCP using <code>kubectl</code>, dynamically.</p><h2 id=motivation-for-egress-tcp-traffic-control>Motivation for egress TCP traffic control</h2><p>Some in-mesh Istio applications must access external services, for example legacy systems. In many cases, the access is
|
|
not performed over HTTP or HTTPS protocols. Other TCP protocols are used, such as database-specific protocols like
|
|
<a href=https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/>MongoDB Wire Protocol</a> and <a href=https://dev.mysql.com/doc/internals/en/client-server-protocol.html>MySQL Client/Server Protocol</a> to communicate with external databases.</p><p>Next let me provide more details about the service entries for TCP traffic.</p><h2 id=service-entries-for-tcp-traffic>Service entries for TCP traffic</h2><p>The service entries for enabling TCP traffic to a specific port must specify <code>TCP</code> as the protocol of the port.
|
|
Additionally, for the <a href=https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/>MongoDB Wire Protocol</a>, the
|
|
protocol can be specified as <code>MONGO</code>, instead of <code>TCP</code>.</p><p>For the <code>addresses</code> field of the entry, a block of IPs in <a href=https://tools.ietf.org/html/rfc2317>CIDR</a>
|
|
notation must be used. Note that the <code>hosts</code> field is ignored for TCP service entries.</p><p>To enable TCP traffic to an external service by its hostname, all the IPs of the hostname must be specified. Each IP
|
|
must be specified by a CIDR block.</p><p>Note that all the IPs of an external service are not always known. To enable egress TCP traffic, only the IPs that are
|
|
used by the applications must be specified.</p><p>Also note that the IPs of an external service are not always static, for example in the case of
|
|
<a href=https://en.wikipedia.org/wiki/Content_delivery_network>CDNs</a>. Sometimes the IPs are static most of the time, but can
|
|
be changed from time to time, for example due to infrastructure changes. In these cases, if the range of the possible
|
|
IPs is known, you should specify the range by CIDR blocks. If the range of the possible IPs is not known, service
|
|
entries for TCP cannot be used and
|
|
<a href=/v1.12/docs/tasks/traffic-management/egress/egress-control/#direct-access-to-external-services>the external services must be called directly</a>,
|
|
bypassing the sidecar proxies.</p><h2 id=relation-to-virtual-machines-support>Relation to virtual machines support</h2><p>Note that the scenario described in this post is different from the
|
|
<a href=/v1.12/docs/examples/virtual-machines/>Bookinfo with Virtual Machines</a> example. In that scenario, a MySQL instance runs on an
|
|
external
|
|
(outside the cluster) machine (a bare metal or a VM), integrated with the Istio service mesh. The MySQL service becomes
|
|
a first-class citizen of the mesh with all the beneficial features of Istio applicable. Among other things, the service
|
|
becomes addressable by a local cluster domain name, for example by <code>mysqldb.vm.svc.cluster.local</code>, and the communication
|
|
to it can be secured by
|
|
<a href=/v1.12/docs/concepts/security/#mutual-tls-authentication>mutual TLS authentication</a>. There is no need to create a service
|
|
entry to access this service; however, the service must be registered with Istio. To enable such integration, Istio
|
|
components (<em>Envoy proxy</em>, <em>node-agent</em>, <code>_istio-agent_</code>) must be installed on the machine and the Istio control plane
|
|
(<em>Pilot</em>, <em>Mixer</em>, <em>Citadel</em>) must be accessible from it. See the
|
|
<a href=/v1.12/docs/examples/virtual-machines/>Istio VM-related</a> tasks for more details.</p><p>In our case, the MySQL instance can run on any machine or can be provisioned as a service by a cloud provider. There is
|
|
no requirement to integrate the machine with Istio. The Istio control plane does not have to be accessible from the
|
|
machine. In the case of MySQL as a service, the machine which MySQL runs on may be not accessible and installing on it
|
|
the required components may be impossible. In our case, the MySQL instance is addressable by its global domain name,
|
|
which could be beneficial if the consuming applications expect to use that domain name. This is especially relevant when
|
|
that expected domain name cannot be changed in the deployment configuration of the consuming applications.</p><h2 id=cleanup>Cleanup</h2><ol><li><p>Drop the <code>test</code> database and the <code>bookinfo</code> user:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysqlsh --sql --ssl-mode=REQUIRED -u admin -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "drop database test; drop user bookinfo;"
|
|
</code></pre><p><em><strong>OR</strong></em></p><p>For <code>mysql</code> and the local database:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ mysql -u root -p --host $MYSQL_DB_HOST --port $MYSQL_DB_PORT -e "drop database test; drop user bookinfo;"
|
|
</code></pre></li><li><p>Remove the virtual services:</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl delete -f @samples/bookinfo/networking/virtual-service-ratings-mysql.yaml@
|
|
Deleted config: virtual-service/default/reviews
|
|
Deleted config: virtual-service/default/ratings
|
|
</code></pre></div></li><li><p>Undeploy <em>ratings v2-mysql</em>:</p><div><a data-skipendnotes=true style=display:none href=https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml>Zip</a><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl delete -f @samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml@
|
|
deployment "ratings-v2-mysql" deleted
|
|
</code></pre></div></li><li><p>Delete the service entry:</p><pre><code class=language-bash data-expandlinks=true data-repo=istio>$ kubectl delete serviceentry mysql-external -n default
|
|
Deleted config: serviceentry mysql-external
|
|
</code></pre></li></ol><h2 id=conclusion>Conclusion</h2><p>In this blog post, I demonstrated how the microservices in an Istio service mesh can consume external services via TCP.
|
|
By default, Istio blocks all the traffic, TCP and HTTP, to the hosts outside the cluster. To enable such traffic for
|
|
TCP, TCP mesh-external service entries must be created for the service mesh.</p></div><nav class=pagenav><div class=left><a title="An introduction to safer, lower-risk deployments and release to production." href=/v1.12/blog/2018/traffic-mirroring/ class=next-link><svg class="icon left-arrow"><use xlink:href="/v1.12/img/icons.svg#left-arrow"/></svg>Traffic Mirroring with Istio for Testing in Production</a></div><div class=right><a title="Describes a simple scenario based on Istio's Bookinfo example." href=/v1.12/blog/2018/egress-https/ class=next-link>Consuming External Web Services<svg class="icon right-arrow"><use xlink:href="/v1.12/img/icons.svg#right-arrow"/></svg></a></div></nav></article><footer class=footer><div class="footer-wrapper container-l"><div class="user-links footer-links"><a class=channel title="GitHub is where development takes place on Istio code" href=https://github.com/istio/community aria-label=GitHub><svg class="icon github"><use xlink:href="/v1.12/img/icons.svg#github"/></svg></a><a class=channel title="Access our team drive if you'd like to take a look at the Istio technical design documents" href=https://groups.google.com/forum/#!forum/istio-team-drive-access aria-label="team drive"><svg class="icon drive"><use xlink:href="/v1.12/img/icons.svg#drive"/></svg></a><a class=channel title="Interactively discuss issues with the Istio community on Slack" href=https://slack.istio.io aria-label=slack><svg class="icon slack"><use xlink:href="/v1.12/img/icons.svg#slack"/></svg></a><a class=channel title="Stack Overflow is where you can ask questions and find curated answers on deploying, configuring, and using Istio" href=https://stackoverflow.com/questions/tagged/istio aria-label="Stack Overflow"><svg class="icon stackoverflow"><use xlink:href="/v1.12/img/icons.svg#stackoverflow"/></svg></a><a class=channel title="Follow us on Twitter to get the latest news" href=https://twitter.com/IstioMesh aria-label=Twitter><svg class="icon twitter"><use xlink:href="/v1.12/img/icons.svg#twitter"/></svg></a></div><hr class=footer-separator role=separator><div class="info footer-info"><a class=logo href=/v1.12/><svg xmlns="http://www.w3.org/2000/svg" width="128" height="60" viewBox="0 0 128 60"><path d="M58.434 48.823A.441.441.0 0158.3 48.497V22.583a.444.444.0 01.134-.326.446.446.0 01.327-.134h3.527a.447.447.0 01.325.134.447.447.0 01.134.326v25.914a.443.443.0 01-.134.326.444.444.0 01-.325.134h-3.527a.444.444.0 01-.327-.134z"/><path d="m70.969 48.477a6.556 6.556.0 01-2.818-1.955 4.338 4.338.0 01-1-2.78v-.345a.443.443.0 01.134-.326.444.444.0 01.326-.135h3.374a.444.444.0 01.326.135.445.445.0 01.134.326v.077a2.014 2.014.0 001.054 1.667 4.672 4.672.0 002.664.709 4.446 4.446.0 002.492-.633 1.862 1.862.0 00.958-1.591 1.426 1.426.0 00-.786-1.322 12.7 12.7.0 00-2.549-.939l-1.457-.46a21.526 21.526.0 01-3.3-1.227 6.57 6.57.0 01-2.262-1.783 4.435 4.435.0 01-.92-2.894 5.081 5.081.0 012.109-4.275 8.993 8.993.0 015.558-1.591 10.445 10.445.0 014.1.748 6.3 6.3.0 012.722 2.07 5 5 0 01.958 3.009.441.441.0 01-.134.326.441.441.0 01-.325.134h-3.258a.441.441.0 01-.326-.134.443.443.0 01-.134-.326 1.974 1.974.0 00-.978-1.667 4.647 4.647.0 00-2.665-.671 4.741 4.741.0 00-2.435.556 1.724 1.724.0 00-.938 1.553 1.512 1.512.0 00.9 1.4 15.875 15.875.0 003.01 1.055l.843.229a27.368 27.368.0 013.412 1.246 6.67 6.67.0 012.338 1.763 4.387 4.387.0 01.958 2.933 4.988 4.988.0 01-2.146 4.275 9.543 9.543.0 01-5.712 1.552 11.626 11.626.0 01-4.227-.709z"/><path d="m97.039 32.837a.443.443.0 01-.326.135h-3.911a.169.169.0 00-.191.192v9.239a2.951 2.951.0 00.632 2.108 2.7 2.7.0 002.013.652h1.15a.444.444.0 01.325.134.441.441.0 01.134.326v2.875a.471.471.0 01-.459.5l-1.994.039a8 8 0 01-4.524-1.035q-1.495-1.035-1.533-3.91V33.166A.17.17.0 0088.164 32.974H85.978A.441.441.0 0185.652 32.839.441.441.0 0185.518 32.513V29.83a.441.441.0 01.134-.326.444.444.0 01.326-.135h2.186a.169.169.0 00.191-.192v-4.485a.438.438.0 01.134-.326.44.44.0 01.325-.134h3.336a.443.443.0 01.325.134.442.442.0 01.135.326v4.485a.169.169.0 00.191.192h3.911a.446.446.0 01.326.135.446.446.0 01.134.326v2.683a.446.446.0 01-.133.324z"/><path d="m101.694 25.917a2.645 2.645.0 01-.767-1.955 2.65 2.65.0 01.767-1.955 2.65 2.65.0 011.955-.767 2.65 2.65.0 011.955.767 2.652 2.652.0 01.767 1.955 2.647 2.647.0 01-.767 1.955 2.646 2.646.0 01-1.955.767 2.645 2.645.0 01-1.955-.767zm-.211 22.906a.441.441.0 01-.134-.326V29.79a.444.444.0 01.134-.326.446.446.0 01.326-.134h3.527a.446.446.0 01.326.134.445.445.0 01.134.326v18.707a.443.443.0 01-.134.326.443.443.0 01-.326.134h-3.527a.443.443.0 01-.326-.134z"/><path d="m114.019 47.734a8.1 8.1.0 01-3.047-4.255 14.439 14.439.0 01-.652-4.37 14.3 14.3.0 01.614-4.371 7.869 7.869.0 013.066-4.178 9.072 9.072.0 015.252-1.5 8.543 8.543.0 015.041 1.5 7.985 7.985.0 013.009 4.14 12.439 12.439.0 01.69 4.37 13.793 13.793.0 01-.651 4.37 8.255 8.255.0 01-3.028 4.275 8.475 8.475.0 01-5.1 1.553 8.754 8.754.0 01-5.194-1.534zm7.629-3.1a4.536 4.536.0 001.476-2.262 11.335 11.335.0 00.383-3.221 10.618 10.618.0 00-.383-3.22 4.169 4.169.0 00-1.457-2.243 4.066 4.066.0 00-2.531-.785 3.942 3.942.0 00-2.453.785 4.376 4.376.0 00-1.5 2.243 11.839 11.839.0 00-.383 3.22 11.84 11.84.0 00.383 3.221 4.222 4.222.0 001.476 2.262 4.075 4.075.0 002.549.8 3.8 3.8.0 002.44-.809z"/><path d="m15.105 32.057v15.565a.059.059.0 01-.049.059L.069 50.25A.06.06.0 01.005 50.167l14.987-33.47a.06.06.0 01.114.025z"/><path d="m17.631 23.087v24.6a.06.06.0 00.053.059l22.449 2.507a.06.06.0 00.061-.084L17.745.032a.06.06.0 00-.114.024z"/><path d="m39.961 52.548-24.833 7.45a.062.062.0 01-.043.0L.079 52.548a.059.059.0 01.026-.113h39.839a.06.06.0 01.017.113z"/></svg></a><div class=footer-languages><a tabindex=-1 role=menuitem lang=en id=switch-lang-en class="footer-languages-item active"><svg class="icon tick"><use xlink:href="/v1.12/img/icons.svg#tick"/></svg>English</a>
|
|
<a tabindex=-1 role=menuitem lang=zh id=switch-lang-zh class=footer-languages-item>中文</a></div></div><ul class=footer-policies><li class=footer-policies-item><a class=footer-policies-link href=https://policies.google.com/privacy>Privacy policy</a> |
|
|
<a class=footer-policies-link href=https://github.com/istio/istio.io/edit/release-1.12/content/en/blog/2018/egress-tcp/index.md>Edit this Page on GitHub</a></li></ul><div class=footer-base><span class=footer-base-copyright>© 2021 Istio Authors.</span>
|
|
<span class=footer-base-version>Version
|
|
Archive
|
|
1.12.3</span><ul class=footer-base-releases><li class=footer-base-releases-item><a tabindex=-1 class=footer-base-releases-link role=menuitem onclick="navigateToUrlOrRoot('https://istio.io/blog\/2018\/egress-tcp\/');return false;">current release</a></li><li class=footer-base-releases-item><a tabindex=-1 class=footer-base-releases-link role=menuitem onclick="navigateToUrlOrRoot('https://preliminary.istio.io/blog\/2018\/egress-tcp\/');return false;">next release</a></li><li class=footer-base-releases-item><a tabindex=-1 class=footer-base-releases-link role=menuitem href=https://istio.io/archive>older releases</a></li></ul></div></div></footer><div id=scroll-to-top-container aria-hidden=true><button id=scroll-to-top title="Back to top"><svg class="icon top"><use xlink:href="/v1.12/img/icons.svg#top"/></svg></button></div></body></html> |