{"id":1963,"date":"2020-05-22T21:53:35","date_gmt":"2020-05-22T18:53:35","guid":{"rendered":"https:\/\/artem.services\/?p=1957"},"modified":"2020-05-22T22:21:28","modified_gmt":"2020-05-22T19:21:28","slug":"1963","status":"publish","type":"post","link":"https:\/\/artem.services\/?p=1963&lang=en","title":{"rendered":"AWS &#8212; Lambda: kubectl"},"content":{"rendered":"<p><img loading=\"lazy\" class=\"aligncenter size-full wp-image-214\" src=\"https:\/\/artem.services\/wp-content\/uploads\/2018\/11\/AWS-Logo.png\" alt=\"\" width=\"975\" height=\"450\" srcset=\"https:\/\/artem.services\/wp-content\/uploads\/2018\/11\/AWS-Logo.png 975w, https:\/\/artem.services\/wp-content\/uploads\/2018\/11\/AWS-Logo-300x138.png 300w, https:\/\/artem.services\/wp-content\/uploads\/2018\/11\/AWS-Logo-768x354.png 768w, https:\/\/artem.services\/wp-content\/uploads\/2018\/11\/AWS-Logo-954x440.png 954w\" sizes=\"(max-width: 975px) 100vw, 975px\" \/><\/p>\n<p>An example of how you can create entities in <strong>Kubernetes<\/strong> using <strong>AWS Lambda<\/strong>.<\/p>\n<p>The function will be in <strong>Python3<\/strong>, so we will use <a href=\"https:\/\/github.com\/kubernetes-client\/python\" target=\"_blank\" rel=\"noopener noreferrer\">Kubernetes Python Client<\/a><\/p>\n<p>More usage examples can be found <a href=\"https:\/\/github.com\/kubernetes-client\/python\/tree\/master\/examples\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>.<\/p>\n<p>Since <strong>AWS Lambda<\/strong> does not support this package, we will pack the &quot;<strong>kubernetes<\/strong>&quot; and &quot;<strong>boto3<\/strong>&quot; modules in our function.<\/p>\n<blockquote><p><strong>&quot;boto3&quot; <\/strong>is needed to access <strong>AWS SSM<\/strong>, where <strong>kubeconfig<\/strong> will be stored<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h3>Preparation<\/h3>\n<p>Create a directory for the lambda and go to it:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nmkdir lambda\r\ncd lambda\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Next you will need &quot;<strong>virtualenv<\/strong>&quot;, if it is not there, you can install it using &quot;<strong>pip3<\/strong>&quot;:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\npip3 install virtualenv\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Create a virtual environment and activate it:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\npython3 -m virtualenv .\r\nsource bin\/activate\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>And install the necessary modules:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\npip3 install kubernetes\r\npip3 install boto3\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Next, we only need the contents of this directory:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n$VIRTUAL_ENV\/lib\/python3.7\/site-packages\r\n<\/pre>\n<p>&nbsp;<\/p>\n<blockquote><p>&quot;<strong>python3.7<\/strong>&quot; &#8212; replace with your version of Python<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<p>It will be more convenient to look at the environment path and copy the contents to a separately created directory, no longer in a virtual environment:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\necho $VIRTUAL_ENV\/lib\/python3.7\/site-packages\r\n\/private\/tmp\/lambda\/lib\/python3.7\/site-packages\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Let&#8217;s create a directory for lambda, which we will already directly download and copy our modules:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nmkdir ~\/lambda_upload\r\ncp -R \/private\/tmp\/lambda\/lib\/python3.7\/site-packages\/. ~\/lambda_upload\/\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h3>SSM Parameter Store<\/h3>\n<p>In the <strong>AWS<\/strong> console, go to &quot;<strong>Systems Manager<\/strong>&quot; -&gt; &quot;<strong>Parameter Store<\/strong>&quot;<\/p>\n<p><img loading=\"lazy\" class=\"aligncenter size-full wp-image-1958\" src=\"https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.27.20.png\" alt=\"\" width=\"538\" height=\"842\" srcset=\"https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.27.20.png 538w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.27.20-192x300.png 192w\" sizes=\"(max-width: 538px) 100vw, 538px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><span data-reactroot=\"\">And create a parameter with the type &quot;<strong>SecureString<\/strong>&quot; and copy the contents of the &quot;<strong>kubeconfig<\/strong>&quot; file as the value. If this is an <strong>EKS<\/strong>, first create a service account so that it does not require <strong>AWS<\/strong> authorization, as in the example below:<\/span><\/p>\n<p><strong>Kubeconfig<\/strong> with <strong>AWS<\/strong> authorization:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n...\r\n  user:\r\n    exec:\r\n      apiVersion: client.authentication.k8s.io\/v1alpha1\r\n      args:\r\n      - --region\r\n      - eu-central-1\r\n      - eks\r\n      - get-token\r\n      - --cluster-name\r\n      - artem-services-stage-eks\r\n      command: aws\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h3>Function<\/h3>\n<p>Now in the directory &quot;<strong>~\/lambda_upload<\/strong>&quot; create a file called &quot;<strong>lambda_function.py<\/strong>&quot; and paste the following text into it:<\/p>\n<h3>lambda_function.py:<\/h3>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nimport os\r\nimport time\r\nimport random\r\nimport string\r\nimport boto3\r\n\r\nfrom kubernetes import config\r\nfrom kubernetes.client import Configuration\r\nfrom kubernetes.client.api import core_v1_api\r\nfrom kubernetes.client.rest import ApiException\r\nfrom kubernetes.stream import stream\r\n\r\n# Get Kubeconfig from SSM\r\ndef get_kube_config():\r\n    awsRegion = os.environ['AWS_REGION']\r\n    ssmParameter = os.environ['SSM']\r\n\r\n    ssm = boto3.client('ssm', region_name=awsRegion)\r\n    parameter = ssm.get_parameter(Name=ssmParameter, WithDecryption=True)\r\n\r\n    kubeconfig = open( '\/tmp\/kubeconfig.yaml', 'w' )\r\n    kubeconfig.write(parameter['Parameter']['Value'])\r\n    kubeconfig.close()\r\n\r\n# Generate random string for unique name of Pod\r\ndef randomString(stringLength=8):\r\n    letters = string.ascii_lowercase + string.digits\r\n    return ''.join(random.choice(letters) for i in range(stringLength))\r\n\r\ndef exec_commands(api_instance):\r\n    name = &quot;busybox-&quot; + randomString()\r\n    namespace = &quot;default&quot;\r\n    resp = None\r\n\r\n    print(&quot;Creating pod...&quot;)\r\n\r\n    pod_manifest = {\r\n        'apiVersion': 'v1',\r\n        'kind': 'Pod',\r\n        'metadata': {\r\n            'name': name\r\n        },\r\n        'spec': {\r\n            'containers': [{\r\n                'image': 'busybox',\r\n                'name': 'busybox',\r\n                &quot;args&quot;: [\r\n                    &quot;\/bin\/sh&quot;,\r\n                    &quot;-c&quot;,\r\n                    &quot;while true;do date;sleep 5; done&quot;\r\n                ]\r\n            }]\r\n        }\r\n    }\r\n    resp = api_instance.create_namespaced_pod(body=pod_manifest, namespace=namespace)\r\n\r\n    while True:\r\n        resp = api_instance.read_namespaced_pod(name=name, namespace=namespace)\r\n        if resp.status.phase == 'Pending' or resp.status.phase == 'Running':\r\n            print(&quot;Done. Pod &quot; + name + &quot; was created.&quot;)\r\n            break\r\n        time.sleep(1)\r\n\r\ndef main(event, context):\r\n    get_kube_config()\r\n\r\n    config.load_kube_config(config_file=&quot;\/tmp\/kubeconfig.yaml&quot;)\r\n    c = Configuration()\r\n    c.assert_hostname = False\r\n    Configuration.set_default(c)\r\n    core_v1 = core_v1_api.CoreV1Api()\r\n\r\n    exec_commands(core_v1)\r\n\r\n\r\nif __name__ == '__main__':\r\n    main()\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Now all the contents of the directory can be packed into a &quot;<strong>zip<\/strong>&quot; archive and loaded into the <strong>Lambda<\/strong> function.<\/p>\n<p>In a variable environment, create 2 variables in which indicate your <strong>AWS Region<\/strong> and the name of the <strong>SSM Parameter Store<\/strong> that you created earlier.<\/p>\n<p><img loading=\"lazy\" class=\"aligncenter size-full wp-image-1959\" src=\"https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26.png\" alt=\"\" width=\"2592\" height=\"462\" srcset=\"https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26.png 2592w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-300x53.png 300w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-1024x183.png 1024w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-768x137.png 768w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-1536x274.png 1536w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-2048x365.png 2048w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-954x170.png 954w, https:\/\/artem.services\/wp-content\/uploads\/2020\/05\/Screenshot-2020-05-22-at-21.42.26-1354x241.png 1354w\" sizes=\"(max-width: 2592px) 100vw, 2592px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><strong>Lambda<\/strong> functions require read permissions from <strong>SSM<\/strong>, so attach the following policy to the role that <strong>Lambda<\/strong> uses:<\/p>\n<pre>arn:aws:iam::aws:policy\/AmazonSSMReadOnlyAccess<\/pre>\n<p>&nbsp;<\/p>\n<p>After starting the function, it will create a pod named &quot;<strong>busybox-<\/strong>&quot; + the generated string of 8 characters. There is no <strong>pod<\/strong> status check, since this script is planned to be used for <strong>EKS Fargate<\/strong>, so as not to wait 1-2 minutes until the <strong>Fargate<\/strong> instance will running, so in any of the conditions, &quot;<strong>Pending<\/strong>&quot; or &quot;<strong>Running<\/strong>&quot;, we consider that the pod was successful created.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An example of how you can create entities in Kubernetes using AWS Lambda. The function will be in Python3, so we will use Kubernetes Python Client More usage examples can be found here. Since AWS Lambda does not support this package, we will pack the &quot;kubernetes&quot; and &quot;boto3&quot; modules in our function. &quot;boto3&quot; is needed &hellip; <a href=\"https:\/\/artem.services\/?p=1963&#038;lang=en\" class=\"more-link\">\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0447\u0438\u0442\u0430\u0442\u044c<span class=\"screen-reader-text\"> &quot;AWS &#8212; Lambda: kubectl&quot;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[599,559],"tags":[543,1439,1093,551,885,1527,1529],"_links":{"self":[{"href":"https:\/\/artem.services\/index.php?rest_route=\/wp\/v2\/posts\/1963"}],"collection":[{"href":"https:\/\/artem.services\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/artem.services\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/artem.services\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/artem.services\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1963"}],"version-history":[{"count":2,"href":"https:\/\/artem.services\/index.php?rest_route=\/wp\/v2\/posts\/1963\/revisions"}],"predecessor-version":[{"id":1967,"href":"https:\/\/artem.services\/index.php?rest_route=\/wp\/v2\/posts\/1963\/revisions\/1967"}],"wp:attachment":[{"href":"https:\/\/artem.services\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1963"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/artem.services\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1963"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/artem.services\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}