<?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: Jer</title>
    <description>The latest articles on DEV Community by Jer (@tensorflowgobrr).</description>
    <link>https://dev.to/tensorflowgobrr</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%2F172866%2F448ec94c-cb3f-4a87-b34d-e58ce6256e32.jpg</url>
      <title>DEV Community: Jer</title>
      <link>https://dev.to/tensorflowgobrr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tensorflowgobrr"/>
    <language>en</language>
    <item>
      <title>Using Google Secrets Manager with Kubernetes</title>
      <dc:creator>Jer</dc:creator>
      <pubDate>Wed, 04 Jan 2023 21:14:19 +0000</pubDate>
      <link>https://dev.to/tensorflowgobrr/using-google-secrets-manager-with-kubernetes-2jf5</link>
      <guid>https://dev.to/tensorflowgobrr/using-google-secrets-manager-with-kubernetes-2jf5</guid>
      <description>&lt;p&gt;If you're running applications on Kubernetes, you know that managing secrets (such as passwords, API keys, and other sensitive data) can be a challenge. You want to keep your secrets secure, but at the same time you need to make them accessible to your applications when they need them.&lt;/p&gt;

&lt;p&gt;One solution to this problem is to use the Google Cloud Secret Store CSI driver. This driver allows you to store and manage your secrets in Google Cloud's Secret Manager service, and then access them from your Kubernetes pods using the Container Storage Interface (CSI).&lt;/p&gt;

&lt;p&gt;To use the Secret Store CSI driver, you'll need to have a Google Cloud account and a Kubernetes cluster running on Google Kubernetes Engine (GKE). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, ensure Workload Identity is enabled on your cluster. 
Google has instructions here &lt;a href="https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_existing_cluster" rel="noopener noreferrer"&gt;https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_existing_cluster&lt;/a&gt; for enabling this.&lt;/li&gt;
&lt;li&gt;Next, You'll also need to install the CSI driver on your cluster. You can find instructions on how to install the Secrets Store CSI Driver here: &lt;a href="https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html" rel="noopener noreferrer"&gt;https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Once you've done that, you'll be able to use the Secret Manager CSI driver to mount secrets as volumes in your pods.  You'll just need to use the instructions in the first link to bind the Google service account with read permissions to secrets manager to the Kubernetes service account that you create with your deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of how you might use the Secret Manager CSI driver in a deployment configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  serviceAccountName: my-service-account # this refers to a k8s serviceaccount object that contains the iam.gke.io/gcp-service-account annotation that must be bound to the gcp service account. 
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-app:latest
        volumeMounts:
        - name: secrets
          mountPath: /secrets
      volumes:
      - name: secrets
        csi:
          driver: secrets-store.csi.k8s.io
          readOnly: true
              volumeAttributes:
                secretProviderClass: "my-secrets"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're using the Secret Manager CSI driver to mount a secret called "file-name-containing-your-secret" as a volume at the path "/secrets" in our container. Our application can then access the secret by reading from this path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: my-secrets
  labels:
    app.kubernetes.io/name: my-app
spec:
  provider: gcp
  parameters:
    secrets: |
      - resourceName: "projects/{YOUR_PROJECT_RESOURCE_ID}/secrets/your-secret-name/versions/latest"
        path: "file-name-containing-your-secret"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the advantages of using the Secret Store CSI driver is that it allows you to manage your secrets in a centralized, secure location. You can use Google Cloud's Secret Manager service to create, rotate, and delete secrets, and the CSI driver will automatically reflect these changes in your Kubernetes pods. This makes it easy to keep your secrets up-to-date and secure.&lt;/p&gt;

&lt;p&gt;Another advantage of the Secret Store CSI driver is that it integrates seamlessly with other Google Cloud services. For example, you can use Cloud Functions or Cloud Scheduler to automatically rotate your secrets on a regular basis, or you can use Cloud Identity-Aware Proxy to limit access to your secrets to authorized users.&lt;/p&gt;

&lt;p&gt;In summary, the Secret Store CSI driver is a powerful tool for managing secrets in Kubernetes. By using it, you can store and manage your secrets in a centralized, secure location and access them from your Kubernetes pods using the Container Storage Interface. If you're running applications on Kubernetes and need to manage secrets, give the Secret Store CSI driver a try!&lt;/p&gt;

</description>
      <category>go</category>
      <category>ruby</category>
      <category>discuss</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>How to leverage Markov Chains for attribution</title>
      <dc:creator>Jer</dc:creator>
      <pubDate>Sat, 01 Jun 2019 01:59:33 +0000</pubDate>
      <link>https://dev.to/tensorflowgobrr/how-to-leverage-markov-chains-for-attribution-1k1i</link>
      <guid>https://dev.to/tensorflowgobrr/how-to-leverage-markov-chains-for-attribution-1k1i</guid>
      <description>&lt;p&gt;A short while ago I published a rather technical post on the development of a python-based attribution model that leverages a probabilistic graphical modeling concept known as a &lt;code&gt;Markov chain&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I realize what might serve as better content is actually the motivation behind doing such a thing, as well as providing a clearer understanding of what is going on behind the scenes.  Bonus: At the end you can grab the code to do this yourself in Python!  So to that end, in this post I'll be describing the basics of the Markov process and why we would want to use it in practice for attribution modeling.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is a Markov Chain
&lt;/h1&gt;

&lt;p&gt;A Markov chain is a type of probabilistic model.  This means that it is a system for representing different states that are connected to each other by probabilities.  &lt;/p&gt;

&lt;p&gt;The state, in the example of our attribution model, is the channel or tactic that a given user is exposed to (e.g. a nonbrand SEM ad or a Display ad).  The question then becomes, given your current state, what is your next most likely state? &lt;/p&gt;

&lt;p&gt;Well one way to estimate this would be to get a list of all possible states branching from the state in question and create a conditional probability distribution representing the likelihood of moving from the initial state to each other possible state. &lt;/p&gt;

&lt;p&gt;So in practice, this could look like the following:&lt;/p&gt;

&lt;p&gt;Let our current state be &lt;code&gt;SEM&lt;/code&gt; in a system containing the possible states of &lt;code&gt;SEM&lt;/code&gt;, &lt;code&gt;SEO&lt;/code&gt;, &lt;code&gt;Display&lt;/code&gt;, &lt;code&gt;Affiliate&lt;/code&gt;, &lt;code&gt;Conversion&lt;/code&gt;, and &lt;code&gt;No Conversion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After we look at every user path in our dataset we get conditional probabilities that resemble this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;P(SEM | SEM) = .1&lt;br&gt;
P(SEO | SEM) = .2&lt;br&gt;
P(Affiliate | SEM) = .05&lt;br&gt;
P(Display | SEM) = .05&lt;br&gt;
P(Conversion | SEM) = .5&lt;br&gt;
P(No Conversion | SEM) = .1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This can be graphically represented.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_W8NV4kc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.jnel.me/content/images/2019/04/Screen-Shot-2019-04-12-at-3.49.58-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_W8NV4kc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.jnel.me/content/images/2019/04/Screen-Shot-2019-04-12-at-3.49.58-PM.png" alt="Screen-Shot-2019-04-12-at-3.49.58-PM" width="603" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how the sum of the probabilities extending from the SEM state equal to one.  This is an important property of a Markov process and one that will arise organically if you have engineered your datset properly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Connect all the nodes
&lt;/h1&gt;

&lt;p&gt;Above we only identified the conditional probabilities for scenario in which our current state was SEM.  We now need to go through the same process for every other scenario that is possible to build a networked model that you can follow indefinitely.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lqw9ngI4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.jnel.me/content/images/2019/04/Screen-Shot-2019-04-12-at-3.57.16-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lqw9ngI4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.jnel.me/content/images/2019/04/Screen-Shot-2019-04-12-at-3.57.16-PM.png" alt="Screen-Shot-2019-04-12-at-3.57.16-PM" width="603" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Intuition
&lt;/h1&gt;

&lt;p&gt;Now up to this point I've written a lot about the process of defining and constructing a Markov chain but I think at this point it is helpful to explain &lt;code&gt;why&lt;/code&gt; I like these models over standard heuristic based attribution models.  &lt;/p&gt;

&lt;p&gt;Look again at the fully constructed network we have created, but pay special attention to the outbound Display vectors that I've highlighted in blue below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_8rbWNBE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.jnel.me/content/images/2019/04/Screen-Shot-2019-04-12-at-4.00.17-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_8rbWNBE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://www.jnel.me/content/images/2019/04/Screen-Shot-2019-04-12-at-4.00.17-PM.png" alt="Screen-Shot-2019-04-12-at-4.00.17-PM" width="603" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to the data, we have a high likelihood of not converting at about 75% and only a 5% chance of converting the user.  However, that user has a 20% probability of going proceeding to SEM as the next step.  And SEM has a 50% chance of converting!&lt;/p&gt;

&lt;p&gt;This means that when it comes time to do the "attribution" portion of this model, Display is very likely to increase its share of conversions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Attributing the Conversions
&lt;/h1&gt;

&lt;p&gt;Now that we have constructed the system that represents our user behavior it's time to use it to re-allocate the total number of conversions that occurred for a period of time.&lt;/p&gt;

&lt;p&gt;What I like to do is take the entire system's probability matrix and simulate thousands of runs through the system that end when our simulated user arrives at either &lt;code&gt;conversion&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;.  This allows us to use a rather small sample to generalize because we can simulate the random walk through the different stages of our system with our prior understanding of the probability of moving from one stage to the next.  Since we pass a probability distribution into the mix we are allowing for a bit more variation in our simulation outcomes.&lt;/p&gt;

&lt;p&gt;After getting the conversion rates of the system we can simulate what occurs when we remove channels from the system one by one to understand their overall contribution to the whole.&lt;/p&gt;

&lt;p&gt;We do this by calculating the &lt;code&gt;removal effect&lt;/code&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt; which is defined as the percentage of conversions we'd miss out on if a given channel or tactic was removed from the system.  &lt;/p&gt;

&lt;p&gt;In other words, if we create one new model for each channel where that channel is set to 100% no conversion, we will have a new model that highlights the effect that removing that channel entirely had on the overall system.&lt;/p&gt;

&lt;p&gt;Mathematically speaking, we'd be taking the percent difference in the conversion rate of the overall system with a given channel set to NULL against the conversion rate of the overall system.  We would do this for each channel.  Then we create a weighting for each of them based off of the sum of removal effects and then we could finally then multiply that number by the number of conversions to arrive at the fractionally attributed number of conversions.&lt;/p&gt;

&lt;p&gt;If the above paragraph confuses you head over to &lt;a href="https://analyzecore.com/2016/08/03/attribution-model-r-part-1/"&gt;here&lt;/a&gt; and scroll about a third of the way down for a clear removal effect example.  I went and made my example system too complicated for me to want to manually write out the the removal effect CVRs.&lt;/p&gt;

&lt;h1&gt;
  
  
  That's it
&lt;/h1&gt;

&lt;p&gt;Well by now you have a working attribution model that leverages a Markov process for allocating fractions of a conversion to multiple touchpoints!  I have also built a proof-of-concept in Python that employs the above methodology to perform Markov model based attribution given a set of touchpoints.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;-&lt;a href="https://nelson.eu.org"&gt;Jeremy Nelson&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Anderl, Eva and Becker, Ingo and Wangenheim, Florian V. and Schumann, Jan Hendrik, Mapping the Customer Journey: A Graph-Based Framework for Online Attribution Modeling (October 18, 2014). Available at SSRN: &lt;a href="https://ssrn.com/abstract=2343077"&gt;https://ssrn.com/abstract=2343077&lt;/a&gt; or &lt;a href="http://dx.doi.org/10.2139/ssrn.2343077"&gt;http://dx.doi.org/10.2139/ssrn.2343077&lt;/a&gt;  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://github.com/jerednel/markov-chain-attribution"&gt;https://github.com/jerednel/markov-chain-attribution&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>datascience</category>
      <category>analytics</category>
      <category>data</category>
    </item>
  </channel>
</rss>
