<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CrimsonSpiderShark</title>
    <description>The latest articles on DEV Community by CrimsonSpiderShark (@crimsonspidershark).</description>
    <link>https://dev.to/crimsonspidershark</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1912882%2F69043f81-8374-4545-ba27-c9888f8c63ba.png</url>
      <title>DEV Community: CrimsonSpiderShark</title>
      <link>https://dev.to/crimsonspidershark</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crimsonspidershark"/>
    <language>en</language>
    <item>
      <title>🟥🕷🦈presents: EKS fun for Data Science (Part 1)</title>
      <dc:creator>CrimsonSpiderShark</dc:creator>
      <pubDate>Sun, 12 Jan 2025 18:25:19 +0000</pubDate>
      <link>https://dev.to/crimsonspidershark/presents-eks-fun-for-data-science-part-1-1m98</link>
      <guid>https://dev.to/crimsonspidershark/presents-eks-fun-for-data-science-part-1-1m98</guid>
      <description>&lt;p&gt;I added the 'fun' to the title because I'm going to get a little silly with it. Just a bit though, there will be plenty of serious stuff in it for you data science sickos.&lt;/p&gt;

&lt;p&gt;So, cliffnotes version of the regular spiel on Kubernetes and EKS: Kubernetes is how you get a bunch of small services to work together without one crashing the other, EKS is how you use Kubernetes in AWS. AWS, by volume, is essentially the Internet. Today, we'll deploy a simple image size reduction service in EKS (this is part 1, after all).&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the Flask code in Python
&lt;/h2&gt;

&lt;p&gt;You don't need it to be Flask or Python, that's just the example I'm going to use. The example looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app.py&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, request, send_file
from PIL import Image
import io
import os

app = Flask(__name__)

@app.route('/resize', methods=['POST'])
def resize_image():
    if 'image' not in request.files:
        return "No image file provided", 400

    image_file = request.files['image']

    try:
        img = Image.open(image_file)
        max_size = int(request.form.get('size', 512))

        img.thumbnail((max_size,max_size))
        img_io = io.BytesIO()
        img.save(img_io, 'JPEG')
        img_io.seek(0)

        return send_file(img_io, mimetype='image/jpeg')

    except Exception as e:
        return f"Error processing image: {str(e)}", 500

if __name__ == "__main__":
  app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 3000)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;requirements.txt&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip
autopep8
Flask==3.0.3
gunicorn==22.0.0
Werkzeug==3.0.6
Pillow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Dockerfile&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY app.py .

EXPOSE 3000

CMD ["python", "app.py"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put those three in a single folder and make the magic happen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfau3ukj9qaid1bxdl3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfau3ukj9qaid1bxdl3w.png" alt="Image description" width="657" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This image sums it up pretty well. Just a list of commands to setup the things you'll need for the image for your Kubernetes cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Push to your ECR repository
&lt;/h2&gt;

&lt;p&gt;Oh, right. ECR is where you keep all your container images for Docker and Kubernetes services. Forgot to mention than one. But &lt;a href="//aws.amazon.com/ecr/private-registry/repositories/create"&gt;here's the link in AWS where you create one.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also just noticed this blog is about using images (the non-typical kind) to reduce images (the typical kind).&lt;/p&gt;

&lt;p&gt;Anyways, create the repository in your console, then go to the list of repos and click on 'View push commands'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesxzli2rrlpvq1x9nccn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesxzli2rrlpvq1x9nccn.png" alt="Image description" width="647" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, in the directory where you have all those previouse files, run the commands you get from than console. And voila, you've got your repo up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create and test your Kubernetes Cluster
&lt;/h2&gt;

&lt;p&gt;Use this deployment code after modifying it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  GNU nano 5.8                                                                                     deployment.yaml                                                                                               
apiVersion: apps/v1
kind: Deployment
metadata:
  name: image-reducer
spec:
  replicas: 2
  selector:
    matchLabels:
      app:
  template:
    metadata:
      labels:
        app: image-reducer
    spec:
      containers:
      - name: image-reducer
        image: &amp;lt;your_image_name&amp;gt;
        ports:
        - containerPort: 3000
        resources:
          requests:
            cpu: "100m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And also one for load balancing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: image-reducer-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
  selector:
    app: image-reducer
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: LoadBalancer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the commands of deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the IP address for your endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get service image-reducer-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give you an IP which you can send a POST request to in the /resize endpoint with an image and get a resized image back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST -F &amp;lt;your_image_path&amp;gt; -F "size=200" http://&amp;lt;your-external-ip&amp;gt;/resize -o resized.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it, simple as pie. It gets you a nice little sample image resizer. Chomp Chomp.&lt;/p&gt;

</description>
      <category>aks</category>
      <category>datascience</category>
      <category>dataops</category>
      <category>aws</category>
    </item>
    <item>
      <title>🟥🕷🦈 brings to you: AWS Glue DataBrew</title>
      <dc:creator>CrimsonSpiderShark</dc:creator>
      <pubDate>Thu, 02 Jan 2025 14:10:53 +0000</pubDate>
      <link>https://dev.to/crimsonspidershark/brings-to-you-aws-glue-databrew-4oif</link>
      <guid>https://dev.to/crimsonspidershark/brings-to-you-aws-glue-databrew-4oif</guid>
      <description>&lt;p&gt;Welcome to the first blog post from this blog for 2025 (and also ever, but who's counting), today I'm going sink my teeth and my fangs into AWS Glue DataBrew. And as this is the first blog (of many), we're going to start it off in the right way: no explanation, just implementation. That's a lie, there will be an explanation, but after the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  In the Glue DataBrew console, create a sample project
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzmadd3nziuh7b92i2ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzmadd3nziuh7b92i2ug.png" alt="I love sampling almost as much as hip-hop producers" width="583" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sample project contains all the data we will explore. Let's pick up the dataset for Chess moves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1bw0fpchkwyj7zi0lwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1bw0fpchkwyj7zi0lwu.png" alt="I love chess pieces! So easy to hunt since they can only move one move at a time" width="738" height="835"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As always create a new AWS IAM role with the appropriate permissions for the task. I said this blog works backwards, right? In reality, this is best practices but you only do it after you have determined the scope with some nice almost-admin permissions. At least that's the shark's reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start processing the data from the project console
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4165xlkp32gzzky9pq1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4165xlkp32gzzky9pq1v.png" alt="Why do people want to con soles? The shoelaces are much more gullible." width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a load of data, 17 columns, 2500 rows, lets reduce some of this down, give it some quality. We're looking for the most common opening move for which black wins when two players are within 22 points of each other in ratings (close games), according to this table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8by5hy0ah2uqzk38xis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8by5hy0ah2uqzk38xis.png" alt="Image description" width="484" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do this, we have to reduce pretty much everything that's not those things&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove duplicates
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1obz92zuzj1u7hkxwqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1obz92zuzj1u7hkxwqb.png" alt="I'm stopping with the descriptions now, its way too much work for a joke" width="275" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the three dots on the column, and you'll find your answer&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5z7fif8b7jhssmab8l1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5z7fif8b7jhssmab8l1j.png" alt="Image description" width="275" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apply the changes and continue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove unnecssary columns
&lt;/h3&gt;

&lt;p&gt;Look at the columns and remove everything that is not related to the ratings, the opening move, the winner and the ID, your final columns should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmg50ikzy9204havr1p78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmg50ikzy9204havr1p78.png" alt="Image description" width="800" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Filter black not winning
&lt;/h3&gt;

&lt;p&gt;Filter out the non-black winning values using the filter icon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f7m0juvdencwt0fxusv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f7m0juvdencwt0fxusv.png" alt="Image description" width="794" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create difference column
&lt;/h3&gt;

&lt;p&gt;Create a column to calculate the differences between ratings as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fekesjbll22x8jqmmp5qo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fekesjbll22x8jqmmp5qo.png" alt="Image description" width="377" height="722"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's filter this column as we did before with two filters this time, one for -22 and another for 22 in ratings difference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9zkopywtb6y5sdcq2l4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9zkopywtb6y5sdcq2l4.png" alt="Image description" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;
Not a lot of data, 176 rows, but it helps us with our point, we can even find the frequency of opening moves right there in the console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fdokoglte0weuxh7m0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fdokoglte0weuxh7m0u.png" alt="Image description" width="283" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The opening that wins the most is A00 (Benko's opening) which makes sense since it is unconventional and not very advantageous for white:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7m9mhbj09msdun4mw78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7m9mhbj09msdun4mw78.png" alt="Image description" width="434" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to GlueDataBrew
&lt;/h2&gt;

&lt;p&gt;So, now we can introduce DataBrew based off of what we understood up there. It is, in its most simplest form, a way to clean (or brew) data and make it easier to consume. Which is abundantly clear from the tutorial, but its good to put it into words. Your final result is a series of data cleaning steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsewcvbw7to0oklwwevx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjsewcvbw7to0oklwwevx.png" alt="Image description" width="364" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use these recipes to create data jobs that will follow this recipe for similar data.&lt;/p&gt;

&lt;p&gt;There is however, things we could do better, which I would encourage you to look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provision for potential missing values and filter them.&lt;/li&gt;
&lt;li&gt;Widened the search to a larger ratings range.&lt;/li&gt;
&lt;li&gt;Made the range so that if black was a more experienced player (far greater range), those would be reflected in the dataset.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But I digress, you can start with this improve on it, and remember, I didn't become a SpiderShark just for the fun of it, I did it so I would have 10 appendages to type with, just like a human! ChompChomp!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
