<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[raag's blog Software development and more]]></title><description><![CDATA[I share everything I learn in my work, software engineering, DevOps, Docker, Kubernetes, Linux and more.]]></description><link>https://blog.raagpc.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 15 Oct 2026 08:07:52 GMT</lastBuildDate><atom:link href="https://blog.raagpc.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building docker images for x86_64 with an Apple Silicon CPU.]]></title><description><![CDATA[If you have a Mac and you deploy your applications with docker, there is the possibility you get this error The requested image's platform (Linux/arm64/v8) does not match the detected host platform (linux/amd64/v4) and no specific platform was reques...]]></description><link>https://blog.raagpc.com/building-docker-images-for-x8664-with-an-apple-silicon-cpu</link><guid isPermaLink="true">https://blog.raagpc.com/building-docker-images-for-x8664-with-an-apple-silicon-cpu</guid><category><![CDATA[Docker]]></category><category><![CDATA[Apple]]></category><category><![CDATA[macOS]]></category><category><![CDATA[apple silicon]]></category><dc:creator><![CDATA[raag]]></dc:creator><pubDate>Wed, 02 Aug 2023 13:00:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690729693399/79ca9e46-d1d3-43de-a6f5-ea95d9441a4b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have a Mac and you deploy your applications with docker, there is the possibility you get this error <code>The requested image's platform (Linux/arm64/v8) does not match the detected host platform (linux/amd64/v4) and no specific platform was requested</code>.</p>
<p>This is because you have an Apple Silicon CPU and the server that will run your image is based on a more traditional amd64/x86_64 architecture. For this, you will need to create an image that supports that type of CPU.</p>
<p>To achieve this, in docker you have the command <code>buildx build</code> wich allows you to create images for different architectures, even to make it compatible with multiple architectures.</p>
<p>The use of this command is very simple. Returning to our initial scenario. If you are a Mac user with Apple Silicon CPU, just run:</p>
<pre><code class="lang-bash">docker buildx build --platform linux/amd64 -t myimage:tag .
</code></pre>
<p>Where <code>linux/amd64</code> is the destination architecture for your image.</p>
<p>That's it, it was very simple, right? if you want to learn more about this command, here is the <a target="_blank" href="https://docs.docker.com/engine/reference/commandline/buildx_build/">official documentation</a>.</p>
<p>Did you know about this command before?</p>
<p>Share in the comments if it was useful to you.</p>
<p>Thanks for reading.</p>
]]></content:encoded></item><item><title><![CDATA[How to upload files with a multipart request in swift.]]></title><description><![CDATA[Recently I had to make a multipart request from an iOS app written in Swift.
The thing is, that there is not a standard way to make it easily, at least not without any third-party library. So, making some research I found this blog post.
The author e...]]></description><link>https://blog.raagpc.com/how-to-upload-files-with-a-multipart-request-in-swift</link><guid isPermaLink="true">https://blog.raagpc.com/how-to-upload-files-with-a-multipart-request-in-swift</guid><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[multipart]]></category><category><![CDATA[iOS]]></category><dc:creator><![CDATA[raag]]></dc:creator><pubDate>Mon, 31 Jul 2023 03:14:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690739522542/df197839-fa0e-4704-8a95-4e73aa547a71.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently I had to make a multipart request from an iOS app written in Swift.</p>
<p>The thing is, that there is not a standard way to make it easily, at least not without any third-party library. So, making some research I found this <a target="_blank" href="https://theswiftdev.com/easy-multipart-file-upload-for-swift/">blog post</a>.</p>
<p>The author explains really well how to build a multipart request through a self-written struct called <code>MultipartRequest</code>.</p>
<p>But in my case, it didn't work out of the box, I'm pretty sure it was because I'm using a newer version of Swift.</p>
<p>So, in order to make it work, I made a few changes.</p>
<h2 id="heading-creating-the-multipartrequest-struct">Creating the MultipartRequest struct</h2>
<p>The principal change I made was to replace the type of the <code>data</code> property from <code>Data</code> to <code>NSMutableData</code>.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> data: <span class="hljs-type">NSMutableData</span>
</code></pre>
<p>This is because the compiler marked an error telling me that Data was not mutable.</p>
<p>Then I had to add an extension to <code>NSMutableData</code> instead to <code>Data</code>.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">NSMutableData</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">appendString</span><span class="hljs-params">(<span class="hljs-number">_</span> string: String)</span></span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = string.data(using: .utf8) {
            <span class="hljs-keyword">self</span>.append(data)
        }
    }
}
</code></pre>
<p>And finally modified the calculated property <code>httpBody</code> to cast the <code>NSMutableData</code> to <code>Data</code>.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">public</span> <span class="hljs-keyword">var</span> httpBody: <span class="hljs-type">Data</span> {
    data.appendString(<span class="hljs-string">"--\(boundary)--"</span>)
    <span class="hljs-keyword">return</span> data <span class="hljs-keyword">as</span> <span class="hljs-type">Data</span>
}
</code></pre>
<p>Here you can see the full struct:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MultipartRequest</span> </span>{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">let</span> boundary: <span class="hljs-type">String</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> separator: <span class="hljs-type">String</span> = <span class="hljs-string">"\r\n"</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> data: <span class="hljs-type">NSMutableData</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">init</span>(boundary: <span class="hljs-type">String</span> = <span class="hljs-type">UUID</span>().uuidString) {
        <span class="hljs-keyword">self</span>.boundary = boundary
        <span class="hljs-keyword">self</span>.data = .<span class="hljs-keyword">init</span>()
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">mutating</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">appendBoundarySeparator</span><span class="hljs-params">()</span></span> {
        data.appendString(<span class="hljs-string">"--\(boundary)\(separator)"</span>)
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">mutating</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">appendSeparator</span><span class="hljs-params">()</span></span> {
        data.appendString(separator)
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">disposition</span><span class="hljs-params">(<span class="hljs-number">_</span> key: String)</span></span> -&gt; <span class="hljs-type">String</span> {
        <span class="hljs-string">"Content-Disposition: form-data; name=\"\(key)\""</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">mutating</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">add</span><span class="hljs-params">(
        key: String,
        value: String
    )</span></span> {
        appendBoundarySeparator()
        data.appendString(disposition(key) + separator)
        appendSeparator()
        data.appendString(value + separator)
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">mutating</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">add</span><span class="hljs-params">(
        key: String,
        fileName: String,
        fileMimeType: String,
        fileData: Data
    )</span></span> {
        appendBoundarySeparator()
        data.appendString(disposition(key) + <span class="hljs-string">"; filename=\"\(fileName)\""</span> + separator)
        data.appendString(<span class="hljs-string">"Content-Type: \(fileMimeType)"</span> + separator + separator)
        data.append(fileData)
        appendSeparator()
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">var</span> httpContentTypeHeadeValue: <span class="hljs-type">String</span> {
        <span class="hljs-string">"multipart/form-data; boundary=\(boundary)"</span>
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">var</span> httpBody: <span class="hljs-type">Data</span> {
        data.appendString(<span class="hljs-string">"--\(boundary)--"</span>)
        <span class="hljs-keyword">return</span> data <span class="hljs-keyword">as</span> <span class="hljs-type">Data</span>
    }
}

<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">NSMutableData</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">appendString</span><span class="hljs-params">(<span class="hljs-number">_</span> string: String)</span></span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = string.data(using: .utf8) {
            <span class="hljs-keyword">self</span>.append(data)
        }
    }
}
</code></pre>
<h2 id="heading-using-the-multipartrequest-struct">Using the MultipartRequest struct.</h2>
<p>Using this struct is very easy:</p>
<p>First, instantiate an object of the <code>MultipartRequest</code> struct.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">var</span> multipart = <span class="hljs-type">MultipartRequest</span>()
</code></pre>
<p>Now you can add parameters to your request:</p>
<pre><code class="lang-swift">multipart.add(key: <span class="hljs-string">"name"</span>, value: <span class="hljs-string">"John"</span>)
</code></pre>
<p>And of course, you can add your file data (in this example it's an image):</p>
<pre><code class="lang-swift">multipart.add(
    key: <span class="hljs-string">"file"</span>,
    fileName: <span class="hljs-string">"test.png"</span>,
    fileMimeType: <span class="hljs-string">"image/png"</span>,
    fileData: imageData
)
</code></pre>
<p>Build your request.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> url = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"https://myurl"</span>)!
<span class="hljs-keyword">var</span> request = <span class="hljs-type">URLRequest</span>(url: url)
request.httpMethod = <span class="hljs-string">"POST"</span>
<span class="hljs-comment">// Here is how to use your struct to set your content-type header</span>
request.setValue(multipart.httpContentTypeHeadeValue, forHTTPHeaderField: <span class="hljs-string">"Content-Type"</span>)
<span class="hljs-comment">// set the body request</span>
request.httpBody = multipart.httpBody
</code></pre>
<p>Finally, execute the request.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">do</span> {
  <span class="hljs-keyword">let</span> (responseData, response) = <span class="hljs-keyword">try</span> await  <span class="hljs-type">URLSession</span>.shared.data(<span class="hljs-keyword">for</span>: request)
  <span class="hljs-built_in">print</span>((response <span class="hljs-keyword">as</span>! <span class="hljs-type">HTTPURLResponse</span>).statusCode)
  <span class="hljs-built_in">print</span>(<span class="hljs-type">String</span>(data: responseData, encoding: .utf8)!)
} <span class="hljs-keyword">catch</span> {
  <span class="hljs-built_in">print</span> (<span class="hljs-string">"Error"</span>)
}
</code></pre>
<p>Now you can upload files from your iOS app.</p>
<h2 id="heading-conclusion">Conclusion.</h2>
<p>I created this <a target="_blank" href="https://github.com/raag/IOS_MULTIPART_REQUEST">Github repository</a> as an example using an image picker on SwiftUI.</p>
<p>Share in the comments if it is useful or if you know another way to do it.</p>
<p>Thanks for reading.</p>
]]></content:encoded></item><item><title><![CDATA[How to deploy images from a private registry on Kubernetes.]]></title><description><![CDATA[One of the first things I wondered when I started working with Kubernetes was; how to deploy images from a private registry.
Most examples on tutorials, use a public image from docker hub to show you how to create a deployment, but when you work in a...]]></description><link>https://blog.raagpc.com/how-to-deploy-images-from-a-private-registry-on-kubernetes</link><guid isPermaLink="true">https://blog.raagpc.com/how-to-deploy-images-from-a-private-registry-on-kubernetes</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[k8s]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[GitLab]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[raag]]></dc:creator><pubDate>Fri, 21 Jul 2023 18:21:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690740270063/49dbf517-9870-4760-ba83-0dc97d9b8f22.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the first things I wondered when I started working with Kubernetes was; how to deploy images from a private registry.</p>
<p>Most examples on tutorials, use a public image from <code>docker hub</code> to show you how to create a deployment, but when you work in a company that has a private registry, you will need a way to be authenticated.</p>
<p>And that way is to use a <code>secret</code>.</p>
<p>In this post, I’m going to explain how to do it using the registries given by GitHub and GitLab.</p>
<h2 id="heading-creating-an-authentication-token">Creating an authentication token.</h2>
<p>The first step would be to create an authentication token to get access to your registry.</p>
<h3 id="heading-github">Github.</h3>
<p>For Github go to <code>Account Settings</code> → <code>Developer Settings</code> → <code>Personal access tokens</code> and click on <code>Generate new token</code>.</p>
<p>Create a new token (you can set it to expire or not depending on your needs).</p>
<p>Check <code>read_packages</code>.</p>
<p>Copy the generated token. We will use it later on our <code>secret</code>.</p>
<h3 id="heading-gitlab">GitLab.</h3>
<p>For GitLab go to <code>User Settings</code> → <code>Access Tokens</code> and create a token giving it a name and check on <code>read_registry</code>.</p>
<p>Copy the generated token. We will use it later on our <code>secret</code>.</p>
<h2 id="heading-create-the-secret">Create the secret.</h2>
<p>Now use kubectl to create your secret:</p>
<pre><code class="lang-bash">kubectl create secret docker-registry [SECRET_NAME] \
 --docker-server=[SERVICE_REGISTRY] \ 
 --docker-username=[USERNAME] \
 --docker-password=[TOKEN] \
 --docker-email=[EMAIL]
</code></pre>
<p><strong>Where:</strong></p>
<ul>
<li><p>[SECRET_NAME] is the name of your secret and you will use it later in the deployment, for example; <strong>mysecret</strong>.</p>
</li>
<li><p>[SERVICE_REGISTRY] is your registry domain.</p>
<ul>
<li><p>For GitHub: <a target="_blank" href="http://ghcr.io"><strong>ghcr.io</strong></a></p>
</li>
<li><p>For GitLab: <a target="_blank" href="http://registry.gitlab.com"><strong>registry.gitlab.com</strong></a></p>
</li>
</ul>
</li>
</ul>
<p>For example:</p>
<pre><code class="lang-bash">kubectl create secret docker-registry mysecret \
 --docker-server=ghcr.io \ 
 --docker-username=myusername \
 --docker-password=[TOKEN] \
 --docker-email=myusername@mail.com
</code></pre>
<h2 id="heading-configure-your-deployment">Configure your deployment.</h2>
<p>Now you can add the section <code>imagePullSecrets</code> in your deployment.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">mydeployment</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-string">...</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-attr">imagePullSecrets:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">mysecret</span>
      <span class="hljs-attr">containers:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">image:</span> <span class="hljs-string">ghcr.io/myusername/myproject:latest</span>
    <span class="hljs-string">...</span>
</code></pre>
<p>Pay special attention to:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">imagePullSecrets:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">mysecret</span>
</code></pre>
<p>And that’s it, your deployment will be authenticated and download your container’s image to create your pods.</p>
<p>Please let me a comment and tell me if this was useful for you.</p>
<p>Thank you.</p>
]]></content:encoded></item></channel></rss>